opencodekit 0.21.9 → 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 (165) hide show
  1. package/dist/index.js +1 -1
  2. package/dist/template/.opencode/AGENTS.md +116 -499
  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 +15 -16
  6. package/dist/template/.opencode/agent/general.md +2 -2
  7. package/dist/template/.opencode/agent/plan.md +3 -3
  8. package/dist/template/.opencode/agent/review.md +2 -3
  9. package/dist/template/.opencode/agent/scout.md +34 -16
  10. package/dist/template/.opencode/agent/vision.md +0 -1
  11. package/dist/template/.opencode/command/clarify.md +48 -0
  12. package/dist/template/.opencode/command/commit.md +53 -0
  13. package/dist/template/.opencode/command/design.md +4 -4
  14. package/dist/template/.opencode/command/fix.md +56 -0
  15. package/dist/template/.opencode/command/improve-architecture.md +55 -0
  16. package/dist/template/.opencode/command/init.md +88 -68
  17. package/dist/template/.opencode/command/refactor.md +66 -0
  18. package/dist/template/.opencode/command/review-codebase.md +1 -1
  19. package/dist/template/.opencode/command/ship.md +1 -1
  20. package/dist/template/.opencode/command/test.md +66 -0
  21. package/dist/template/.opencode/dcp.jsonc +29 -46
  22. package/dist/template/.opencode/memory/README.md +3 -5
  23. package/dist/template/.opencode/memory/_templates/adr.md +45 -0
  24. package/dist/template/.opencode/memory/project/gotchas.md +1 -1
  25. package/dist/template/.opencode/memory/project/user.md +1 -2
  26. package/dist/template/.opencode/memory/session-context.md +1 -1
  27. package/dist/template/.opencode/opencode.json +10 -332
  28. package/dist/template/.opencode/plugin/README.md +1 -1
  29. package/dist/template/.opencode/plugin/guard.ts +62 -0
  30. package/dist/template/.opencode/plugin/{lib/memory-admin-tools.ts → memory/admin.ts} +4 -4
  31. package/dist/template/.opencode/plugin/{lib → memory}/capture.ts +1 -1
  32. package/dist/template/.opencode/plugin/{lib → memory}/compile.ts +2 -2
  33. package/dist/template/.opencode/plugin/{lib → memory}/context.ts +1 -1
  34. package/dist/template/.opencode/plugin/{lib → memory}/curator.ts +1 -1
  35. package/dist/template/.opencode/plugin/{lib → memory}/db/observations.ts +102 -3
  36. package/dist/template/.opencode/plugin/{lib → memory}/db/schema.ts +43 -1
  37. package/dist/template/.opencode/plugin/{lib → memory}/db/types.ts +22 -0
  38. package/dist/template/.opencode/plugin/{lib/memory-db.ts → memory/db.ts} +1 -1
  39. package/dist/template/.opencode/plugin/{lib → memory}/distill.ts +1 -1
  40. package/dist/template/.opencode/plugin/{lib/memory-helpers.ts → memory/helpers.ts} +5 -1
  41. package/dist/template/.opencode/plugin/{lib/memory-hooks.ts → memory/hooks.ts} +1 -1
  42. package/dist/template/.opencode/plugin/{lib → memory}/index-generator.ts +2 -2
  43. package/dist/template/.opencode/plugin/{lib → memory}/inject.ts +1 -1
  44. package/dist/template/.opencode/plugin/{lib → memory}/lint.ts +2 -2
  45. package/dist/template/.opencode/plugin/memory/tools.ts +322 -0
  46. package/dist/template/.opencode/plugin/{lib → memory}/validate.ts +2 -2
  47. package/dist/template/.opencode/plugin/memory.ts +7 -17
  48. package/dist/template/.opencode/plugin/srcwalk.ts +721 -0
  49. package/dist/template/.opencode/skill/agent-code-quality-gate/SKILL.md +98 -0
  50. package/dist/template/.opencode/skill/behavioral-kernel/SKILL.md +52 -0
  51. package/dist/template/.opencode/skill/browser-testing-with-devtools/SKILL.md +85 -0
  52. package/dist/template/.opencode/skill/code-cleanup/SKILL.md +114 -0
  53. package/dist/template/.opencode/skill/code-navigation/SKILL.md +142 -0
  54. package/dist/template/.opencode/skill/code-review-and-quality/SKILL.md +131 -0
  55. package/dist/template/.opencode/skill/debugging-and-error-recovery/SKILL.md +109 -0
  56. package/dist/template/.opencode/skill/deep-module-design/SKILL.md +207 -0
  57. package/dist/template/.opencode/skill/git-workflow-and-versioning/SKILL.md +77 -0
  58. package/dist/template/.opencode/skill/grill-me/SKILL.md +140 -0
  59. package/dist/template/.opencode/skill/memory-system/SKILL.md +9 -10
  60. package/dist/template/.opencode/skill/planning-and-task-breakdown/SKILL.md +116 -0
  61. package/dist/template/.opencode/skill/shipping-and-launch/SKILL.md +95 -0
  62. package/dist/template/.opencode/skill/source-driven-development/SKILL.md +103 -0
  63. package/dist/template/.opencode/skill/spec-driven-development/SKILL.md +121 -0
  64. package/dist/template/.opencode/skill/srcwalk/SKILL.md +161 -0
  65. package/dist/template/.opencode/skill/ubiquitous-language/SKILL.md +184 -0
  66. package/dist/template/.opencode/tool/context7.ts +1 -1
  67. package/dist/template/.opencode/tool/grepsearch.ts +1 -1
  68. package/package.json +1 -1
  69. package/dist/template/.opencode/AGENT_ALIGNMENT.md +0 -564
  70. package/dist/template/.opencode/agent/painter.md +0 -83
  71. package/dist/template/.opencode/command/compound.md +0 -240
  72. package/dist/template/.opencode/command/curate.md +0 -299
  73. package/dist/template/.opencode/command/handoff.md +0 -149
  74. package/dist/template/.opencode/command/health.md +0 -356
  75. package/dist/template/.opencode/command/init-context.md +0 -297
  76. package/dist/template/.opencode/command/init-user.md +0 -125
  77. package/dist/template/.opencode/command/iterate.md +0 -200
  78. package/dist/template/.opencode/command/lfg.md +0 -173
  79. package/dist/template/.opencode/command/resume.md +0 -78
  80. package/dist/template/.opencode/command/status.md +0 -126
  81. package/dist/template/.opencode/command/ui-slop-check.md +0 -169
  82. package/dist/template/.opencode/plugin/lib/memory-tools.ts +0 -535
  83. package/dist/template/.opencode/skill/agent-evals/SKILL.md +0 -208
  84. package/dist/template/.opencode/skill/anti-ai-slop/SKILL.md +0 -76
  85. package/dist/template/.opencode/skill/augment-context-engine/SKILL.md +0 -122
  86. package/dist/template/.opencode/skill/augment-context-engine/mcp.json +0 -6
  87. package/dist/template/.opencode/skill/brand-asset-protocol/SKILL.md +0 -222
  88. package/dist/template/.opencode/skill/code-search-patterns/SKILL.md +0 -253
  89. package/dist/template/.opencode/skill/code-simplification/SKILL.md +0 -211
  90. package/dist/template/.opencode/skill/context-condensation/SKILL.md +0 -149
  91. package/dist/template/.opencode/skill/context-initialization/SKILL.md +0 -69
  92. package/dist/template/.opencode/skill/context-management/SKILL.md +0 -390
  93. package/dist/template/.opencode/skill/deep-research/SKILL.md +0 -384
  94. package/dist/template/.opencode/skill/design-direction-advisor/SKILL.md +0 -139
  95. package/dist/template/.opencode/skill/dispatching-parallel-agents/SKILL.md +0 -191
  96. package/dist/template/.opencode/skill/executing-plans/SKILL.md +0 -247
  97. package/dist/template/.opencode/skill/figma-go/SKILL.md +0 -65
  98. package/dist/template/.opencode/skill/finishing-a-development-branch/SKILL.md +0 -357
  99. package/dist/template/.opencode/skill/full-output-enforcement/SKILL.md +0 -62
  100. package/dist/template/.opencode/skill/gh-address-comments/SKILL.md +0 -29
  101. package/dist/template/.opencode/skill/gh-address-comments/scripts/fetch_comments.py +0 -237
  102. package/dist/template/.opencode/skill/gh-fix-ci/SKILL.md +0 -38
  103. package/dist/template/.opencode/skill/gh-fix-ci/scripts/inspect_pr_checks.py +0 -509
  104. package/dist/template/.opencode/skill/hi-fi-prototype-html/SKILL.md +0 -253
  105. package/dist/template/.opencode/skill/html-deck-export/SKILL.md +0 -189
  106. package/dist/template/.opencode/skill/index-knowledge/SKILL.md +0 -413
  107. package/dist/template/.opencode/skill/memory-grounding/SKILL.md +0 -68
  108. package/dist/template/.opencode/skill/playwriter/SKILL.md +0 -158
  109. package/dist/template/.opencode/skill/portless/SKILL.md +0 -109
  110. package/dist/template/.opencode/skill/prd/SKILL.md +0 -146
  111. package/dist/template/.opencode/skill/prd-task/SKILL.md +0 -182
  112. package/dist/template/.opencode/skill/prd-task/references/prd-schema.json +0 -124
  113. package/dist/template/.opencode/skill/prompt-leverage/SKILL.md +0 -90
  114. package/dist/template/.opencode/skill/prompt-leverage/references/framework.md +0 -91
  115. package/dist/template/.opencode/skill/prompt-leverage/scripts/augment_prompt.py +0 -157
  116. package/dist/template/.opencode/skill/receiving-code-review/SKILL.md +0 -263
  117. package/dist/template/.opencode/skill/reconcile/SKILL.md +0 -183
  118. package/dist/template/.opencode/skill/reflection-checkpoints/SKILL.md +0 -183
  119. package/dist/template/.opencode/skill/requesting-code-review/SKILL.md +0 -443
  120. package/dist/template/.opencode/skill/requesting-code-review/references/specialist-profiles.md +0 -108
  121. package/dist/template/.opencode/skill/requesting-code-review/review.md +0 -160
  122. package/dist/template/.opencode/skill/rtk-command-compression/SKILL.md +0 -134
  123. package/dist/template/.opencode/skill/screenshot/SKILL.md +0 -48
  124. package/dist/template/.opencode/skill/screenshot/scripts/ensure_macos_permissions.sh +0 -54
  125. package/dist/template/.opencode/skill/screenshot/scripts/macos_display_info.swift +0 -22
  126. package/dist/template/.opencode/skill/screenshot/scripts/macos_permissions.swift +0 -40
  127. package/dist/template/.opencode/skill/screenshot/scripts/macos_window_info.swift +0 -126
  128. package/dist/template/.opencode/skill/screenshot/scripts/take_screenshot.ps1 +0 -163
  129. package/dist/template/.opencode/skill/screenshot/scripts/take_screenshot.py +0 -585
  130. package/dist/template/.opencode/skill/security-threat-model/SKILL.md +0 -36
  131. package/dist/template/.opencode/skill/security-threat-model/references/prompt-template.md +0 -255
  132. package/dist/template/.opencode/skill/security-threat-model/references/security-controls-and-assets.md +0 -32
  133. package/dist/template/.opencode/skill/sharing-skills/SKILL.md +0 -214
  134. package/dist/template/.opencode/skill/skill-creator/SKILL.md +0 -181
  135. package/dist/template/.opencode/skill/skill-installer/SKILL.md +0 -58
  136. package/dist/template/.opencode/skill/skill-installer/scripts/github_utils.py +0 -21
  137. package/dist/template/.opencode/skill/skill-installer/scripts/install-skill-from-github.py +0 -313
  138. package/dist/template/.opencode/skill/skill-installer/scripts/list-skills.py +0 -106
  139. package/dist/template/.opencode/skill/swarm-coordination/SKILL.md +0 -244
  140. package/dist/template/.opencode/skill/swarm-coordination/references/architecture.md +0 -39
  141. package/dist/template/.opencode/skill/swarm-coordination/references/delegation-worker-protocol.md +0 -145
  142. package/dist/template/.opencode/skill/swarm-coordination/references/dependency-graph.md +0 -50
  143. package/dist/template/.opencode/skill/swarm-coordination/references/drift-check.md +0 -90
  144. package/dist/template/.opencode/skill/swarm-coordination/references/integration-beads.md +0 -20
  145. package/dist/template/.opencode/skill/swarm-coordination/references/launch-flow.md +0 -186
  146. package/dist/template/.opencode/skill/swarm-coordination/references/reconciler.md +0 -172
  147. package/dist/template/.opencode/skill/swarm-coordination/references/tier-enforcement.md +0 -78
  148. package/dist/template/.opencode/skill/swarm-coordination/references/tmux-integration.md +0 -134
  149. package/dist/template/.opencode/skill/systematic-debugging/SKILL.md +0 -402
  150. package/dist/template/.opencode/skill/terse-output-mode/SKILL.md +0 -95
  151. package/dist/template/.opencode/skill/think-in-code/SKILL.md +0 -136
  152. package/dist/template/.opencode/skill/ux-quality-gates/SKILL.md +0 -137
  153. package/dist/template/.opencode/skill/v1-run/SKILL.md +0 -175
  154. package/dist/template/.opencode/skill/v1-run/mcp.json +0 -6
  155. package/dist/template/.opencode/skill/verification-gates/SKILL.md +0 -63
  156. package/dist/template/.opencode/skill/visual-analysis/SKILL.md +0 -154
  157. package/dist/template/.opencode/skill/web-design-guidelines/SKILL.md +0 -46
  158. package/dist/template/.opencode/skill/workspace-setup/SKILL.md +0 -76
  159. package/dist/template/.opencode/skill/writing-plans/SKILL.md +0 -320
  160. /package/dist/template/.opencode/plugin/{lib → memory}/compact.ts +0 -0
  161. /package/dist/template/.opencode/plugin/{lib → memory}/db/graph.ts +0 -0
  162. /package/dist/template/.opencode/plugin/{lib → memory}/db/maintenance.ts +0 -0
  163. /package/dist/template/.opencode/plugin/{lib → memory}/db/pipeline.ts +0 -0
  164. /package/dist/template/.opencode/plugin/{lib → memory}/notify.ts +0 -0
  165. /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
- }