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
|
@@ -17,8 +17,8 @@
|
|
|
17
17
|
|
|
18
18
|
import { upsertMemoryFile } from "./db/maintenance.js";
|
|
19
19
|
import type { ObservationRow } from "./db/types.js";
|
|
20
|
-
import { getMemoryDB } from "./
|
|
21
|
-
import { TYPE_ICONS, parseConcepts } from "./
|
|
20
|
+
import { getMemoryDB } from "./db.js";
|
|
21
|
+
import { TYPE_ICONS, parseConcepts } from "./helpers.js";
|
|
22
22
|
import { appendOperationLog } from "./operation-log.js";
|
|
23
23
|
|
|
24
24
|
// ============================================================================
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* Protects the most recent N messages from compression.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
import { estimateTokens, MEMORY_CONFIG } from "./
|
|
10
|
+
import { estimateTokens, MEMORY_CONFIG } from "./db.js";
|
|
11
11
|
|
|
12
12
|
// ============================================================================
|
|
13
13
|
// Types
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
import { getMemoryDB } from "./schema.js";
|
|
9
9
|
import type {
|
|
10
|
+
FeedbackEvent,
|
|
10
11
|
ObservationInput,
|
|
11
12
|
ObservationRow,
|
|
12
13
|
ObservationType,
|
|
@@ -19,8 +20,7 @@ import type {
|
|
|
19
20
|
|
|
20
21
|
/**
|
|
21
22
|
* Store a new observation in the database.
|
|
22
|
-
*/
|
|
23
|
-
export function storeObservation(input: ObservationInput): number {
|
|
23
|
+
*/ export function storeObservation(input: ObservationInput): number {
|
|
24
24
|
const db = getMemoryDB();
|
|
25
25
|
const now = new Date();
|
|
26
26
|
|
|
@@ -31,8 +31,10 @@ export function storeObservation(input: ObservationInput): number {
|
|
|
31
31
|
type, title, subtitle, facts, narrative, raw_source, concepts,
|
|
32
32
|
files_read, files_modified, confidence, bead_id,
|
|
33
33
|
supersedes, markdown_file, source, wing, hall, room,
|
|
34
|
+
helpful_count, harmful_count, feedback_events, effective_score,
|
|
35
|
+
maturity, retrieval_count, last_retrieved,
|
|
34
36
|
created_at, created_at_epoch
|
|
35
|
-
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
37
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
36
38
|
`,
|
|
37
39
|
)
|
|
38
40
|
.run(
|
|
@@ -53,6 +55,13 @@ export function storeObservation(input: ObservationInput): number {
|
|
|
53
55
|
input.wing ?? null,
|
|
54
56
|
input.hall ?? null,
|
|
55
57
|
input.room ?? null,
|
|
58
|
+
0, // helpful_count
|
|
59
|
+
0, // harmful_count
|
|
60
|
+
null, // feedback_events
|
|
61
|
+
0.0, // effective_score
|
|
62
|
+
"candidate", // maturity
|
|
63
|
+
0, // retrieval_count
|
|
64
|
+
null, // last_retrieved
|
|
56
65
|
now.toISOString(),
|
|
57
66
|
now.getTime(),
|
|
58
67
|
);
|
|
@@ -302,3 +311,93 @@ export function getObservationStats(): Record<string, number> {
|
|
|
302
311
|
}
|
|
303
312
|
return stats;
|
|
304
313
|
}
|
|
314
|
+
|
|
315
|
+
// ============================================================================
|
|
316
|
+
// Feedback & Tracking (aligned with pikit memory extension)
|
|
317
|
+
// ============================================================================
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* Record feedback (helpful/harmful) on an observation.
|
|
321
|
+
*/
|
|
322
|
+
export function recordFeedback(
|
|
323
|
+
observationId: number,
|
|
324
|
+
feedbackType: "helpful" | "harmful",
|
|
325
|
+
reason?: string,
|
|
326
|
+
sessionId?: string,
|
|
327
|
+
): {
|
|
328
|
+
success: boolean;
|
|
329
|
+
helpfulCount: number;
|
|
330
|
+
harmfulCount: number;
|
|
331
|
+
error?: string;
|
|
332
|
+
} {
|
|
333
|
+
const db = getMemoryDB();
|
|
334
|
+
|
|
335
|
+
const row = db
|
|
336
|
+
.query("SELECT * FROM observations WHERE id = ?")
|
|
337
|
+
.get(observationId) as ObservationRow | undefined;
|
|
338
|
+
|
|
339
|
+
if (!row) {
|
|
340
|
+
return {
|
|
341
|
+
success: false,
|
|
342
|
+
helpfulCount: 0,
|
|
343
|
+
harmfulCount: 0,
|
|
344
|
+
error: `Observation #${observationId} not found`,
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
// Parse existing feedback events
|
|
349
|
+
let events: FeedbackEvent[] = [];
|
|
350
|
+
try {
|
|
351
|
+
events = row.feedback_events ? JSON.parse(row.feedback_events) : [];
|
|
352
|
+
} catch {
|
|
353
|
+
events = [];
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
// Append new event
|
|
357
|
+
const newEvent: FeedbackEvent = {
|
|
358
|
+
type: feedbackType,
|
|
359
|
+
timestamp: Date.now(),
|
|
360
|
+
reason,
|
|
361
|
+
session_id: sessionId,
|
|
362
|
+
};
|
|
363
|
+
events.push(newEvent);
|
|
364
|
+
|
|
365
|
+
const helpfulCount =
|
|
366
|
+
feedbackType === "helpful" ? row.helpful_count + 1 : row.helpful_count;
|
|
367
|
+
const harmfulCount =
|
|
368
|
+
feedbackType === "harmful" ? row.harmful_count + 1 : row.harmful_count;
|
|
369
|
+
|
|
370
|
+
// Persist
|
|
371
|
+
db.run(
|
|
372
|
+
`UPDATE observations SET
|
|
373
|
+
helpful_count = ?,
|
|
374
|
+
harmful_count = ?,
|
|
375
|
+
feedback_events = ?,
|
|
376
|
+
updated_at = ?
|
|
377
|
+
WHERE id = ?`,
|
|
378
|
+
[
|
|
379
|
+
helpfulCount,
|
|
380
|
+
harmfulCount,
|
|
381
|
+
JSON.stringify(events),
|
|
382
|
+
new Date().toISOString(),
|
|
383
|
+
observationId,
|
|
384
|
+
],
|
|
385
|
+
);
|
|
386
|
+
|
|
387
|
+
return { success: true, helpfulCount, harmfulCount };
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
/**
|
|
391
|
+
* Increment retrieval_count and update last_retrieved for given observation IDs.
|
|
392
|
+
*/
|
|
393
|
+
export function markObservationsRetrieved(ids: number[]): void {
|
|
394
|
+
if (ids.length === 0) return;
|
|
395
|
+
const db = getMemoryDB();
|
|
396
|
+
const now = new Date().toISOString();
|
|
397
|
+
const stmt = db.query(
|
|
398
|
+
`UPDATE observations SET retrieval_count = retrieval_count + 1, last_retrieved = ? WHERE id = ?`,
|
|
399
|
+
);
|
|
400
|
+
for (const id of ids) {
|
|
401
|
+
stmt.run(now, id);
|
|
402
|
+
}
|
|
403
|
+
}
|
|
@@ -126,7 +126,7 @@ function logRecovery(message: string): void {
|
|
|
126
126
|
// Schema v3 (v2 + navigation, entity graph, raw source, chunk type)
|
|
127
127
|
// ============================================================================
|
|
128
128
|
|
|
129
|
-
const SCHEMA_VERSION =
|
|
129
|
+
const SCHEMA_VERSION = 4;
|
|
130
130
|
|
|
131
131
|
const SCHEMA_SQL = `
|
|
132
132
|
-- Schema versioning for migrations
|
|
@@ -158,6 +158,13 @@ CREATE TABLE IF NOT EXISTS observations (
|
|
|
158
158
|
wing TEXT,
|
|
159
159
|
hall TEXT CHECK(hall IS NULL OR hall IN ('facts','events','discoveries','preferences','advice')),
|
|
160
160
|
room TEXT,
|
|
161
|
+
helpful_count INTEGER NOT NULL DEFAULT 0,
|
|
162
|
+
harmful_count INTEGER NOT NULL DEFAULT 0,
|
|
163
|
+
feedback_events TEXT,
|
|
164
|
+
effective_score REAL DEFAULT 0,
|
|
165
|
+
maturity TEXT DEFAULT 'active',
|
|
166
|
+
retrieval_count INTEGER DEFAULT 0,
|
|
167
|
+
last_retrieved TEXT,
|
|
161
168
|
created_at TEXT NOT NULL,
|
|
162
169
|
created_at_epoch INTEGER NOT NULL,
|
|
163
170
|
updated_at TEXT,
|
|
@@ -610,6 +617,9 @@ function initializeSchema(db: Database): void {
|
|
|
610
617
|
if (currentVersion < 3) {
|
|
611
618
|
migrateV2ToV3(db);
|
|
612
619
|
}
|
|
620
|
+
if (currentVersion < 4) {
|
|
621
|
+
migrateV3ToV4(db);
|
|
622
|
+
}
|
|
613
623
|
}
|
|
614
624
|
|
|
615
625
|
// Record schema version
|
|
@@ -685,3 +695,35 @@ function migrateV2ToV3(db: Database): void {
|
|
|
685
695
|
}
|
|
686
696
|
}
|
|
687
697
|
}
|
|
698
|
+
|
|
699
|
+
// ============================================================================
|
|
700
|
+
// Schema v4: Pikit alignment — feedback, scoring, and tracking columns
|
|
701
|
+
// ============================================================================
|
|
702
|
+
|
|
703
|
+
const MIGRATION_V3_TO_V4 = `
|
|
704
|
+
ALTER TABLE observations ADD COLUMN helpful_count INTEGER NOT NULL DEFAULT 0;
|
|
705
|
+
ALTER TABLE observations ADD COLUMN harmful_count INTEGER NOT NULL DEFAULT 0;
|
|
706
|
+
ALTER TABLE observations ADD COLUMN feedback_events TEXT;
|
|
707
|
+
ALTER TABLE observations ADD COLUMN effective_score REAL DEFAULT 0;
|
|
708
|
+
ALTER TABLE observations ADD COLUMN maturity TEXT DEFAULT 'active';
|
|
709
|
+
ALTER TABLE observations ADD COLUMN retrieval_count INTEGER DEFAULT 0;
|
|
710
|
+
ALTER TABLE observations ADD COLUMN last_retrieved TEXT;
|
|
711
|
+
`;
|
|
712
|
+
|
|
713
|
+
/**
|
|
714
|
+
* Migrate from schema v3 to v4.
|
|
715
|
+
* Adds: helpful_count, harmful_count, feedback_events, effective_score,
|
|
716
|
+
* maturity, retrieval_count, last_retrieved.
|
|
717
|
+
*/
|
|
718
|
+
function migrateV3ToV4(db: Database): void {
|
|
719
|
+
for (const stmt of MIGRATION_V3_TO_V4.split(";")) {
|
|
720
|
+
const trimmed = stmt.trim();
|
|
721
|
+
if (trimmed) {
|
|
722
|
+
try {
|
|
723
|
+
db.run(trimmed);
|
|
724
|
+
} catch {
|
|
725
|
+
// Statement may fail if already applied (e.g. column exists)
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
}
|
|
@@ -145,6 +145,13 @@ export interface ObservationRow {
|
|
|
145
145
|
wing: string | null; // v3: navigation wing (project/person)
|
|
146
146
|
hall: HallType | null; // v3: navigation hall (facts/events/...)
|
|
147
147
|
room: string | null; // v3: navigation room (topic)
|
|
148
|
+
helpful_count: number;
|
|
149
|
+
harmful_count: number;
|
|
150
|
+
feedback_events: string | null; // JSON array of FeedbackEvent
|
|
151
|
+
effective_score: number | null;
|
|
152
|
+
maturity: string | null;
|
|
153
|
+
retrieval_count: number | null;
|
|
154
|
+
last_retrieved: string | null;
|
|
148
155
|
created_at: string;
|
|
149
156
|
created_at_epoch: number;
|
|
150
157
|
updated_at: string | null;
|
|
@@ -282,3 +289,18 @@ export interface ArchiveOptions {
|
|
|
282
289
|
/** Dry run — don't actually archive, just count */
|
|
283
290
|
dryRun?: boolean;
|
|
284
291
|
}
|
|
292
|
+
|
|
293
|
+
// ============================================================================
|
|
294
|
+
// Feedback & Scoring Types (aligned with pikit memory extension)
|
|
295
|
+
// ============================================================================
|
|
296
|
+
|
|
297
|
+
export type FeedbackType = "helpful" | "harmful";
|
|
298
|
+
|
|
299
|
+
export interface FeedbackEvent {
|
|
300
|
+
type: FeedbackType;
|
|
301
|
+
timestamp: number; // Date.now()
|
|
302
|
+
reason?: string;
|
|
303
|
+
session_id?: string;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
export type MaturityState = "candidate" | "active" | "stale" | "deprecated";
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Memory Database Module v3 — Barrel Export
|
|
3
3
|
*
|
|
4
4
|
* Re-exports all functions and types from sub-modules in ./db/.
|
|
5
|
-
* This preserves backward compatibility for existing imports from "./
|
|
5
|
+
* This preserves backward compatibility for existing imports from "./db.js".
|
|
6
6
|
*
|
|
7
7
|
* Sub-module structure:
|
|
8
8
|
* db/types.ts — Configuration, types, interfaces
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import { readFile } from "node:fs/promises";
|
|
9
|
-
import type { ObservationType } from "./
|
|
9
|
+
import type { ObservationType } from "./db.js";
|
|
10
10
|
|
|
11
11
|
// ============================================================================
|
|
12
12
|
// Constants
|
|
@@ -120,6 +120,8 @@ export function formatObservation(obs: {
|
|
|
120
120
|
supersedes?: number | null;
|
|
121
121
|
superseded_by?: number | null;
|
|
122
122
|
source?: string | null;
|
|
123
|
+
helpful_count?: number | null;
|
|
124
|
+
harmful_count?: number | null;
|
|
123
125
|
created_at?: string | null;
|
|
124
126
|
}): string {
|
|
125
127
|
const icon = TYPE_ICONS[obs.type] ?? "\uD83D\uDCCC";
|
|
@@ -135,6 +137,8 @@ export function formatObservation(obs: {
|
|
|
135
137
|
if (obs.bead_id) lines.push(` Bead: ${obs.bead_id}`);
|
|
136
138
|
if (obs.supersedes) lines.push(` Supersedes: #${obs.supersedes}`);
|
|
137
139
|
if (obs.superseded_by) lines.push(` Superseded by: #${obs.superseded_by}`);
|
|
140
|
+
if ((obs.helpful_count ?? 0) > 0 || (obs.harmful_count ?? 0) > 0)
|
|
141
|
+
lines.push(` Feedback: ${obs.helpful_count ?? 0}\uD83D\uDC4D / ${obs.harmful_count ?? 0}\uD83D\uDC4E`);
|
|
138
142
|
if (obs.narrative) lines.push(`\n${obs.narrative}`);
|
|
139
143
|
if (obs.created_at) lines.push(`\n _Created: ${obs.created_at}_`);
|
|
140
144
|
return lines.join("\n");
|
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
|
|
11
11
|
import { upsertMemoryFile } from "./db/maintenance.js";
|
|
12
12
|
import type { ObservationRow } from "./db/types.js";
|
|
13
|
-
import { getMemoryDB } from "./
|
|
14
|
-
import { TYPE_ICONS, parseConcepts } from "./
|
|
13
|
+
import { getMemoryDB } from "./db.js";
|
|
14
|
+
import { TYPE_ICONS, parseConcepts } from "./helpers.js";
|
|
15
15
|
|
|
16
16
|
// ============================================================================
|
|
17
17
|
// Types
|
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
import type { ObservationRow } from "./db/types.js";
|
|
12
|
-
import { getMemoryDB } from "./
|
|
13
|
-
import { hasWord, parseConcepts } from "./
|
|
12
|
+
import { getMemoryDB } from "./db.js";
|
|
13
|
+
import { hasWord, parseConcepts } from "./helpers.js";
|
|
14
14
|
|
|
15
15
|
// ============================================================================
|
|
16
16
|
// Types
|
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core Memory Tools
|
|
3
|
+
*
|
|
4
|
+
* Two tools aligned with pikit memory extension:
|
|
5
|
+
* - observation: create observations OR give feedback on existing ones
|
|
6
|
+
* - memory-search: search observations by text OR read memory files by path
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { tool, type ToolContext } from "@opencode-ai/plugin/tool";
|
|
10
|
+
import {
|
|
11
|
+
type ConfidenceLevel,
|
|
12
|
+
type ObservationSource,
|
|
13
|
+
type ObservationType,
|
|
14
|
+
type HallType,
|
|
15
|
+
VALID_HALLS,
|
|
16
|
+
} from "./db/types.js";
|
|
17
|
+
import {
|
|
18
|
+
autoDetectFiles,
|
|
19
|
+
parseCSV,
|
|
20
|
+
formatObservation,
|
|
21
|
+
TYPE_ICONS,
|
|
22
|
+
VALID_TYPES,
|
|
23
|
+
} from "./helpers.js";
|
|
24
|
+
import { validateObservation } from "./validate.js";
|
|
25
|
+
import {
|
|
26
|
+
storeObservation,
|
|
27
|
+
getObservationById,
|
|
28
|
+
searchObservationsFTS,
|
|
29
|
+
recordFeedback,
|
|
30
|
+
markObservationsRetrieved,
|
|
31
|
+
} from "./db/observations.js";
|
|
32
|
+
import { getMemoryFile } from "./db/maintenance.js";
|
|
33
|
+
|
|
34
|
+
// ============================================================================
|
|
35
|
+
// Error Handling Wrapper
|
|
36
|
+
// ============================================================================
|
|
37
|
+
|
|
38
|
+
function withDBErrorHandling<T extends Record<string, unknown>>(
|
|
39
|
+
handler: (args: T) => string | Promise<string>,
|
|
40
|
+
): (args: T, context: ToolContext) => Promise<string> {
|
|
41
|
+
return async (args: T, _context: ToolContext) => {
|
|
42
|
+
try {
|
|
43
|
+
return await handler(args);
|
|
44
|
+
} catch (err) {
|
|
45
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
46
|
+
return `Error: ${msg}`;
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// ============================================================================
|
|
52
|
+
// Tool Definitions
|
|
53
|
+
// ============================================================================
|
|
54
|
+
|
|
55
|
+
interface CoreToolDeps {
|
|
56
|
+
handoffDir: string;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function createCoreTools(deps: CoreToolDeps) {
|
|
60
|
+
const { handoffDir } = deps;
|
|
61
|
+
|
|
62
|
+
return {
|
|
63
|
+
// --------------------------------------------------------------------
|
|
64
|
+
// observation: Create or give feedback
|
|
65
|
+
// --------------------------------------------------------------------
|
|
66
|
+
observation: tool({
|
|
67
|
+
description: `Create a durable observation for future retrieval, or mark an existing one as helpful/harmful.
|
|
68
|
+
Pass id+feedback for feedback mode; pass type+title for create mode.
|
|
69
|
+
|
|
70
|
+
Create mode captures decisions, bugs, features, patterns, discoveries, learnings, or warnings.
|
|
71
|
+
Feedback mode lets you rate past observations.
|
|
72
|
+
|
|
73
|
+
Create mode examples:
|
|
74
|
+
observation({ type: "decision", title: "Use JWT for auth", narrative: "Stateless across services.", confidence: "high" })
|
|
75
|
+
observation({ type: "bugfix", title: "Fix null pointer", files_modified: "src/auth.ts" })
|
|
76
|
+
|
|
77
|
+
Feedback mode examples:
|
|
78
|
+
observation({ id: 42, feedback: "helpful" })
|
|
79
|
+
observation({ id: 42, feedback: "harmful", reason: "Outdated information" })`,
|
|
80
|
+
args: {
|
|
81
|
+
// --- Create mode params ---
|
|
82
|
+
type: tool.schema
|
|
83
|
+
.string()
|
|
84
|
+
.optional()
|
|
85
|
+
.describe(
|
|
86
|
+
"Observation type for create mode: decision, bugfix, feature, pattern, discovery, learning, warning",
|
|
87
|
+
),
|
|
88
|
+
title: tool.schema.string().optional().describe("Short title (create mode)"),
|
|
89
|
+
subtitle: tool.schema.string().optional().describe("Optional subtitle"),
|
|
90
|
+
facts: tool.schema
|
|
91
|
+
.string()
|
|
92
|
+
.optional()
|
|
93
|
+
.describe("Comma-separated key facts"),
|
|
94
|
+
narrative: tool.schema
|
|
95
|
+
.string()
|
|
96
|
+
.optional()
|
|
97
|
+
.describe("Detailed context"),
|
|
98
|
+
content: tool.schema
|
|
99
|
+
.string()
|
|
100
|
+
.optional()
|
|
101
|
+
.describe("Alias for narrative"),
|
|
102
|
+
concepts: tool.schema
|
|
103
|
+
.string()
|
|
104
|
+
.optional()
|
|
105
|
+
.describe("Comma-separated concepts"),
|
|
106
|
+
files_read: tool.schema
|
|
107
|
+
.string()
|
|
108
|
+
.optional()
|
|
109
|
+
.describe("Comma-separated files read"),
|
|
110
|
+
files_modified: tool.schema
|
|
111
|
+
.string()
|
|
112
|
+
.optional()
|
|
113
|
+
.describe("Comma-separated files modified"),
|
|
114
|
+
files: tool.schema
|
|
115
|
+
.string()
|
|
116
|
+
.optional()
|
|
117
|
+
.describe("Alias for files_modified"),
|
|
118
|
+
bead_id: tool.schema.string().optional().describe("Related bead ID"),
|
|
119
|
+
confidence: tool.schema
|
|
120
|
+
.string()
|
|
121
|
+
.optional()
|
|
122
|
+
.describe("high, medium, or low"),
|
|
123
|
+
supersedes: tool.schema
|
|
124
|
+
.string()
|
|
125
|
+
.optional()
|
|
126
|
+
.describe("Observation ID this supersedes"),
|
|
127
|
+
source: tool.schema
|
|
128
|
+
.string()
|
|
129
|
+
.optional()
|
|
130
|
+
.describe("manual, curator, or imported"),
|
|
131
|
+
hall: tool.schema
|
|
132
|
+
.string()
|
|
133
|
+
.optional()
|
|
134
|
+
.describe("Navigation hall: facts, events, discoveries, preferences, advice"),
|
|
135
|
+
|
|
136
|
+
// --- Feedback mode params ---
|
|
137
|
+
id: tool.schema
|
|
138
|
+
.number()
|
|
139
|
+
.optional()
|
|
140
|
+
.describe("Observation ID for feedback mode"),
|
|
141
|
+
feedback: tool.schema
|
|
142
|
+
.string()
|
|
143
|
+
.optional()
|
|
144
|
+
.describe('"helpful" or "harmful" (feedback mode)'),
|
|
145
|
+
reason: tool.schema
|
|
146
|
+
.string()
|
|
147
|
+
.optional()
|
|
148
|
+
.describe("Optional reason for feedback"),
|
|
149
|
+
},
|
|
150
|
+
execute: withDBErrorHandling(async (args) => {
|
|
151
|
+
// --- Feedback mode: observation #id marked helpful/harmful ---
|
|
152
|
+
if (args.id !== undefined && args.feedback !== undefined) {
|
|
153
|
+
const obsId = Number(args.id);
|
|
154
|
+
if (!Number.isInteger(obsId)) return "❌ id must be an integer.";
|
|
155
|
+
const fb = String(args.feedback);
|
|
156
|
+
if (fb !== "helpful" && fb !== "harmful") return '❌ feedback must be "helpful" or "harmful".';
|
|
157
|
+
|
|
158
|
+
const result = recordFeedback(obsId, fb, args.reason as string | undefined);
|
|
159
|
+
if (!result.success) return `❌ ${result.error ?? "Failed to record feedback."}`;
|
|
160
|
+
|
|
161
|
+
return [
|
|
162
|
+
`✅ Observation #${obsId} marked as ${fb}.`,
|
|
163
|
+
`- Feedback: ${result.helpfulCount} helpful / ${result.harmfulCount} harmful`,
|
|
164
|
+
].join("\n");
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// --- Create mode: store a new observation ---
|
|
168
|
+
if (!args.type || !args.title) {
|
|
169
|
+
return "❌ Provide type+title to create an observation, or id+feedback to give feedback.";
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
const obsType = args.type as ObservationType;
|
|
173
|
+
if (!VALID_TYPES.includes(obsType)) {
|
|
174
|
+
return `Error: Invalid type "${args.type}". Valid: ${VALID_TYPES.join(", ")}`;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
const confidence = (args.confidence ?? "high") as ConfidenceLevel;
|
|
178
|
+
if (!["high", "medium", "low"].includes(confidence)) {
|
|
179
|
+
return `Error: Invalid confidence "${args.confidence}". Valid: high, medium, low`;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const narrative = args.narrative ?? args.content;
|
|
183
|
+
const facts = parseCSV(args.facts);
|
|
184
|
+
const concepts = parseCSV(args.concepts);
|
|
185
|
+
let filesRead = parseCSV(args.files_read);
|
|
186
|
+
const filesModified = parseCSV(args.files_modified ?? args.files);
|
|
187
|
+
|
|
188
|
+
// Auto-detect files from narrative if not explicitly provided
|
|
189
|
+
if (!filesRead && narrative) {
|
|
190
|
+
const detected = autoDetectFiles(narrative);
|
|
191
|
+
if (detected.length > 0) filesRead = detected;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
let supersedes: number | undefined;
|
|
195
|
+
if (args.supersedes) {
|
|
196
|
+
const parsed = Number.parseInt(args.supersedes, 10);
|
|
197
|
+
if (!Number.isNaN(parsed)) supersedes = parsed;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
const source = (args.source ?? "manual") as ObservationSource;
|
|
201
|
+
const hall = args.hall as HallType | undefined;
|
|
202
|
+
|
|
203
|
+
// Validation gate: check for duplicates, contradictions, low quality
|
|
204
|
+
const validation = validateObservation({
|
|
205
|
+
type: obsType,
|
|
206
|
+
title: args.title,
|
|
207
|
+
facts,
|
|
208
|
+
narrative,
|
|
209
|
+
concepts,
|
|
210
|
+
confidence,
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
if (validation.verdict === "reject") {
|
|
214
|
+
const reasons = validation.issues.map(i => i.message).join("; ");
|
|
215
|
+
const dupHint = validation.duplicateOf
|
|
216
|
+
? ` Use \`observation({ supersedes: "${validation.duplicateOf}", ... })\` to update it.`
|
|
217
|
+
: "";
|
|
218
|
+
return `Rejected: ${reasons}.${dupHint}`;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
const id = storeObservation({
|
|
222
|
+
type: obsType,
|
|
223
|
+
title: args.title,
|
|
224
|
+
subtitle: args.subtitle,
|
|
225
|
+
facts,
|
|
226
|
+
narrative,
|
|
227
|
+
concepts,
|
|
228
|
+
files_read: filesRead,
|
|
229
|
+
files_modified: filesModified,
|
|
230
|
+
confidence,
|
|
231
|
+
bead_id: args.bead_id,
|
|
232
|
+
supersedes,
|
|
233
|
+
source,
|
|
234
|
+
hall,
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
const warnings = validation.issues.length > 0
|
|
238
|
+
? `\n⚠️ Warnings: ${validation.issues.map(i => i.message).join("; ")}`
|
|
239
|
+
: "";
|
|
240
|
+
|
|
241
|
+
return `${TYPE_ICONS[obsType] ?? "📌"} Observation #${id} stored [${obsType}] "${args.title}" (confidence: ${confidence}, source: ${source})${warnings}`;
|
|
242
|
+
}),
|
|
243
|
+
}),
|
|
244
|
+
|
|
245
|
+
// --------------------------------------------------------------------
|
|
246
|
+
// memory-search: Search or read memory
|
|
247
|
+
// --------------------------------------------------------------------
|
|
248
|
+
"memory-search": tool({
|
|
249
|
+
description: `Search observations by text query / #id references, or read a memory file by path.
|
|
250
|
+
Pass file=path to read a memory file; pass query=text to search observations.
|
|
251
|
+
|
|
252
|
+
Search modes:
|
|
253
|
+
- query only: Search observations using FTS5 (falls back to LIKE)
|
|
254
|
+
- query + type: Filter observations by type (decision, bugfix, etc.)
|
|
255
|
+
- file=path: Read a memory file (e.g. persona/default, scenes/<id>)
|
|
256
|
+
- #id refs: Lookup observations by ID number`,
|
|
257
|
+
args: {
|
|
258
|
+
query: tool.schema
|
|
259
|
+
.string()
|
|
260
|
+
.optional()
|
|
261
|
+
.describe("Search query or #id references"),
|
|
262
|
+
type: tool.schema
|
|
263
|
+
.string()
|
|
264
|
+
.optional()
|
|
265
|
+
.describe("Optional observation type filter"),
|
|
266
|
+
limit: tool.schema
|
|
267
|
+
.number()
|
|
268
|
+
.optional()
|
|
269
|
+
.describe("Maximum results, default 10"),
|
|
270
|
+
file: tool.schema
|
|
271
|
+
.string()
|
|
272
|
+
.optional()
|
|
273
|
+
.describe("Memory file path (e.g. persona/default, scenes/<id>)"),
|
|
274
|
+
},
|
|
275
|
+
execute: withDBErrorHandling(async (args) => {
|
|
276
|
+
const limit = Math.min(args.limit ?? 10, 50);
|
|
277
|
+
|
|
278
|
+
// --- File mode: read a memory file by path ---
|
|
279
|
+
if (args.file) {
|
|
280
|
+
const filePath = String(args.file);
|
|
281
|
+
const row = getMemoryFile(filePath);
|
|
282
|
+
if (!row) return `Memory file not found: ${filePath}`;
|
|
283
|
+
return row.content;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// --- ID refs mode: resolve #N references ---
|
|
287
|
+
if (args.query) {
|
|
288
|
+
const query = String(args.query);
|
|
289
|
+
const idRefs = [...query.matchAll(/#(\d+)/g)].map(m => parseInt(m[1], 10));
|
|
290
|
+
if (idRefs.length > 0) {
|
|
291
|
+
const rows = idRefs
|
|
292
|
+
.map(id => getObservationById(id))
|
|
293
|
+
.filter((r): r is NonNullable<typeof r> => r !== null);
|
|
294
|
+
if (rows.length === 0) return "No observations found for the requested IDs.";
|
|
295
|
+
return rows.map(r => formatObservation(r)).join("\n\n---\n\n");
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// --- Search mode ---
|
|
300
|
+
const query = args.query ? String(args.query).trim() : "";
|
|
301
|
+
const scope = (args.type ?? "observations") as string;
|
|
302
|
+
const typeFilter = VALID_TYPES.includes(scope as ObservationType)
|
|
303
|
+
? (scope as ObservationType)
|
|
304
|
+
: undefined;
|
|
305
|
+
|
|
306
|
+
let rows;
|
|
307
|
+
try {
|
|
308
|
+
rows = searchObservationsFTS(query, { type: typeFilter, limit });
|
|
309
|
+
} catch {
|
|
310
|
+
return "Search failed.";
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
if (rows.length === 0) return "No matching observations found.";
|
|
314
|
+
|
|
315
|
+
// Track retrieval
|
|
316
|
+
markObservationsRetrieved(rows.map(r => r.id));
|
|
317
|
+
|
|
318
|
+
return rows.map(r => formatObservation(r)).join("\n\n---\n\n");
|
|
319
|
+
}),
|
|
320
|
+
}),
|
|
321
|
+
};
|
|
322
|
+
}
|