squish-memory 1.0.2 → 1.1.5
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/.env.example +130 -0
- package/CHANGELOG.md +55 -0
- package/README.md +150 -287
- package/config/hooks/claude-code-hooks.json +39 -0
- package/config/hooks/cursor-hooks.json +30 -0
- package/config/hooks/opencode-hooks.json +30 -0
- package/config/hooks/windsurf-hooks.json +30 -0
- package/config/mcp-mode-semantics.json +23 -21
- package/config/plugin-manifest.json +101 -152
- package/{plugin.json → config/plugin.json} +2 -2
- package/config/settings.json +52 -51
- package/{commands → core/commands}/init.md +39 -39
- package/dist/config.d.ts +28 -4
- package/dist/config.js +97 -29
- package/dist/core/adapters/config/claude-code.d.ts +45 -0
- package/dist/core/adapters/config/claude-code.js +113 -0
- package/dist/core/adapters/config/cursor.d.ts +26 -0
- package/dist/core/adapters/config/cursor.js +74 -0
- package/dist/core/adapters/config/opencode.d.ts +23 -0
- package/dist/core/adapters/config/opencode.js +73 -0
- package/dist/core/adapters/config/windsurf.d.ts +26 -0
- package/dist/core/adapters/config/windsurf.js +74 -0
- package/dist/core/adapters/index.d.ts +45 -0
- package/dist/core/adapters/index.js +84 -0
- package/dist/core/adapters/scripts/install-adapter.d.ts +19 -0
- package/dist/core/adapters/scripts/install-adapter.js +149 -0
- package/dist/core/adapters/timeline.d.ts +23 -0
- package/dist/core/adapters/timeline.js +88 -0
- package/dist/core/adapters/types.d.ts +157 -0
- package/dist/core/adapters/types.js +50 -0
- package/dist/{algorithms → core/algorithms}/analytics/token-estimator.d.ts +1 -1
- package/dist/{algorithms → core/algorithms}/analytics/token-estimator.js +3 -3
- package/dist/{algorithms → core/algorithms}/detection/semantic-ranker.d.ts +1 -1
- package/dist/{algorithms → core/algorithms}/detection/semantic-ranker.js +1 -1
- package/dist/{algorithms → core/algorithms}/detection/two-stage-detector.d.ts +1 -1
- package/dist/{algorithms → core/algorithms}/detection/two-stage-detector.js +7 -10
- package/dist/{algorithms → core/algorithms}/handlers/approve-merge.js +4 -4
- package/dist/{algorithms → core/algorithms}/handlers/detect-duplicates.js +3 -3
- package/dist/{algorithms → core/algorithms}/handlers/get-stats.js +3 -3
- package/dist/{algorithms → core/algorithms}/handlers/list-proposals.js +3 -3
- package/dist/{algorithms → core/algorithms}/handlers/preview-merge.js +3 -3
- package/dist/{algorithms → core/algorithms}/handlers/reject-merge.js +3 -3
- package/dist/{algorithms → core/algorithms}/handlers/reverse-merge.js +3 -3
- package/dist/core/algorithms/index.d.ts +21 -0
- package/dist/core/algorithms/index.js +26 -0
- package/dist/core/algorithms/operations/cache-maintenance.d.ts +12 -0
- package/dist/core/algorithms/operations/cache-maintenance.js +157 -0
- package/dist/{algorithms → core/algorithms}/safety/safety-checks.d.ts +1 -1
- package/dist/{algorithms → core/algorithms}/strategies/merge-strategies.d.ts +19 -1
- package/dist/{algorithms → core/algorithms}/strategies/merge-strategies.js +74 -123
- package/dist/core/algorithms/types.d.ts +133 -0
- package/dist/core/algorithms/types.js +5 -0
- package/dist/core/associations.d.ts +1 -2
- package/dist/core/associations.js +1 -2
- package/dist/core/autosave.d.ts +19 -0
- package/dist/core/autosave.js +16 -0
- package/dist/{commands → core/commands}/managed-sync.js +5 -5
- package/dist/core/commands/mcp-server.js +739 -0
- package/dist/core/context/agent-context.d.ts +106 -0
- package/dist/core/context/agent-context.js +274 -0
- package/dist/core/{context-paging.d.ts → context/context-paging.d.ts} +2 -12
- package/dist/core/{context-paging.js → context/context-paging.js} +19 -39
- package/dist/core/context/context-window.d.ts +40 -0
- package/dist/core/context/context-window.js +177 -0
- package/dist/core/context/context.js +22 -0
- package/dist/core/embeddings.d.ts +1 -1
- package/dist/core/embeddings.js +54 -2
- package/dist/core/error-handling.d.ts +63 -0
- package/dist/core/error-handling.js +173 -0
- package/dist/core/external-folder/index.d.ts +102 -0
- package/dist/core/external-folder/index.js +294 -0
- package/dist/core/hooks/agent-hooks.d.ts +74 -0
- package/dist/core/hooks/agent-hooks.js +244 -0
- package/dist/core/hooks/auto-tagger.d.ts +19 -0
- package/dist/core/hooks/auto-tagger.js +155 -0
- package/dist/core/hooks/capture-filter.d.ts +41 -0
- package/dist/core/hooks/capture-filter.js +128 -0
- package/dist/core/index.d.ts +6 -6
- package/dist/core/index.js +6 -6
- package/dist/core/{agent-memory.js → ingestion/agent-memory.js} +5 -7
- package/dist/core/{core-memory.js → ingestion/core-memory.js} +4 -4
- package/dist/core/ingestion/learnings.d.ts +57 -0
- package/dist/core/ingestion/learnings.js +202 -0
- package/dist/core/lib/db-client.d.ts +114 -0
- package/dist/core/lib/db-client.js +130 -0
- package/dist/core/lib/schemas.d.ts +129 -0
- package/dist/core/lib/schemas.js +87 -0
- package/dist/core/{utils.d.ts → lib/utils.d.ts} +1 -0
- package/dist/core/{utils.js → lib/utils.js} +31 -15
- package/dist/core/lib/validation.d.ts +38 -0
- package/dist/core/lib/validation.js +151 -0
- package/dist/core/lifecycle.d.ts +7 -0
- package/dist/core/lifecycle.js +140 -20
- package/dist/core/local-embeddings.d.ts +6 -1
- package/dist/core/local-embeddings.js +6 -15
- package/dist/core/logger.js +7 -1
- package/dist/core/mcp/tools.js +35 -3
- package/dist/core/memory/categorizer.js +1 -0
- package/dist/core/memory/conflict-detector.js +1 -1
- package/dist/core/memory/consolidation.d.ts +1 -10
- package/dist/core/memory/consolidation.js +2 -11
- package/dist/core/memory/context-collector.js +1 -1
- package/dist/core/memory/edit-workflow.js +1 -1
- package/dist/core/memory/entity-resolver.js +7 -7
- package/dist/core/memory/fact-extractor.js +12 -12
- package/dist/core/memory/feedback-tracker.js +1 -1
- package/dist/core/memory/hooks.d.ts +88 -0
- package/dist/core/memory/hooks.js +174 -0
- package/dist/core/memory/hybrid-retrieval.js +2 -2
- package/dist/core/memory/hybrid-search.d.ts +1 -6
- package/dist/core/memory/hybrid-search.js +70 -84
- package/dist/core/memory/importance.d.ts +8 -13
- package/dist/core/memory/importance.js +47 -74
- package/dist/core/memory/loader.d.ts +31 -0
- package/dist/core/memory/loader.js +141 -0
- package/dist/core/memory/markdown/markdown-storage.d.ts +72 -0
- package/dist/core/memory/markdown/markdown-storage.js +243 -0
- package/dist/core/memory/memories.d.ts +12 -4
- package/dist/core/memory/memories.js +192 -180
- package/dist/core/memory/memory-lifecycle.d.ts +8 -0
- package/dist/core/memory/memory-lifecycle.js +55 -0
- package/dist/core/memory/migrate.d.ts +21 -0
- package/dist/core/memory/migrate.js +134 -0
- package/dist/core/memory/normalization.d.ts +22 -0
- package/dist/core/memory/normalization.js +26 -0
- package/dist/core/memory/progressive-disclosure.js +1 -1
- package/dist/core/memory/query-rewriter.js +9 -9
- package/dist/core/memory/serialization.d.ts +4 -0
- package/dist/core/memory/serialization.js +49 -0
- package/dist/core/memory/stats.d.ts +5 -0
- package/dist/core/memory/stats.js +63 -12
- package/dist/core/memory/temporal-facts.js +21 -0
- package/dist/core/memory/write-gate.js +1 -1
- package/dist/core/obsidian-vault.d.ts +30 -0
- package/dist/core/obsidian-vault.js +94 -0
- package/dist/core/places/index.d.ts +14 -0
- package/dist/core/places/index.js +14 -0
- package/dist/core/places/memory-places.d.ts +68 -0
- package/dist/core/places/memory-places.js +261 -0
- package/dist/core/places/places.d.ts +88 -0
- package/dist/core/places/places.js +314 -0
- package/dist/core/places/rules.d.ts +74 -0
- package/dist/core/places/rules.js +240 -0
- package/dist/core/places/walking.d.ts +56 -0
- package/dist/core/places/walking.js +121 -0
- package/dist/core/projects.d.ts +5 -0
- package/dist/core/projects.js +39 -18
- package/dist/core/responses.d.ts +96 -0
- package/dist/core/responses.js +122 -0
- package/dist/core/scheduler/cron-scheduler.js +29 -7
- package/dist/core/scheduler/index.d.ts +1 -1
- package/dist/core/scheduler/index.js +1 -1
- package/dist/core/scheduler/job-runner.js +1 -1
- package/dist/core/search/conversations.js +40 -42
- package/dist/core/search/entities.js +6 -9
- package/dist/core/search/graph-boost.d.ts +7 -0
- package/dist/core/search/graph-boost.js +23 -0
- package/dist/core/search/qmd-search.js +4 -4
- package/dist/core/security/encrypt.d.ts +6 -0
- package/dist/core/security/encrypt.js +47 -0
- package/dist/core/{governance.d.ts → security/governance.d.ts} +6 -1
- package/dist/core/security/governance.js +79 -0
- package/dist/core/session/auto-load.js +6 -6
- package/dist/core/session/index.d.ts +1 -1
- package/dist/core/session/index.js +1 -1
- package/dist/core/session/self-iteration-job.d.ts +20 -0
- package/dist/core/session/self-iteration-job.js +282 -0
- package/dist/core/session/session-hooks.d.ts +18 -0
- package/dist/core/session/session-hooks.js +58 -0
- package/dist/core/session-hooks/self-iteration-job.js +35 -35
- package/dist/core/{cache.js → storage/cache.js} +2 -2
- package/dist/core/sync/qmd-sync.d.ts +1 -13
- package/dist/core/sync/qmd-sync.js +1 -13
- package/dist/core/toon.d.ts +43 -0
- package/dist/core/toon.js +160 -0
- package/dist/core/utils/memory-operations.js +1 -1
- package/dist/core/utils/vector-operations.d.ts +71 -0
- package/dist/core/utils/vector-operations.js +129 -0
- package/dist/db/adapter.d.ts +3 -3
- package/dist/db/adapter.js +99 -88
- package/dist/db/bootstrap.js +820 -522
- package/dist/{drizzle → db/drizzle}/schema-sqlite.d.ts +74 -25
- package/dist/{drizzle → db/drizzle}/schema-sqlite.js +91 -24
- package/dist/{drizzle → db/drizzle}/schema.d.ts +79 -32
- package/dist/{drizzle → db/drizzle}/schema.js +106 -35
- package/dist/db/drizzle.config.d.ts +3 -0
- package/dist/db/drizzle.config.js +12 -0
- package/dist/db/index.d.ts +1 -5
- package/dist/db/index.js +51 -8
- package/dist/db/neon.d.ts +8 -0
- package/dist/db/neon.js +20 -0
- package/dist/db/schema/index.d.ts +40 -0
- package/dist/db/schema/index.js +105 -0
- package/dist/db/schema/tables/context-sessions.d.ts +9 -0
- package/dist/db/schema/tables/context-sessions.js +37 -0
- package/dist/db/schema/tables/conversations.d.ts +9 -0
- package/dist/db/schema/tables/conversations.js +47 -0
- package/dist/db/schema/tables/core-memory.d.ts +9 -0
- package/dist/db/schema/tables/core-memory.js +41 -0
- package/dist/db/schema/tables/entities.d.ts +9 -0
- package/dist/db/schema/tables/entities.js +39 -0
- package/dist/db/schema/tables/entity-relations.d.ts +9 -0
- package/dist/db/schema/tables/entity-relations.js +31 -0
- package/dist/db/schema/tables/learnings.d.ts +9 -0
- package/dist/db/schema/tables/learnings.js +66 -0
- package/dist/db/schema/tables/memories.d.ts +9 -0
- package/dist/db/schema/tables/memories.js +161 -0
- package/dist/db/schema/tables/memory-associations.d.ts +9 -0
- package/dist/db/schema/tables/memory-associations.js +39 -0
- package/dist/db/schema/tables/memory-hash-cache.d.ts +9 -0
- package/dist/db/schema/tables/memory-hash-cache.js +29 -0
- package/dist/db/schema/tables/memory-merge-history.d.ts +9 -0
- package/dist/db/schema/tables/memory-merge-history.js +33 -0
- package/dist/db/schema/tables/memory-merge-proposals.d.ts +9 -0
- package/dist/db/schema/tables/memory-merge-proposals.js +39 -0
- package/dist/db/schema/tables/messages.d.ts +9 -0
- package/dist/db/schema/tables/messages.js +41 -0
- package/dist/db/schema/tables/namespaces.d.ts +9 -0
- package/dist/db/schema/tables/namespaces.js +37 -0
- package/dist/db/schema/tables/projects.d.ts +9 -0
- package/dist/db/schema/tables/projects.js +31 -0
- package/dist/db/schema/tables/users.d.ts +9 -0
- package/dist/db/schema/tables/users.js +27 -0
- package/dist/db/schema.d.ts +1 -1
- package/dist/db/schema.js +2 -2
- package/dist/db/supabase.d.ts +9 -0
- package/dist/db/supabase.js +24 -0
- package/dist/index.d.ts +2 -14
- package/dist/index.js +1320 -640
- package/dist/vendor/sql.js/sql-wasm.wasm +0 -0
- package/dist/webui/server.d.ts +5 -0
- package/dist/{api/web/web.js → webui/server.js} +511 -508
- package/generated/mcp/manifest.json +1 -1
- package/{.mcp.json → mcp.json.example} +1 -1
- package/package.json +159 -181
- package/scripts/README.md +60 -0
- package/scripts/copy-runtime-assets.mjs +26 -0
- package/scripts/generate-mcp.mjs +264 -264
- package/scripts/github-release.sh +4 -4
- package/scripts/install-claude-code.sh +85 -0
- package/scripts/install-cursor.sh +56 -0
- package/scripts/install-hooks.sh +73 -0
- package/scripts/install-interactive.mjs +357 -677
- package/scripts/install-opencode.sh +75 -0
- package/scripts/install-windsurf.sh +67 -0
- package/skills/squish-memory/SKILL.md +104 -114
- package/skills/squish-memory/{install.mjs → scripts/install.mjs} +2 -2
- package/skills/squish-memory/{install.sh → scripts/install.sh} +2 -2
- package/skills/squish-memory/write_skill.js +2 -0
- package/.claude-plugin/marketplace.json +0 -20
- package/.claude-plugin/plugin.json +0 -32
- package/.env.mcp.example +0 -60
- package/QUICK-START.md +0 -71
- package/bin/squish-add.mjs +0 -32
- package/bin/squish-rm.mjs +0 -21
- package/commands/observe.md +0 -5
- package/dist/api/web/index.d.ts +0 -3
- package/dist/api/web/index.js +0 -4
- package/dist/api/web/web-server.d.ts +0 -3
- package/dist/api/web/web-server.js +0 -6
- package/dist/api/web/web.d.ts +0 -4
- package/dist/commands/mcp-server.js +0 -393
- package/dist/core/context.js +0 -24
- package/dist/core/governance.js +0 -64
- package/dist/core/observations.d.ts +0 -26
- package/dist/core/observations.js +0 -110
- package/dist/core/requirements.d.ts +0 -20
- package/dist/core/requirements.js +0 -35
- package/hooks/hooks.json +0 -52
- package/hooks/post-tool-use.js +0 -26
- package/hooks/session-end.js +0 -28
- package/hooks/session-start.js +0 -33
- package/hooks/user-prompt-submit.js +0 -26
- package/hooks/utils.js +0 -153
- package/npx-installer.js +0 -208
- package/packages/plugin-claude-code/README.md +0 -73
- package/packages/plugin-claude-code/dist/plugin-wrapper.d.ts +0 -35
- package/packages/plugin-claude-code/dist/plugin-wrapper.js +0 -191
- package/packages/plugin-claude-code/package.json +0 -31
- package/packages/plugin-openclaw/README.md +0 -70
- package/packages/plugin-openclaw/dist/index.d.ts +0 -49
- package/packages/plugin-openclaw/dist/index.js +0 -262
- package/packages/plugin-openclaw/openclaw.plugin.json +0 -94
- package/packages/plugin-openclaw/package.json +0 -31
- package/packages/plugin-opencode/install.mjs +0 -217
- package/packages/plugin-opencode/package.json +0 -21
- package/scripts/db/check-db.mjs +0 -88
- package/scripts/db/fix-all-columns.mjs +0 -52
- package/scripts/db/fix-schema-all.mjs +0 -55
- package/scripts/db/fix-schema-full.mjs +0 -46
- package/scripts/db/fix-schema.mjs +0 -38
- package/scripts/db/init-db.mjs +0 -13
- package/scripts/db/recreate-db.mjs +0 -14
- package/scripts/install-mcp.mjs +0 -116
- package/scripts/install-web.sh +0 -120
- package/scripts/install.mjs +0 -340
- package/scripts/openclaw-bootstrap.mjs +0 -127
- package/scripts/package-release.sh +0 -71
- package/scripts/test/test-all-systems.mjs +0 -139
- package/scripts/test/test-memory-system.mjs +0 -139
- package/scripts/test/test-v0.5.0.mjs +0 -210
- package/skills/memory-guide/SKILL.md +0 -332
- package/skills/squish-cli/SKILL.md +0 -240
- package/skills/squish-mcp/SKILL.md +0 -355
- package/skills/squish-memory/claude-desktop.json +0 -12
- package/skills/squish-memory/openclaw.json +0 -13
- package/skills/squish-memory/opencode.json +0 -14
- package/skills/squish-memory/skill.json +0 -32
- /package/{commands → core/commands}/context-paging.md +0 -0
- /package/{commands → core/commands}/context-status.md +0 -0
- /package/{commands → core/commands}/context.md +0 -0
- /package/{commands → core/commands}/core-memory.md +0 -0
- /package/{commands → core/commands}/health.md +0 -0
- /package/{commands → core/commands}/merge.md +0 -0
- /package/{commands → core/commands}/recall.md +0 -0
- /package/{commands → core/commands}/remember.md +0 -0
- /package/{commands → core/commands}/search.md +0 -0
- /package/dist/{algorithms → core/algorithms}/detection/hash-filters.d.ts +0 -0
- /package/dist/{algorithms → core/algorithms}/detection/hash-filters.js +0 -0
- /package/dist/{algorithms → core/algorithms}/handlers/approve-merge.d.ts +0 -0
- /package/dist/{algorithms → core/algorithms}/handlers/detect-duplicates.d.ts +0 -0
- /package/dist/{algorithms → core/algorithms}/handlers/get-stats.d.ts +0 -0
- /package/dist/{algorithms → core/algorithms}/handlers/list-proposals.d.ts +0 -0
- /package/dist/{algorithms → core/algorithms}/handlers/preview-merge.d.ts +0 -0
- /package/dist/{algorithms → core/algorithms}/handlers/reject-merge.d.ts +0 -0
- /package/dist/{algorithms → core/algorithms}/handlers/reverse-merge.d.ts +0 -0
- /package/dist/{algorithms → core/algorithms}/safety/safety-checks.js +0 -0
- /package/dist/{algorithms → core/algorithms}/utils/response-builder.d.ts +0 -0
- /package/dist/{algorithms → core/algorithms}/utils/response-builder.js +0 -0
- /package/dist/{commands → core/commands}/managed-sync.d.ts +0 -0
- /package/dist/{commands → core/commands}/mcp-server.d.ts +0 -0
- /package/dist/core/{context.d.ts → context/context.d.ts} +0 -0
- /package/dist/core/{agent-memory.d.ts → ingestion/agent-memory.d.ts} +0 -0
- /package/dist/core/{core-memory.d.ts → ingestion/core-memory.d.ts} +0 -0
- /package/dist/core/{privacy.d.ts → security/privacy.d.ts} +0 -0
- /package/dist/core/{privacy.js → security/privacy.js} +0 -0
- /package/dist/core/{secret-detector.d.ts → security/secret-detector.d.ts} +0 -0
- /package/dist/core/{secret-detector.js → security/secret-detector.js} +0 -0
- /package/dist/core/{cache.d.ts → storage/cache.d.ts} +0 -0
- /package/dist/core/{database.d.ts → storage/database.d.ts} +0 -0
- /package/dist/core/{database.js → storage/database.js} +0 -0
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Places Module - Spatial memory organization (Method of Loci)
|
|
3
|
+
*
|
|
4
|
+
* Provides spatial "places" for memory organization:
|
|
5
|
+
* - Entry Hall: Project overview, goals
|
|
6
|
+
* - Library: Research, patterns, discoveries
|
|
7
|
+
* - Workshop: Implementation, code, fixes
|
|
8
|
+
* - Lab: Experiments, tests, trials
|
|
9
|
+
* - Office: Decisions, planning, roadmap
|
|
10
|
+
* - Garden: Ideas, future concepts
|
|
11
|
+
* - Archive: Completed, historical
|
|
12
|
+
*/
|
|
13
|
+
import { randomUUID } from 'crypto';
|
|
14
|
+
import { eq, and, isNull } from 'drizzle-orm';
|
|
15
|
+
import { getDb } from '../../db/index.js';
|
|
16
|
+
import { getSchema } from '../../db/schema.js';
|
|
17
|
+
import { logger } from '../logger.js';
|
|
18
|
+
// Default places configuration
|
|
19
|
+
export const DEFAULT_PLACES = [
|
|
20
|
+
{ name: 'Entry Hall', placeType: 'entry_hall', lociIndex: 0, description: 'Project overview, goals, and current status', purpose: 'Quick orientation to project state' },
|
|
21
|
+
{ name: 'Library', placeType: 'library', lociIndex: 1, description: 'Research, patterns, and discoveries', purpose: 'Reference knowledge and learned patterns' },
|
|
22
|
+
{ name: 'Workshop', placeType: 'workshop', lociIndex: 2, description: 'Implementation, code, and fixes', purpose: 'Active development and recent changes' },
|
|
23
|
+
{ name: 'Lab', placeType: 'lab', lociIndex: 3, description: 'Experiments, tests, and trials', purpose: 'Testing and exploration results' },
|
|
24
|
+
{ name: 'Office', placeType: 'office', lociIndex: 4, description: 'Decisions, planning, and roadmap', purpose: 'Project direction and decisions' },
|
|
25
|
+
{ name: 'Garden', placeType: 'garden', lociIndex: 5, description: 'Ideas and future concepts', purpose: 'Brainstorming and upcoming plans' },
|
|
26
|
+
{ name: 'Archive', placeType: 'archive', lociIndex: 6, description: 'Completed and historical items', purpose: 'Reference for completed work' },
|
|
27
|
+
];
|
|
28
|
+
/**
|
|
29
|
+
* Create a new place
|
|
30
|
+
*/
|
|
31
|
+
export async function createPlace(input) {
|
|
32
|
+
const db = await getDb();
|
|
33
|
+
if (!db) {
|
|
34
|
+
throw new Error('Database unavailable');
|
|
35
|
+
}
|
|
36
|
+
const schema = await getSchema();
|
|
37
|
+
const sqliteDb = db;
|
|
38
|
+
const id = randomUUID();
|
|
39
|
+
// Check for duplicate
|
|
40
|
+
const existing = await sqliteDb.select()
|
|
41
|
+
.from(schema.places)
|
|
42
|
+
.where(and(eq(schema.places.projectId, input.projectId), eq(schema.places.name, input.name), input.parentId
|
|
43
|
+
? eq(schema.places.parentId, input.parentId)
|
|
44
|
+
: isNull(schema.places.parentId)))
|
|
45
|
+
.limit(1);
|
|
46
|
+
if (existing.length > 0) {
|
|
47
|
+
throw new Error(`Place "${input.name}" already exists`);
|
|
48
|
+
}
|
|
49
|
+
await sqliteDb.insert(schema.places).values({
|
|
50
|
+
id,
|
|
51
|
+
projectId: input.projectId,
|
|
52
|
+
name: input.name,
|
|
53
|
+
placeType: input.placeType,
|
|
54
|
+
parentId: input.parentId || null,
|
|
55
|
+
lociIndex: input.lociIndex ?? 0,
|
|
56
|
+
positionX: 0,
|
|
57
|
+
positionY: 0,
|
|
58
|
+
description: input.description || null,
|
|
59
|
+
purpose: input.purpose || null,
|
|
60
|
+
memoryCount: 0,
|
|
61
|
+
});
|
|
62
|
+
logger.info(`[Places] Created place: ${input.name} (${input.placeType})`);
|
|
63
|
+
return {
|
|
64
|
+
id,
|
|
65
|
+
projectId: input.projectId,
|
|
66
|
+
name: input.name,
|
|
67
|
+
placeType: input.placeType,
|
|
68
|
+
parentId: input.parentId || null,
|
|
69
|
+
lociIndex: input.lociIndex ?? 0,
|
|
70
|
+
positionX: 0,
|
|
71
|
+
positionY: 0,
|
|
72
|
+
description: input.description || null,
|
|
73
|
+
purpose: input.purpose || null,
|
|
74
|
+
memoryCount: 0,
|
|
75
|
+
createdAt: new Date(),
|
|
76
|
+
updatedAt: new Date(),
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Get a place by ID
|
|
81
|
+
*/
|
|
82
|
+
export async function getPlace(id) {
|
|
83
|
+
const db = await getDb();
|
|
84
|
+
if (!db)
|
|
85
|
+
return null;
|
|
86
|
+
const schema = await getSchema();
|
|
87
|
+
const sqliteDb = db;
|
|
88
|
+
const result = await sqliteDb.select()
|
|
89
|
+
.from(schema.places)
|
|
90
|
+
.where(eq(schema.places.id, id))
|
|
91
|
+
.limit(1);
|
|
92
|
+
if (result.length === 0)
|
|
93
|
+
return null;
|
|
94
|
+
const row = result[0];
|
|
95
|
+
return {
|
|
96
|
+
id: row.id,
|
|
97
|
+
projectId: row.project_id,
|
|
98
|
+
name: row.name,
|
|
99
|
+
placeType: (row.place_type || row.placeType || 'custom'),
|
|
100
|
+
parentId: row.parent_id || row.parentId || null,
|
|
101
|
+
lociIndex: row.loci_index ?? row.lociIndex ?? 0,
|
|
102
|
+
positionX: row.position_x ?? row.positionX ?? 0,
|
|
103
|
+
positionY: row.position_y ?? row.positionY ?? 0,
|
|
104
|
+
description: row.description,
|
|
105
|
+
purpose: row.purpose,
|
|
106
|
+
memoryCount: row.memory_count ?? row.memoryCount ?? 0,
|
|
107
|
+
createdAt: new Date(row.created_at || row.createdAt || Date.now()),
|
|
108
|
+
updatedAt: new Date(row.updated_at || row.updatedAt || Date.now()),
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Get places for a project, ordered by loci_index
|
|
113
|
+
*/
|
|
114
|
+
export async function getProjectPlaces(projectId) {
|
|
115
|
+
const db = await getDb();
|
|
116
|
+
if (!db)
|
|
117
|
+
return [];
|
|
118
|
+
const schema = await getSchema();
|
|
119
|
+
const sqliteDb = db;
|
|
120
|
+
const results = await sqliteDb.select()
|
|
121
|
+
.from(schema.places)
|
|
122
|
+
.where(eq(schema.places.projectId, projectId))
|
|
123
|
+
.orderBy(schema.places.lociIndex);
|
|
124
|
+
return results.map((row) => ({
|
|
125
|
+
id: row.id,
|
|
126
|
+
projectId: row.project_id,
|
|
127
|
+
name: row.name,
|
|
128
|
+
placeType: (row.place_type || row.placeType),
|
|
129
|
+
parentId: row.parent_id || row.parentId,
|
|
130
|
+
lociIndex: row.loci_index ?? row.lociIndex ?? 0,
|
|
131
|
+
positionX: row.position_x ?? row.positionX ?? 0,
|
|
132
|
+
positionY: row.position_y ?? row.positionY ?? 0,
|
|
133
|
+
description: row.description,
|
|
134
|
+
purpose: row.purpose,
|
|
135
|
+
memoryCount: row.memory_count ?? row.memoryCount ?? 0,
|
|
136
|
+
createdAt: new Date(row.created_at || row.createdAt),
|
|
137
|
+
updatedAt: new Date(row.updated_at || row.updatedAt),
|
|
138
|
+
}));
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Get place by type for a project
|
|
142
|
+
*/
|
|
143
|
+
export async function getPlaceByType(projectId, placeType) {
|
|
144
|
+
const db = await getDb();
|
|
145
|
+
if (!db)
|
|
146
|
+
return null;
|
|
147
|
+
const schema = await getSchema();
|
|
148
|
+
const sqliteDb = db;
|
|
149
|
+
const result = await sqliteDb.select()
|
|
150
|
+
.from(schema.places)
|
|
151
|
+
.where(and(eq(schema.places.projectId, projectId), eq(schema.places.placeType, placeType)))
|
|
152
|
+
.limit(1);
|
|
153
|
+
if (result.length === 0)
|
|
154
|
+
return null;
|
|
155
|
+
const row = result[0];
|
|
156
|
+
return {
|
|
157
|
+
id: row.id,
|
|
158
|
+
projectId: row.project_id,
|
|
159
|
+
name: row.name,
|
|
160
|
+
placeType: (row.place_type || row.placeType || 'custom'),
|
|
161
|
+
parentId: row.parent_id || row.parentId || null,
|
|
162
|
+
lociIndex: row.loci_index ?? row.lociIndex ?? 0,
|
|
163
|
+
positionX: row.position_x ?? row.positionX ?? 0,
|
|
164
|
+
positionY: row.position_y ?? row.positionY ?? 0,
|
|
165
|
+
description: row.description,
|
|
166
|
+
purpose: row.purpose,
|
|
167
|
+
memoryCount: row.memory_count ?? row.memoryCount ?? 0,
|
|
168
|
+
createdAt: new Date(row.created_at || row.createdAt || Date.now()),
|
|
169
|
+
updatedAt: new Date(row.updated_at || row.updatedAt || Date.now()),
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Update a place
|
|
174
|
+
*/
|
|
175
|
+
export async function updatePlace(id, input) {
|
|
176
|
+
const db = await getDb();
|
|
177
|
+
if (!db)
|
|
178
|
+
return null;
|
|
179
|
+
const schema = await getSchema();
|
|
180
|
+
const sqliteDb = db;
|
|
181
|
+
const updateData = {};
|
|
182
|
+
if (input.name !== undefined)
|
|
183
|
+
updateData.name = input.name;
|
|
184
|
+
if (input.description !== undefined)
|
|
185
|
+
updateData.description = input.description;
|
|
186
|
+
if (input.purpose !== undefined)
|
|
187
|
+
updateData.purpose = input.purpose;
|
|
188
|
+
if (input.lociIndex !== undefined)
|
|
189
|
+
updateData.lociIndex = input.lociIndex;
|
|
190
|
+
if (input.positionX !== undefined)
|
|
191
|
+
updateData.positionX = input.positionX;
|
|
192
|
+
if (input.positionY !== undefined)
|
|
193
|
+
updateData.positionY = input.positionY;
|
|
194
|
+
if (Object.keys(updateData).length === 0) {
|
|
195
|
+
return getPlace(id);
|
|
196
|
+
}
|
|
197
|
+
await sqliteDb.update(schema.places)
|
|
198
|
+
.set(updateData)
|
|
199
|
+
.where(eq(schema.places.id, id));
|
|
200
|
+
return getPlace(id);
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Delete a place
|
|
204
|
+
*/
|
|
205
|
+
export async function deletePlace(id) {
|
|
206
|
+
const db = await getDb();
|
|
207
|
+
if (!db)
|
|
208
|
+
return false;
|
|
209
|
+
const schema = await getSchema();
|
|
210
|
+
const sqliteDb = db;
|
|
211
|
+
await sqliteDb.delete(schema.places).where(eq(schema.places.id, id));
|
|
212
|
+
logger.info(`[Places] Deleted place: ${id}`);
|
|
213
|
+
return true;
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Initialize default 7 places for a project
|
|
217
|
+
*/
|
|
218
|
+
export async function initializeDefaultPlaces(projectId) {
|
|
219
|
+
const created = [];
|
|
220
|
+
for (const placeConfig of DEFAULT_PLACES) {
|
|
221
|
+
// Check if place of this type already exists
|
|
222
|
+
const existing = await getPlaceByType(projectId, placeConfig.placeType);
|
|
223
|
+
if (existing) {
|
|
224
|
+
created.push(existing);
|
|
225
|
+
continue;
|
|
226
|
+
}
|
|
227
|
+
const place = await createPlace({
|
|
228
|
+
projectId,
|
|
229
|
+
name: placeConfig.name,
|
|
230
|
+
placeType: placeConfig.placeType,
|
|
231
|
+
parentId: null,
|
|
232
|
+
lociIndex: placeConfig.lociIndex,
|
|
233
|
+
description: placeConfig.description,
|
|
234
|
+
purpose: placeConfig.purpose,
|
|
235
|
+
});
|
|
236
|
+
created.push(place);
|
|
237
|
+
}
|
|
238
|
+
// Also initialize default rules if none exist
|
|
239
|
+
const { initializeDefaultRules } = await import('./rules.js');
|
|
240
|
+
await initializeDefaultRules(projectId);
|
|
241
|
+
logger.info(`[Places] Initialized ${created.length} default places for project: ${projectId}`);
|
|
242
|
+
return created;
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Get place by loci index
|
|
246
|
+
*/
|
|
247
|
+
export async function getPlaceByLociIndex(projectId, lociIndex) {
|
|
248
|
+
const db = await getDb();
|
|
249
|
+
if (!db)
|
|
250
|
+
return null;
|
|
251
|
+
const schema = await getSchema();
|
|
252
|
+
const sqliteDb = db;
|
|
253
|
+
const result = await sqliteDb.select()
|
|
254
|
+
.from(schema.places)
|
|
255
|
+
.where(and(eq(schema.places.projectId, projectId), eq(schema.places.lociIndex, lociIndex)))
|
|
256
|
+
.limit(1);
|
|
257
|
+
if (result.length === 0)
|
|
258
|
+
return null;
|
|
259
|
+
const row = result[0];
|
|
260
|
+
return {
|
|
261
|
+
id: row.id,
|
|
262
|
+
projectId: row.project_id,
|
|
263
|
+
name: row.name,
|
|
264
|
+
placeType: (row.place_type || row.placeType || 'custom'),
|
|
265
|
+
parentId: row.parent_id || row.parentId || null,
|
|
266
|
+
lociIndex: row.loci_index ?? row.lociIndex ?? 0,
|
|
267
|
+
positionX: row.position_x ?? row.positionX ?? 0,
|
|
268
|
+
positionY: row.position_y ?? row.positionY ?? 0,
|
|
269
|
+
description: row.description,
|
|
270
|
+
purpose: row.purpose,
|
|
271
|
+
memoryCount: row.memory_count ?? row.memoryCount ?? 0,
|
|
272
|
+
createdAt: new Date(row.created_at || row.createdAt || Date.now()),
|
|
273
|
+
updatedAt: new Date(row.updated_at || row.updatedAt || Date.now()),
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* Update memory count for a place
|
|
278
|
+
*/
|
|
279
|
+
export async function updatePlaceMemoryCount(placeId) {
|
|
280
|
+
const db = await getDb();
|
|
281
|
+
if (!db)
|
|
282
|
+
return;
|
|
283
|
+
const schema = await getSchema();
|
|
284
|
+
const sqliteDb = db;
|
|
285
|
+
// Count memories in this place
|
|
286
|
+
const countResult = await sqliteDb.select({ count: schema.memoryPlaces.id })
|
|
287
|
+
.from(schema.memoryPlaces)
|
|
288
|
+
.where(eq(schema.memoryPlaces.placeId, placeId));
|
|
289
|
+
const count = countResult.length;
|
|
290
|
+
await sqliteDb.update(schema.places)
|
|
291
|
+
.set({ memoryCount: count })
|
|
292
|
+
.where(eq(schema.places.id, placeId));
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* Sync all place memory counts - recalculate counts for all places in a project
|
|
296
|
+
* Useful for fixing counts after bulk operations or data recovery
|
|
297
|
+
*/
|
|
298
|
+
export async function syncAllPlaceMemoryCounts(projectId) {
|
|
299
|
+
const db = await getDb();
|
|
300
|
+
if (!db)
|
|
301
|
+
return;
|
|
302
|
+
const schema = await getSchema();
|
|
303
|
+
const sqliteDb = db;
|
|
304
|
+
// Get all places for this project
|
|
305
|
+
const allPlaces = await sqliteDb.select()
|
|
306
|
+
.from(schema.places)
|
|
307
|
+
.where(eq(schema.places.projectId, projectId));
|
|
308
|
+
// Update each place's memory count
|
|
309
|
+
for (const place of allPlaces) {
|
|
310
|
+
await updatePlaceMemoryCount(place.id);
|
|
311
|
+
}
|
|
312
|
+
logger.info(`[Places] Synced memory counts for ${allPlaces.length} places`);
|
|
313
|
+
}
|
|
314
|
+
//# sourceMappingURL=places.js.map
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Places Rules Engine - Auto-assignment logic
|
|
3
|
+
*
|
|
4
|
+
* Evaluates which place a memory should be assigned to based on:
|
|
5
|
+
* - Tool used (Write, Edit, Task, etc.)
|
|
6
|
+
* - Content keywords
|
|
7
|
+
* - Tags
|
|
8
|
+
* - Memory type
|
|
9
|
+
*/
|
|
10
|
+
import type { PlaceType } from './places.js';
|
|
11
|
+
export interface PlaceRule {
|
|
12
|
+
id: string;
|
|
13
|
+
projectId: string;
|
|
14
|
+
name: string;
|
|
15
|
+
placeType: PlaceType;
|
|
16
|
+
matchTool: string | null;
|
|
17
|
+
matchKeyword: string | null;
|
|
18
|
+
matchTag: string | null;
|
|
19
|
+
matchMemoryType: string | null;
|
|
20
|
+
priority: number;
|
|
21
|
+
enabled: boolean;
|
|
22
|
+
createdAt: Date;
|
|
23
|
+
updatedAt: Date;
|
|
24
|
+
}
|
|
25
|
+
export interface PlaceRuleCreateInput {
|
|
26
|
+
projectId: string;
|
|
27
|
+
name: string;
|
|
28
|
+
placeType: PlaceType;
|
|
29
|
+
matchTool?: string;
|
|
30
|
+
matchKeyword?: string;
|
|
31
|
+
matchTag?: string;
|
|
32
|
+
matchMemoryType?: string;
|
|
33
|
+
priority?: number;
|
|
34
|
+
enabled?: boolean;
|
|
35
|
+
}
|
|
36
|
+
export interface RuleMatchInput {
|
|
37
|
+
toolName?: string;
|
|
38
|
+
content?: string;
|
|
39
|
+
tags?: string[];
|
|
40
|
+
memoryType?: string;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Default auto-assignment rules
|
|
44
|
+
*/
|
|
45
|
+
export declare const DEFAULT_RULES: Omit<PlaceRuleCreateInput, 'projectId'>[];
|
|
46
|
+
/**
|
|
47
|
+
* Create a place rule
|
|
48
|
+
*/
|
|
49
|
+
export declare function createPlaceRule(input: PlaceRuleCreateInput): Promise<PlaceRule>;
|
|
50
|
+
/**
|
|
51
|
+
* Get rules for a project
|
|
52
|
+
*/
|
|
53
|
+
export declare function getProjectRules(projectId: string): Promise<PlaceRule[]>;
|
|
54
|
+
/**
|
|
55
|
+
* Check if a rule matches the input
|
|
56
|
+
*/
|
|
57
|
+
export declare function matchesRule(rule: PlaceRule, input: RuleMatchInput): boolean;
|
|
58
|
+
/**
|
|
59
|
+
* Find matching place for a memory based on rules
|
|
60
|
+
*/
|
|
61
|
+
export declare function findMatchingPlace(projectId: string, input: RuleMatchInput): Promise<PlaceType | null>;
|
|
62
|
+
/**
|
|
63
|
+
* Initialize default rules for a project
|
|
64
|
+
*/
|
|
65
|
+
export declare function initializeDefaultRules(projectId: string): Promise<PlaceRule[]>;
|
|
66
|
+
/**
|
|
67
|
+
* Delete a rule
|
|
68
|
+
*/
|
|
69
|
+
export declare function deletePlaceRule(id: string): Promise<boolean>;
|
|
70
|
+
/**
|
|
71
|
+
* Update a rule
|
|
72
|
+
*/
|
|
73
|
+
export declare function updatePlaceRule(id: string, updates: Partial<PlaceRuleCreateInput>): Promise<PlaceRule | null>;
|
|
74
|
+
//# sourceMappingURL=rules.d.ts.map
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Places Rules Engine - Auto-assignment logic
|
|
3
|
+
*
|
|
4
|
+
* Evaluates which place a memory should be assigned to based on:
|
|
5
|
+
* - Tool used (Write, Edit, Task, etc.)
|
|
6
|
+
* - Content keywords
|
|
7
|
+
* - Tags
|
|
8
|
+
* - Memory type
|
|
9
|
+
*/
|
|
10
|
+
import { randomUUID } from 'crypto';
|
|
11
|
+
import { eq, desc } from 'drizzle-orm';
|
|
12
|
+
import { getDb } from '../../db/index.js';
|
|
13
|
+
import { getSchema } from '../../db/schema.js';
|
|
14
|
+
import { logger } from '../logger.js';
|
|
15
|
+
/**
|
|
16
|
+
* Default auto-assignment rules
|
|
17
|
+
*/
|
|
18
|
+
export const DEFAULT_RULES = [
|
|
19
|
+
// Workshop - Implementation, code, fixes
|
|
20
|
+
{ name: 'Write to Workshop', placeType: 'workshop', matchTool: 'Write', priority: 100 },
|
|
21
|
+
{ name: 'Edit to Workshop', placeType: 'workshop', matchTool: 'Edit', priority: 100 },
|
|
22
|
+
{ name: 'MultiEdit to Workshop', placeType: 'workshop', matchTool: 'MultiEdit', priority: 100 },
|
|
23
|
+
{ name: 'Fix keyword to Workshop', placeType: 'workshop', matchKeyword: 'fix', priority: 80 },
|
|
24
|
+
{ name: 'Bug keyword to Workshop', placeType: 'workshop', matchKeyword: 'bug', priority: 80 },
|
|
25
|
+
// Lab - Experiments, tests
|
|
26
|
+
{ name: 'Test to Lab', placeType: 'lab', matchTool: 'Bash', matchKeyword: 'test', priority: 90 },
|
|
27
|
+
{ name: 'Test tag to Lab', placeType: 'lab', matchTag: 'test', priority: 85 },
|
|
28
|
+
// Office - Decisions, planning
|
|
29
|
+
{ name: 'Task to Office', placeType: 'office', matchTool: 'Task', priority: 100 },
|
|
30
|
+
{ name: 'TodoWrite to Office', placeType: 'office', matchTool: 'TodoWrite', priority: 100 },
|
|
31
|
+
{ name: 'Decision keyword to Office', placeType: 'office', matchKeyword: 'decided', priority: 70 },
|
|
32
|
+
{ name: 'Planning keyword to Office', placeType: 'office', matchKeyword: 'will implement', priority: 70 },
|
|
33
|
+
// Library - Research, patterns
|
|
34
|
+
{ name: 'Search to Library', placeType: 'library', matchTool: 'grep', priority: 90 },
|
|
35
|
+
{ name: 'WebFetch to Library', placeType: 'library', matchTool: 'WebFetch', priority: 85 },
|
|
36
|
+
{ name: 'Research keyword to Library', placeType: 'library', matchKeyword: 'research', priority: 80 },
|
|
37
|
+
{ name: 'Pattern keyword to Library', placeType: 'library', matchKeyword: 'pattern', priority: 75 },
|
|
38
|
+
// Garden - Ideas, future
|
|
39
|
+
{ name: 'Idea keyword to Garden', placeType: 'garden', matchKeyword: 'idea', priority: 80 },
|
|
40
|
+
{ name: 'Explore keyword to Garden', placeType: 'garden', matchKeyword: 'explore', priority: 75 },
|
|
41
|
+
{ name: 'Future keyword to Garden', placeType: 'garden', matchKeyword: 'will add', priority: 70 },
|
|
42
|
+
];
|
|
43
|
+
/**
|
|
44
|
+
* Create a place rule
|
|
45
|
+
*/
|
|
46
|
+
export async function createPlaceRule(input) {
|
|
47
|
+
const db = await getDb();
|
|
48
|
+
if (!db) {
|
|
49
|
+
throw new Error('Database unavailable');
|
|
50
|
+
}
|
|
51
|
+
const schema = await getSchema();
|
|
52
|
+
const sqliteDb = db;
|
|
53
|
+
const id = randomUUID();
|
|
54
|
+
await sqliteDb.insert(schema.placeRules).values({
|
|
55
|
+
id,
|
|
56
|
+
projectId: input.projectId,
|
|
57
|
+
name: input.name,
|
|
58
|
+
placeType: input.placeType,
|
|
59
|
+
matchTool: input.matchTool || null,
|
|
60
|
+
matchKeyword: input.matchKeyword || null,
|
|
61
|
+
matchTag: input.matchTag || null,
|
|
62
|
+
matchMemoryType: input.matchMemoryType || null,
|
|
63
|
+
priority: input.priority ?? 0,
|
|
64
|
+
enabled: input.enabled !== false ? 1 : 0,
|
|
65
|
+
});
|
|
66
|
+
logger.info(`[PlaceRules] Created rule: ${input.name} -> ${input.placeType}`);
|
|
67
|
+
return {
|
|
68
|
+
id,
|
|
69
|
+
projectId: input.projectId,
|
|
70
|
+
name: input.name,
|
|
71
|
+
placeType: input.placeType,
|
|
72
|
+
matchTool: input.matchTool || null,
|
|
73
|
+
matchKeyword: input.matchKeyword || null,
|
|
74
|
+
matchTag: input.matchTag || null,
|
|
75
|
+
matchMemoryType: input.matchMemoryType || null,
|
|
76
|
+
priority: input.priority ?? 0,
|
|
77
|
+
enabled: input.enabled ?? true,
|
|
78
|
+
createdAt: new Date(),
|
|
79
|
+
updatedAt: new Date(),
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Get rules for a project
|
|
84
|
+
*/
|
|
85
|
+
export async function getProjectRules(projectId) {
|
|
86
|
+
const db = await getDb();
|
|
87
|
+
if (!db)
|
|
88
|
+
return [];
|
|
89
|
+
const schema = await getSchema();
|
|
90
|
+
const sqliteDb = db;
|
|
91
|
+
const results = await sqliteDb.select()
|
|
92
|
+
.from(schema.placeRules)
|
|
93
|
+
.where(eq(schema.placeRules.projectId, projectId))
|
|
94
|
+
.orderBy(desc(schema.placeRules.priority));
|
|
95
|
+
return results.map((row) => ({
|
|
96
|
+
id: row.id,
|
|
97
|
+
projectId: row.project_id,
|
|
98
|
+
name: row.name,
|
|
99
|
+
placeType: (row.place_type || row.placeType || 'custom'),
|
|
100
|
+
matchTool: row.match_tool || row.matchTool,
|
|
101
|
+
matchKeyword: row.match_keyword || row.matchKeyword,
|
|
102
|
+
matchTag: row.match_tag || row.matchTag,
|
|
103
|
+
matchMemoryType: row.match_memory_type || row.matchMemoryType,
|
|
104
|
+
priority: row.priority ?? 0,
|
|
105
|
+
enabled: row.enabled === 1 || row.enabled === true,
|
|
106
|
+
createdAt: new Date(row.created_at || Date.now()),
|
|
107
|
+
updatedAt: new Date(row.updated_at || Date.now()),
|
|
108
|
+
}));
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Check if a rule matches the input
|
|
112
|
+
*/
|
|
113
|
+
export function matchesRule(rule, input) {
|
|
114
|
+
// Check tool match
|
|
115
|
+
if (rule.matchTool && input.toolName) {
|
|
116
|
+
if (input.toolName.toLowerCase() !== rule.matchTool.toLowerCase()) {
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
// Check keyword match
|
|
121
|
+
if (rule.matchKeyword && input.content) {
|
|
122
|
+
const contentLower = input.content.toLowerCase();
|
|
123
|
+
if (!contentLower.includes(rule.matchKeyword.toLowerCase())) {
|
|
124
|
+
return false;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
// Check tag match
|
|
128
|
+
if (rule.matchTag && input.tags) {
|
|
129
|
+
const hasTag = input.tags.some(t => t.toLowerCase() === rule.matchTag.toLowerCase());
|
|
130
|
+
if (!hasTag) {
|
|
131
|
+
return false;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
// Check memory type match
|
|
135
|
+
if (rule.matchMemoryType && input.memoryType) {
|
|
136
|
+
if (input.memoryType.toLowerCase() !== rule.matchMemoryType.toLowerCase()) {
|
|
137
|
+
return false;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return true;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Find matching place for a memory based on rules
|
|
144
|
+
*/
|
|
145
|
+
export async function findMatchingPlace(projectId, input) {
|
|
146
|
+
const rules = await getProjectRules(projectId);
|
|
147
|
+
// Sort by priority (highest first)
|
|
148
|
+
const sortedRules = rules
|
|
149
|
+
.filter(r => r.enabled)
|
|
150
|
+
.sort((a, b) => b.priority - a.priority);
|
|
151
|
+
for (const rule of sortedRules) {
|
|
152
|
+
if (matchesRule(rule, input)) {
|
|
153
|
+
logger.info(`[PlaceRules] Matched rule "${rule.name}" -> ${rule.placeType}`);
|
|
154
|
+
return rule.placeType;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
return null;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Initialize default rules for a project
|
|
161
|
+
*/
|
|
162
|
+
export async function initializeDefaultRules(projectId) {
|
|
163
|
+
const created = [];
|
|
164
|
+
for (const ruleConfig of DEFAULT_RULES) {
|
|
165
|
+
const rule = await createPlaceRule({
|
|
166
|
+
projectId,
|
|
167
|
+
...ruleConfig,
|
|
168
|
+
});
|
|
169
|
+
created.push(rule);
|
|
170
|
+
}
|
|
171
|
+
logger.info(`[PlaceRules] Initialized ${created.length} default rules for project: ${projectId}`);
|
|
172
|
+
return created;
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Delete a rule
|
|
176
|
+
*/
|
|
177
|
+
export async function deletePlaceRule(id) {
|
|
178
|
+
const db = await getDb();
|
|
179
|
+
if (!db)
|
|
180
|
+
return false;
|
|
181
|
+
const schema = await getSchema();
|
|
182
|
+
const sqliteDb = db;
|
|
183
|
+
await sqliteDb.delete(schema.placeRules).where(eq(schema.placeRules.id, id));
|
|
184
|
+
logger.info(`[PlaceRules] Deleted rule: ${id}`);
|
|
185
|
+
return true;
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Update a rule
|
|
189
|
+
*/
|
|
190
|
+
export async function updatePlaceRule(id, updates) {
|
|
191
|
+
const db = await getDb();
|
|
192
|
+
if (!db)
|
|
193
|
+
return null;
|
|
194
|
+
const schema = await getSchema();
|
|
195
|
+
const sqliteDb = db;
|
|
196
|
+
const updateData = {};
|
|
197
|
+
if (updates.name !== undefined)
|
|
198
|
+
updateData.name = updates.name;
|
|
199
|
+
if (updates.placeType !== undefined)
|
|
200
|
+
updateData.placeType = updates.placeType;
|
|
201
|
+
if (updates.matchTool !== undefined)
|
|
202
|
+
updateData.matchTool = updates.matchTool;
|
|
203
|
+
if (updates.matchKeyword !== undefined)
|
|
204
|
+
updateData.matchKeyword = updates.matchKeyword;
|
|
205
|
+
if (updates.matchTag !== undefined)
|
|
206
|
+
updateData.matchTag = updates.matchTag;
|
|
207
|
+
if (updates.matchMemoryType !== undefined)
|
|
208
|
+
updateData.matchMemoryType = updates.matchMemoryType;
|
|
209
|
+
if (updates.priority !== undefined)
|
|
210
|
+
updateData.priority = updates.priority;
|
|
211
|
+
if (updates.enabled !== undefined)
|
|
212
|
+
updateData.enabled = updates.enabled;
|
|
213
|
+
if (Object.keys(updateData).length === 0)
|
|
214
|
+
return null;
|
|
215
|
+
await sqliteDb.update(schema.placeRules)
|
|
216
|
+
.set(updateData)
|
|
217
|
+
.where(eq(schema.placeRules.id, id));
|
|
218
|
+
const result = await sqliteDb.select()
|
|
219
|
+
.from(schema.placeRules)
|
|
220
|
+
.where(eq(schema.placeRules.id, id))
|
|
221
|
+
.limit(1);
|
|
222
|
+
if (result.length === 0)
|
|
223
|
+
return null;
|
|
224
|
+
const row = result[0];
|
|
225
|
+
return {
|
|
226
|
+
id: row.id,
|
|
227
|
+
projectId: row.project_id,
|
|
228
|
+
name: row.name,
|
|
229
|
+
placeType: row.place_type,
|
|
230
|
+
matchTool: row.match_tool,
|
|
231
|
+
matchKeyword: row.match_keyword,
|
|
232
|
+
matchTag: row.match_tag,
|
|
233
|
+
matchMemoryType: row.match_memory_type,
|
|
234
|
+
priority: row.priority,
|
|
235
|
+
enabled: row.enabled === 1 || row.enabled === true,
|
|
236
|
+
createdAt: new Date(row.created_at),
|
|
237
|
+
updatedAt: new Date(row.updated_at),
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
//# sourceMappingURL=rules.js.map
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Walking Interface - Sequential memory retrieval through places
|
|
3
|
+
*
|
|
4
|
+
* Implements Method of Loci walking through memory places:
|
|
5
|
+
* - Walk single place to get memories in order
|
|
6
|
+
* - Walk all places for full tour
|
|
7
|
+
* - Token budget handling with TOON compression
|
|
8
|
+
*/
|
|
9
|
+
import { type Place } from './places.js';
|
|
10
|
+
export interface WalkOptions {
|
|
11
|
+
tokenBudget?: number;
|
|
12
|
+
maxMemoriesPerPlace?: number;
|
|
13
|
+
includePurpose?: boolean;
|
|
14
|
+
compressWithToon?: boolean;
|
|
15
|
+
}
|
|
16
|
+
export interface WalkResult {
|
|
17
|
+
place: Place;
|
|
18
|
+
memories: MemorySummary[];
|
|
19
|
+
totalTokens: number;
|
|
20
|
+
truncated: boolean;
|
|
21
|
+
}
|
|
22
|
+
export interface MemorySummary {
|
|
23
|
+
id: string;
|
|
24
|
+
content: string;
|
|
25
|
+
type: string;
|
|
26
|
+
tags: string[];
|
|
27
|
+
createdAt: string;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Walk through a single place
|
|
31
|
+
*/
|
|
32
|
+
export declare function walkPlace(projectId: string, placeType: string, options?: WalkOptions): Promise<WalkResult | null>;
|
|
33
|
+
/**
|
|
34
|
+
* Walk through all places in loci order
|
|
35
|
+
*/
|
|
36
|
+
export declare function walkAllPlaces(projectId: string, options?: WalkOptions): Promise<WalkResult[]>;
|
|
37
|
+
/**
|
|
38
|
+
* Quick tour - just place names and purposes (minimal tokens)
|
|
39
|
+
*/
|
|
40
|
+
export declare function quickTour(projectId: string): Promise<{
|
|
41
|
+
places: {
|
|
42
|
+
name: string;
|
|
43
|
+
purpose: string;
|
|
44
|
+
memoryCount: number;
|
|
45
|
+
}[];
|
|
46
|
+
totalMemories: number;
|
|
47
|
+
}>;
|
|
48
|
+
/**
|
|
49
|
+
* Get context summary for a place (for injection)
|
|
50
|
+
*/
|
|
51
|
+
export declare function getPlaceContext(projectId: string, placeType: string, maxTokens?: number): Promise<string>;
|
|
52
|
+
/**
|
|
53
|
+
* Full context for session start (all places)
|
|
54
|
+
*/
|
|
55
|
+
export declare function getFullWalkingContext(projectId: string, maxTokens?: number): Promise<string>;
|
|
56
|
+
//# sourceMappingURL=walking.d.ts.map
|