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.
- package/dist/index.js +1 -1
- package/dist/template/.opencode/AGENTS.md +116 -487
- package/dist/template/.opencode/README.md +1 -1
- package/dist/template/.opencode/agent/build.md +56 -396
- package/dist/template/.opencode/agent/explore.md +0 -1
- package/dist/template/.opencode/agent/review.md +0 -1
- package/dist/template/.opencode/agent/scout.md +0 -1
- package/dist/template/.opencode/agent/vision.md +0 -1
- package/dist/template/.opencode/command/clarify.md +48 -0
- package/dist/template/.opencode/command/commit.md +53 -0
- package/dist/template/.opencode/command/fix.md +56 -0
- package/dist/template/.opencode/command/improve-architecture.md +55 -0
- package/dist/template/.opencode/command/init.md +88 -68
- package/dist/template/.opencode/command/refactor.md +66 -0
- package/dist/template/.opencode/command/test.md +66 -0
- package/dist/template/.opencode/dcp.jsonc +13 -2
- package/dist/template/.opencode/memory/README.md +3 -5
- package/dist/template/.opencode/memory/_templates/adr.md +45 -0
- package/dist/template/.opencode/memory/project/gotchas.md +1 -1
- package/dist/template/.opencode/memory/session-context.md +1 -1
- package/dist/template/.opencode/plugin/README.md +1 -1
- package/dist/template/.opencode/plugin/guard.ts +62 -0
- package/dist/template/.opencode/plugin/{lib/memory-admin-tools.ts → memory/admin.ts} +4 -4
- package/dist/template/.opencode/plugin/{lib → memory}/capture.ts +1 -1
- package/dist/template/.opencode/plugin/{lib → memory}/compile.ts +2 -2
- package/dist/template/.opencode/plugin/{lib → memory}/context.ts +1 -1
- package/dist/template/.opencode/plugin/{lib → memory}/curator.ts +1 -1
- package/dist/template/.opencode/plugin/{lib → memory}/db/observations.ts +102 -3
- package/dist/template/.opencode/plugin/{lib → memory}/db/schema.ts +43 -1
- package/dist/template/.opencode/plugin/{lib → memory}/db/types.ts +22 -0
- package/dist/template/.opencode/plugin/{lib/memory-db.ts → memory/db.ts} +1 -1
- package/dist/template/.opencode/plugin/{lib → memory}/distill.ts +1 -1
- package/dist/template/.opencode/plugin/{lib/memory-helpers.ts → memory/helpers.ts} +5 -1
- package/dist/template/.opencode/plugin/{lib/memory-hooks.ts → memory/hooks.ts} +1 -1
- package/dist/template/.opencode/plugin/{lib → memory}/index-generator.ts +2 -2
- package/dist/template/.opencode/plugin/{lib → memory}/inject.ts +1 -1
- package/dist/template/.opencode/plugin/{lib → memory}/lint.ts +2 -2
- package/dist/template/.opencode/plugin/memory/tools.ts +322 -0
- package/dist/template/.opencode/plugin/{lib → memory}/validate.ts +2 -2
- package/dist/template/.opencode/plugin/memory.ts +7 -17
- package/dist/template/.opencode/plugin/srcwalk.ts +721 -0
- package/dist/template/.opencode/skill/agent-code-quality-gate/SKILL.md +98 -0
- package/dist/template/.opencode/skill/behavioral-kernel/SKILL.md +52 -0
- package/dist/template/.opencode/skill/browser-testing-with-devtools/SKILL.md +85 -0
- package/dist/template/.opencode/skill/code-cleanup/SKILL.md +114 -0
- package/dist/template/.opencode/skill/code-navigation/SKILL.md +142 -0
- package/dist/template/.opencode/skill/code-review-and-quality/SKILL.md +131 -0
- package/dist/template/.opencode/skill/debugging-and-error-recovery/SKILL.md +109 -0
- package/dist/template/.opencode/skill/deep-module-design/SKILL.md +207 -0
- package/dist/template/.opencode/skill/git-workflow-and-versioning/SKILL.md +77 -0
- package/dist/template/.opencode/skill/grill-me/SKILL.md +140 -0
- package/dist/template/.opencode/skill/memory-system/SKILL.md +9 -10
- package/dist/template/.opencode/skill/planning-and-task-breakdown/SKILL.md +116 -0
- package/dist/template/.opencode/skill/shipping-and-launch/SKILL.md +95 -0
- package/dist/template/.opencode/skill/source-driven-development/SKILL.md +103 -0
- package/dist/template/.opencode/skill/spec-driven-development/SKILL.md +121 -0
- package/dist/template/.opencode/skill/srcwalk/SKILL.md +161 -0
- package/dist/template/.opencode/skill/ubiquitous-language/SKILL.md +184 -0
- package/package.json +1 -1
- package/dist/template/.opencode/AGENT_ALIGNMENT.md +0 -564
- package/dist/template/.opencode/agent/painter.md +0 -83
- package/dist/template/.opencode/command/compound.md +0 -240
- package/dist/template/.opencode/command/curate.md +0 -299
- package/dist/template/.opencode/command/handoff.md +0 -149
- package/dist/template/.opencode/command/health.md +0 -356
- package/dist/template/.opencode/command/init-context.md +0 -297
- package/dist/template/.opencode/command/init-user.md +0 -125
- package/dist/template/.opencode/command/iterate.md +0 -200
- package/dist/template/.opencode/command/lfg.md +0 -173
- package/dist/template/.opencode/command/resume.md +0 -78
- package/dist/template/.opencode/command/status.md +0 -126
- package/dist/template/.opencode/command/ui-slop-check.md +0 -169
- package/dist/template/.opencode/plugin/lib/memory-tools.ts +0 -535
- package/dist/template/.opencode/skill/agent-evals/SKILL.md +0 -208
- package/dist/template/.opencode/skill/anti-ai-slop/SKILL.md +0 -76
- package/dist/template/.opencode/skill/augment-context-engine/SKILL.md +0 -122
- package/dist/template/.opencode/skill/augment-context-engine/mcp.json +0 -6
- package/dist/template/.opencode/skill/brand-asset-protocol/SKILL.md +0 -222
- package/dist/template/.opencode/skill/code-search-patterns/SKILL.md +0 -224
- package/dist/template/.opencode/skill/code-simplification/SKILL.md +0 -211
- package/dist/template/.opencode/skill/context-condensation/SKILL.md +0 -149
- package/dist/template/.opencode/skill/context-initialization/SKILL.md +0 -69
- package/dist/template/.opencode/skill/context-management/SKILL.md +0 -390
- package/dist/template/.opencode/skill/deep-research/SKILL.md +0 -384
- package/dist/template/.opencode/skill/design-direction-advisor/SKILL.md +0 -139
- package/dist/template/.opencode/skill/dispatching-parallel-agents/SKILL.md +0 -191
- package/dist/template/.opencode/skill/executing-plans/SKILL.md +0 -247
- package/dist/template/.opencode/skill/figma-go/SKILL.md +0 -65
- package/dist/template/.opencode/skill/finishing-a-development-branch/SKILL.md +0 -357
- package/dist/template/.opencode/skill/full-output-enforcement/SKILL.md +0 -62
- package/dist/template/.opencode/skill/gh-address-comments/SKILL.md +0 -29
- package/dist/template/.opencode/skill/gh-address-comments/scripts/fetch_comments.py +0 -237
- package/dist/template/.opencode/skill/gh-fix-ci/SKILL.md +0 -38
- package/dist/template/.opencode/skill/gh-fix-ci/scripts/inspect_pr_checks.py +0 -509
- package/dist/template/.opencode/skill/hi-fi-prototype-html/SKILL.md +0 -253
- package/dist/template/.opencode/skill/html-deck-export/SKILL.md +0 -189
- package/dist/template/.opencode/skill/index-knowledge/SKILL.md +0 -413
- package/dist/template/.opencode/skill/memory-grounding/SKILL.md +0 -68
- package/dist/template/.opencode/skill/playwriter/SKILL.md +0 -158
- package/dist/template/.opencode/skill/portless/SKILL.md +0 -109
- package/dist/template/.opencode/skill/prd/SKILL.md +0 -146
- package/dist/template/.opencode/skill/prd-task/SKILL.md +0 -182
- package/dist/template/.opencode/skill/prd-task/references/prd-schema.json +0 -124
- package/dist/template/.opencode/skill/prompt-leverage/SKILL.md +0 -90
- package/dist/template/.opencode/skill/prompt-leverage/references/framework.md +0 -91
- package/dist/template/.opencode/skill/prompt-leverage/scripts/augment_prompt.py +0 -157
- package/dist/template/.opencode/skill/receiving-code-review/SKILL.md +0 -263
- package/dist/template/.opencode/skill/reconcile/SKILL.md +0 -183
- package/dist/template/.opencode/skill/reflection-checkpoints/SKILL.md +0 -183
- package/dist/template/.opencode/skill/requesting-code-review/SKILL.md +0 -443
- package/dist/template/.opencode/skill/requesting-code-review/references/specialist-profiles.md +0 -108
- package/dist/template/.opencode/skill/requesting-code-review/review.md +0 -160
- package/dist/template/.opencode/skill/rtk-command-compression/SKILL.md +0 -134
- package/dist/template/.opencode/skill/screenshot/SKILL.md +0 -48
- package/dist/template/.opencode/skill/screenshot/scripts/ensure_macos_permissions.sh +0 -54
- package/dist/template/.opencode/skill/screenshot/scripts/macos_display_info.swift +0 -22
- package/dist/template/.opencode/skill/screenshot/scripts/macos_permissions.swift +0 -40
- package/dist/template/.opencode/skill/screenshot/scripts/macos_window_info.swift +0 -126
- package/dist/template/.opencode/skill/screenshot/scripts/take_screenshot.ps1 +0 -163
- package/dist/template/.opencode/skill/screenshot/scripts/take_screenshot.py +0 -585
- package/dist/template/.opencode/skill/security-threat-model/SKILL.md +0 -36
- package/dist/template/.opencode/skill/security-threat-model/references/prompt-template.md +0 -255
- package/dist/template/.opencode/skill/security-threat-model/references/security-controls-and-assets.md +0 -32
- package/dist/template/.opencode/skill/sharing-skills/SKILL.md +0 -214
- package/dist/template/.opencode/skill/skill-creator/SKILL.md +0 -181
- package/dist/template/.opencode/skill/skill-installer/SKILL.md +0 -58
- package/dist/template/.opencode/skill/skill-installer/scripts/github_utils.py +0 -21
- package/dist/template/.opencode/skill/skill-installer/scripts/install-skill-from-github.py +0 -313
- package/dist/template/.opencode/skill/skill-installer/scripts/list-skills.py +0 -106
- package/dist/template/.opencode/skill/swarm-coordination/SKILL.md +0 -244
- package/dist/template/.opencode/skill/swarm-coordination/references/architecture.md +0 -39
- package/dist/template/.opencode/skill/swarm-coordination/references/delegation-worker-protocol.md +0 -145
- package/dist/template/.opencode/skill/swarm-coordination/references/dependency-graph.md +0 -50
- package/dist/template/.opencode/skill/swarm-coordination/references/drift-check.md +0 -90
- package/dist/template/.opencode/skill/swarm-coordination/references/integration-beads.md +0 -20
- package/dist/template/.opencode/skill/swarm-coordination/references/launch-flow.md +0 -186
- package/dist/template/.opencode/skill/swarm-coordination/references/reconciler.md +0 -172
- package/dist/template/.opencode/skill/swarm-coordination/references/tier-enforcement.md +0 -78
- package/dist/template/.opencode/skill/swarm-coordination/references/tmux-integration.md +0 -134
- package/dist/template/.opencode/skill/systematic-debugging/SKILL.md +0 -402
- package/dist/template/.opencode/skill/terse-output-mode/SKILL.md +0 -95
- package/dist/template/.opencode/skill/think-in-code/SKILL.md +0 -136
- package/dist/template/.opencode/skill/ux-quality-gates/SKILL.md +0 -137
- package/dist/template/.opencode/skill/v1-run/SKILL.md +0 -175
- package/dist/template/.opencode/skill/v1-run/mcp.json +0 -6
- package/dist/template/.opencode/skill/verification-gates/SKILL.md +0 -63
- package/dist/template/.opencode/skill/visual-analysis/SKILL.md +0 -154
- package/dist/template/.opencode/skill/web-design-guidelines/SKILL.md +0 -46
- package/dist/template/.opencode/skill/workspace-setup/SKILL.md +0 -76
- package/dist/template/.opencode/skill/writing-plans/SKILL.md +0 -320
- /package/dist/template/.opencode/plugin/{lib → memory}/compact.ts +0 -0
- /package/dist/template/.opencode/plugin/{lib → memory}/db/graph.ts +0 -0
- /package/dist/template/.opencode/plugin/{lib → memory}/db/maintenance.ts +0 -0
- /package/dist/template/.opencode/plugin/{lib → memory}/db/pipeline.ts +0 -0
- /package/dist/template/.opencode/plugin/{lib → memory}/notify.ts +0 -0
- /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
|
-
}
|