@stackmemoryai/stackmemory 0.5.67 → 0.6.1
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/README.md +136 -42
- package/dist/src/cli/commands/daemon.js +27 -0
- package/dist/src/cli/commands/daemon.js.map +2 -2
- package/dist/src/core/context/frame-database.js +12 -3
- package/dist/src/core/context/frame-database.js.map +2 -2
- package/dist/src/core/database/embedding-provider.js +17 -0
- package/dist/src/core/database/embedding-provider.js.map +7 -0
- package/dist/src/core/database/sqlite-adapter.js +257 -11
- package/dist/src/core/database/sqlite-adapter.js.map +2 -2
- package/dist/src/daemon/daemon-config.js +17 -0
- package/dist/src/daemon/daemon-config.js.map +2 -2
- package/dist/src/daemon/services/maintenance-service.js +230 -0
- package/dist/src/daemon/services/maintenance-service.js.map +7 -0
- package/dist/src/daemon/unified-daemon.js +36 -3
- package/dist/src/daemon/unified-daemon.js.map +2 -2
- package/package.json +11 -6
- package/scripts/install-claude-hooks-auto.js +33 -19
- package/templates/claude-hooks/hooks.json +4 -2
- package/templates/claude-hooks/on-task-complete.js +90 -0
- package/templates/claude-hooks/skill-eval.cjs +411 -0
- package/templates/claude-hooks/skill-eval.sh +31 -0
- package/templates/claude-hooks/skill-rules.json +274 -0
package/README.md
CHANGED
|
@@ -14,7 +14,9 @@ StackMemory is a **production-ready memory runtime** for AI coding tools that pr
|
|
|
14
14
|
- **Full Linear integration** with bidirectional sync
|
|
15
15
|
- **Context persistence** that survives /clear operations
|
|
16
16
|
- **Hierarchical frame organization** (nested call stack model)
|
|
17
|
-
- **
|
|
17
|
+
- **Skills system** with `/spec` and `/linear-run` for Claude Code
|
|
18
|
+
- **Automatic hooks** for task tracking, Linear sync, and spec progress
|
|
19
|
+
- **498 tests passing** with comprehensive coverage
|
|
18
20
|
|
|
19
21
|
Instead of a linear chat log, StackMemory organizes memory as a **call stack** of scoped work (frames), with intelligent LLM-driven retrieval and team collaboration features.
|
|
20
22
|
|
|
@@ -34,13 +36,13 @@ Tools forget decisions and constraints between sessions. StackMemory makes conte
|
|
|
34
36
|
|
|
35
37
|
## Features (at a glance)
|
|
36
38
|
|
|
37
|
-
- MCP tools for Claude Code: 26+ tools; context on every request
|
|
38
|
-
-
|
|
39
|
-
-
|
|
40
|
-
-
|
|
41
|
-
-
|
|
42
|
-
|
|
43
|
-
|
|
39
|
+
- **MCP tools** for Claude Code: 26+ tools; context on every request
|
|
40
|
+
- **Skills**: `/spec` (iterative spec generation), `/linear-run` (task execution via RLM)
|
|
41
|
+
- **Hooks**: automatic context save, task tracking, Linear sync, PROMPT_PLAN updates
|
|
42
|
+
- **Prompt Forge**: watches AGENTS.md and CLAUDE.md for prompt optimization (GEPA)
|
|
43
|
+
- **Safe branches**: worktree isolation with `--worktree` or `-w`
|
|
44
|
+
- **Persistent context**: frames, anchors, decisions, retrieval
|
|
45
|
+
- **Integrations**: Linear, Greptile, DiffMem, Browser MCP
|
|
44
46
|
|
|
45
47
|
---
|
|
46
48
|
|
|
@@ -131,13 +133,127 @@ Env defaults (optional):
|
|
|
131
133
|
|
|
132
134
|
---
|
|
133
135
|
|
|
134
|
-
##
|
|
136
|
+
## Skills System
|
|
137
|
+
|
|
138
|
+
StackMemory ships Claude Code skills that integrate directly into your workflow. Skills are invoked via `/skill-name` in Claude Code or `stackmemory skills <name>` from the CLI.
|
|
139
|
+
|
|
140
|
+
### Spec Generator (`/spec`)
|
|
141
|
+
|
|
142
|
+
Generates iterative spec documents following a 4-doc progressive chain. Each document reads previous ones from disk for context.
|
|
143
|
+
|
|
144
|
+
```
|
|
145
|
+
ONE_PAGER.md → DEV_SPEC.md → PROMPT_PLAN.md → AGENTS.md
|
|
146
|
+
(standalone) (reads 1) (reads 1+2) (reads 1+2+3)
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
# Generate specs in order
|
|
151
|
+
/spec one-pager "My App" # Problem, audience, core flow, MVP
|
|
152
|
+
/spec dev-spec # Architecture, tech stack, APIs
|
|
153
|
+
/spec prompt-plan # TDD stages A-G with checkboxes
|
|
154
|
+
/spec agents # Agent guardrails and responsibilities
|
|
155
|
+
|
|
156
|
+
# Manage progress
|
|
157
|
+
/spec list # Show existing specs
|
|
158
|
+
/spec update prompt-plan "auth" # Check off matching items
|
|
159
|
+
/spec validate prompt-plan # Check completion status
|
|
160
|
+
|
|
161
|
+
# CLI equivalent
|
|
162
|
+
stackmemory skills spec one-pager "My App"
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
Output goes to `docs/specs/`. Use `--force` to regenerate an existing spec.
|
|
166
|
+
|
|
167
|
+
### Linear Task Runner (`/linear-run`)
|
|
168
|
+
|
|
169
|
+
Pulls tasks from Linear, executes them via the RLM orchestrator (8 subagent types), and syncs results back.
|
|
170
|
+
|
|
171
|
+
```bash
|
|
172
|
+
/linear-run next # Execute next todo task
|
|
173
|
+
/linear-run next --priority high # Filter by priority
|
|
174
|
+
/linear-run all # Execute all pending tasks
|
|
175
|
+
/linear-run all --dry-run # Preview without executing
|
|
176
|
+
/linear-run task STA-123 # Run a specific task
|
|
177
|
+
/linear-run preview # Show execution plan
|
|
178
|
+
|
|
179
|
+
# CLI equivalent
|
|
180
|
+
stackmemory ralph linear next
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
On task completion:
|
|
184
|
+
1. Marks the Linear task as `done`
|
|
185
|
+
2. Auto-checks matching PROMPT_PLAN items
|
|
186
|
+
3. Syncs metrics (tokens, cost, tests) back to Linear
|
|
187
|
+
|
|
188
|
+
Options: `--priority <level>`, `--tag <tag>`, `--dry-run`, `--maxConcurrent <n>`
|
|
189
|
+
|
|
190
|
+
---
|
|
191
|
+
|
|
192
|
+
## Hooks (Automatic)
|
|
193
|
+
|
|
194
|
+
StackMemory installs Claude Code hooks that run automatically during your session. Hooks are non-blocking and fail silently to never interrupt your workflow.
|
|
195
|
+
|
|
196
|
+
### Installed Hooks
|
|
197
|
+
|
|
198
|
+
| Hook | Trigger | What it does |
|
|
199
|
+
|------|---------|-------------|
|
|
200
|
+
| `on-task-complete` | Task marked done | Saves context, syncs Linear (STA-* tasks), auto-checks PROMPT_PLAN items |
|
|
201
|
+
| `on-startup` | Session start | Loads StackMemory context, initializes frame |
|
|
202
|
+
| `on-clear` | `/clear` command | Persists context before clearing |
|
|
203
|
+
| `skill-eval` | User prompt | Scores prompt against 28 skill patterns, recommends relevant skills |
|
|
204
|
+
| `tool-use-trace` | Tool invocation | Logs tool usage for context tracking |
|
|
205
|
+
|
|
206
|
+
### Skill Evaluation
|
|
207
|
+
|
|
208
|
+
When you type a prompt, the `skill-eval` hook scores it against `skill-rules.json` (28 mapped skills with keyword, pattern, intent, and directory matching). Skills scoring above the threshold (default: 3) are recommended.
|
|
209
|
+
|
|
210
|
+
```json
|
|
211
|
+
// Example: user types "generate a spec for the auth system"
|
|
212
|
+
// skill-eval recommends:
|
|
213
|
+
{
|
|
214
|
+
"recommendedSkills": [
|
|
215
|
+
{ "skillName": "spec-generator", "score": 8 },
|
|
216
|
+
{ "skillName": "frame-management", "score": 5 }
|
|
217
|
+
]
|
|
218
|
+
}
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
### Hook Installation
|
|
222
|
+
|
|
223
|
+
Hooks install automatically during `npm install` (with user consent). To install or reinstall manually:
|
|
224
|
+
|
|
225
|
+
```bash
|
|
226
|
+
# Automatic (prompted during npm install)
|
|
227
|
+
npm install -g @stackmemoryai/stackmemory
|
|
228
|
+
|
|
229
|
+
# Manual install
|
|
230
|
+
stackmemory hooks install
|
|
135
231
|
|
|
136
|
-
|
|
232
|
+
# Skip hooks (CI/non-interactive)
|
|
233
|
+
STACKMEMORY_AUTO_HOOKS=true npm install -g @stackmemoryai/stackmemory
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
Hooks are stored in `~/.claude/hooks/` and configured via `~/.claude/hooks.json`.
|
|
237
|
+
|
|
238
|
+
### PROMPT_PLAN Auto-Progress
|
|
239
|
+
|
|
240
|
+
When a task completes (via hook or `/linear-run`), StackMemory fuzzy-matches the task title against unchecked `- [ ]` items in `docs/specs/PROMPT_PLAN.md` and checks them off automatically. One item per task completion, best-effort.
|
|
137
241
|
|
|
138
242
|
---
|
|
139
243
|
|
|
140
|
-
##
|
|
244
|
+
## Prompt Forge (GEPA)
|
|
245
|
+
|
|
246
|
+
When launching via `claude-sm`, StackMemory watches `CLAUDE.md`, `AGENT.md`, and `AGENTS.md` for changes. On file modification, the GEPA optimizer analyzes content and suggests improvements for prompt clarity and structure. Runs as a detached background process.
|
|
247
|
+
|
|
248
|
+
```bash
|
|
249
|
+
# Launch with Prompt Forge active
|
|
250
|
+
claude-sm
|
|
251
|
+
|
|
252
|
+
# Status shown in terminal:
|
|
253
|
+
# Prompt Forge: watching CLAUDE.md, AGENTS.md for optimization
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
---
|
|
141
257
|
|
|
142
258
|
### Install
|
|
143
259
|
|
|
@@ -180,15 +296,11 @@ stackmemory doctor
|
|
|
180
296
|
|
|
181
297
|
Checks project initialization, database integrity, MCP config, and suggests fixes.
|
|
182
298
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
## 3. Advanced Setup
|
|
186
|
-
|
|
187
|
-
See https://github.com/stackmemoryai/stackmemory/blob/main/docs/setup.md for advanced options (hosted mode, ChromaDB, manual MCP config, and available tools).
|
|
299
|
+
See [docs/setup.md](https://github.com/stackmemoryai/stackmemory/blob/main/docs/setup.md) for advanced options (hosted mode, ChromaDB, manual MCP config).
|
|
188
300
|
|
|
189
301
|
---
|
|
190
302
|
|
|
191
|
-
##
|
|
303
|
+
## Open-Source Local Mode
|
|
192
304
|
|
|
193
305
|
### Step 1: Clone & Build
|
|
194
306
|
|
|
@@ -285,35 +397,17 @@ StackMemory implements an intelligent two-tier storage architecture:
|
|
|
285
397
|
|
|
286
398
|
## Claude Code Integration
|
|
287
399
|
|
|
288
|
-
StackMemory
|
|
289
|
-
|
|
290
|
-
### Quick Setup
|
|
400
|
+
StackMemory integrates with Claude Code via MCP tools, skills, and hooks. See the [Hooks](#hooks-automatic) and [Skills](#skills-system) sections above.
|
|
291
401
|
|
|
292
402
|
```bash
|
|
293
|
-
#
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
#
|
|
298
|
-
```
|
|
299
|
-
|
|
300
|
-
### Integration Methods
|
|
301
|
-
|
|
302
|
-
```bash
|
|
303
|
-
# 1. Shell wrapper (recommended)
|
|
304
|
-
claude [--auto-sync] [--sync-interval=10]
|
|
305
|
-
|
|
306
|
-
# 2. Linear auto-sync daemon
|
|
307
|
-
./scripts/linear-auto-sync.sh start [interval]
|
|
308
|
-
|
|
309
|
-
# 3. Background daemon
|
|
310
|
-
./scripts/stackmemory-daemon.sh [interval] &
|
|
311
|
-
|
|
312
|
-
# 4. Git hooks
|
|
313
|
-
./scripts/setup-git-hooks.sh
|
|
403
|
+
# Full setup (one-time)
|
|
404
|
+
npm install -g @stackmemoryai/stackmemory # installs hooks automatically
|
|
405
|
+
cd your-project && stackmemory init # init project
|
|
406
|
+
stackmemory setup-mcp # configure MCP
|
|
407
|
+
stackmemory doctor # verify everything works
|
|
314
408
|
```
|
|
315
409
|
|
|
316
|
-
|
|
410
|
+
Additional integration methods: shell wrapper (`claude-sm`), Linear auto-sync daemon, background daemon, git hooks. See [docs/setup.md](https://github.com/stackmemoryai/stackmemory/blob/main/docs/setup.md).
|
|
317
411
|
|
|
318
412
|
## RLM (Recursive Language Model) Orchestration
|
|
319
413
|
|
|
@@ -106,6 +106,8 @@ The daemon provides:
|
|
|
106
106
|
const services = [];
|
|
107
107
|
if (newStatus.services.context.enabled) services.push("context");
|
|
108
108
|
if (newStatus.services.linear.enabled) services.push("linear");
|
|
109
|
+
if (newStatus.services.maintenance?.enabled)
|
|
110
|
+
services.push("maintenance");
|
|
109
111
|
if (newStatus.services.fileWatch.enabled) services.push("file-watch");
|
|
110
112
|
if (services.length > 0) {
|
|
111
113
|
console.log(chalk.gray(`Services: ${services.join(", ")}`));
|
|
@@ -228,6 +230,31 @@ The daemon provides:
|
|
|
228
230
|
console.log(chalk.gray(` Syncs: ${lin.syncCount}`));
|
|
229
231
|
}
|
|
230
232
|
}
|
|
233
|
+
const maint = status.services.maintenance;
|
|
234
|
+
if (maint) {
|
|
235
|
+
console.log(
|
|
236
|
+
` Maintenance: ${maint.enabled ? chalk.green("Enabled") : chalk.gray("Disabled")}`
|
|
237
|
+
);
|
|
238
|
+
if (maint.enabled) {
|
|
239
|
+
console.log(
|
|
240
|
+
chalk.gray(` Interval: ${config.maintenance.interval} min`)
|
|
241
|
+
);
|
|
242
|
+
if (maint.staleFramesCleaned) {
|
|
243
|
+
console.log(
|
|
244
|
+
chalk.gray(
|
|
245
|
+
` Stale frames cleaned: ${maint.staleFramesCleaned}`
|
|
246
|
+
)
|
|
247
|
+
);
|
|
248
|
+
}
|
|
249
|
+
if (maint.ftsRebuilds) {
|
|
250
|
+
console.log(chalk.gray(` FTS rebuilds: ${maint.ftsRebuilds}`));
|
|
251
|
+
}
|
|
252
|
+
if (maint.lastRun) {
|
|
253
|
+
const ago = Math.round((Date.now() - maint.lastRun) / 1e3 / 60);
|
|
254
|
+
console.log(chalk.gray(` Last run: ${ago} min ago`));
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
231
258
|
const fw = status.services.fileWatch;
|
|
232
259
|
console.log(
|
|
233
260
|
` FileWatch: ${fw.enabled ? chalk.green("Enabled") : chalk.gray("Disabled")}`
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/cli/commands/daemon.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Daemon CLI Command\n * Manage StackMemory unified daemon\n */\n\nimport { Command } from 'commander';\nimport chalk from 'chalk';\nimport ora from 'ora';\nimport { existsSync, readFileSync, unlinkSync } from 'fs';\nimport { spawn } from 'child_process';\nimport { join } from 'path';\nimport {\n loadDaemonConfig,\n saveDaemonConfig,\n readDaemonStatus,\n getDaemonPaths,\n DEFAULT_DAEMON_CONFIG,\n type DaemonConfig,\n} from '../../daemon/daemon-config.js';\n\nexport function createDaemonCommand(): Command {\n const cmd = new Command('daemon')\n .description('Manage StackMemory unified daemon for background services')\n .addHelpText(\n 'after',\n `\nExamples:\n stackmemory daemon start Start the daemon\n stackmemory daemon stop Stop the daemon\n stackmemory daemon status Check daemon status\n stackmemory daemon logs View daemon logs\n stackmemory daemon config Show/edit configuration\n\nThe daemon provides:\n - Context auto-save (default: every 15 minutes)\n - Linear sync (optional, if configured)\n - File watch (optional, for change detection)\n`\n );\n\n // Start command\n cmd\n .command('start')\n .description('Start the unified daemon')\n .option('--foreground', 'Run in foreground (for debugging)')\n .option('--save-interval <minutes>', 'Context save interval in minutes')\n .option('--linear-interval <minutes>', 'Linear sync interval in minutes')\n .option('--no-linear', 'Disable Linear sync')\n .option('--log-level <level>', 'Log level (debug|info|warn|error)')\n .action(async (options) => {\n const status = readDaemonStatus();\n\n if (status.running) {\n console.log(\n chalk.yellow('Daemon already running'),\n chalk.gray(`(pid: ${status.pid})`)\n );\n return;\n }\n\n const spinner = ora('Starting unified daemon...').start();\n\n try {\n // Build args\n const args = ['daemon-run'];\n\n if (options.saveInterval) {\n args.push('--save-interval', options.saveInterval);\n }\n if (options.linearInterval) {\n args.push('--linear-interval', options.linearInterval);\n }\n if (options.linear === false) {\n args.push('--no-linear');\n }\n if (options.logLevel) {\n args.push('--log-level', options.logLevel);\n }\n\n if (options.foreground) {\n spinner.stop();\n console.log(chalk.cyan('Running in foreground (Ctrl+C to stop)'));\n const { UnifiedDaemon } =\n await import('../../daemon/unified-daemon.js');\n const config: Partial<DaemonConfig> = {};\n if (options.saveInterval) {\n config.context = {\n enabled: true,\n interval: parseInt(options.saveInterval, 10),\n };\n }\n if (options.linearInterval) {\n config.linear = {\n enabled: true,\n interval: parseInt(options.linearInterval, 10),\n retryAttempts: 3,\n retryDelay: 30000,\n };\n }\n if (options.linear === false) {\n config.linear = {\n enabled: false,\n interval: 60,\n retryAttempts: 3,\n retryDelay: 30000,\n };\n }\n const daemon = new UnifiedDaemon(config);\n await daemon.start();\n return;\n }\n\n // Get path to daemon script\n const daemonScript = getDaemonScriptPath();\n if (!daemonScript) {\n spinner.fail(chalk.red('Daemon script not found'));\n return;\n }\n\n // Start in background\n const daemonProcess = spawn('node', [daemonScript, ...args.slice(1)], {\n detached: true,\n stdio: 'ignore',\n env: { ...process.env },\n });\n\n daemonProcess.unref();\n\n // Wait for startup\n await new Promise((r) => setTimeout(r, 1000));\n const newStatus = readDaemonStatus();\n\n if (newStatus.running) {\n spinner.succeed(chalk.green('Daemon started'));\n console.log(chalk.gray(`PID: ${newStatus.pid}`));\n\n // Show enabled services\n const services = [];\n if (newStatus.services.context.enabled) services.push('context');\n if (newStatus.services.linear.enabled) services.push('linear');\n if (newStatus.services.fileWatch.enabled) services.push('file-watch');\n if (services.length > 0) {\n console.log(chalk.gray(`Services: ${services.join(', ')}`));\n }\n } else {\n spinner.fail(chalk.red('Failed to start daemon'));\n console.log(chalk.gray('Check logs: stackmemory daemon logs'));\n }\n } catch (error) {\n spinner.fail(chalk.red('Failed to start daemon'));\n console.log(chalk.gray((error as Error).message));\n }\n });\n\n // Stop command\n cmd\n .command('stop')\n .description('Stop the unified daemon')\n .action(() => {\n const status = readDaemonStatus();\n\n if (!status.running || !status.pid) {\n console.log(chalk.yellow('Daemon not running'));\n return;\n }\n\n try {\n process.kill(status.pid, 'SIGTERM');\n console.log(chalk.green('Daemon stopped'));\n } catch (err) {\n console.log(chalk.red('Failed to stop daemon'));\n console.log(chalk.gray((err as Error).message));\n\n // Clean up stale PID file\n const { pidFile } = getDaemonPaths();\n if (existsSync(pidFile)) {\n unlinkSync(pidFile);\n console.log(chalk.gray('Cleaned up stale PID file'));\n }\n }\n });\n\n // Restart command\n cmd\n .command('restart')\n .description('Restart the unified daemon')\n .action(async () => {\n const status = readDaemonStatus();\n\n if (status.running && status.pid) {\n try {\n process.kill(status.pid, 'SIGTERM');\n await new Promise((r) => setTimeout(r, 1000));\n } catch {\n // Ignore\n }\n }\n\n // Get saved config\n const config = loadDaemonConfig();\n\n // Start with same config\n const daemonScript = getDaemonScriptPath();\n if (!daemonScript) {\n console.log(chalk.red('Daemon script not found'));\n return;\n }\n\n const args: string[] = [];\n if (config.context.interval !== 15) {\n args.push('--save-interval', String(config.context.interval));\n }\n if (!config.linear.enabled) {\n args.push('--no-linear');\n } else if (config.linear.interval !== 60) {\n args.push('--linear-interval', String(config.linear.interval));\n }\n\n const daemonProcess = spawn('node', [daemonScript, ...args], {\n detached: true,\n stdio: 'ignore',\n });\n daemonProcess.unref();\n\n await new Promise((r) => setTimeout(r, 1000));\n const newStatus = readDaemonStatus();\n\n if (newStatus.running) {\n console.log(\n chalk.green('Daemon restarted'),\n chalk.gray(`(pid: ${newStatus.pid})`)\n );\n } else {\n console.log(chalk.red('Failed to restart daemon'));\n }\n });\n\n // Status command\n cmd\n .command('status')\n .description('Check daemon status')\n .action(() => {\n const status = readDaemonStatus();\n const config = loadDaemonConfig();\n\n console.log(chalk.bold('\\nStackMemory Unified Daemon\\n'));\n\n console.log(\n `Status: ${status.running ? chalk.green('Running') : chalk.yellow('Stopped')}`\n );\n\n if (status.running) {\n console.log(chalk.gray(` PID: ${status.pid}`));\n if (status.uptime) {\n const uptime = Math.round(status.uptime / 1000);\n const hours = Math.floor(uptime / 3600);\n const mins = Math.floor((uptime % 3600) / 60);\n const secs = uptime % 60;\n console.log(chalk.gray(` Uptime: ${hours}h ${mins}m ${secs}s`));\n }\n }\n\n console.log('');\n console.log(chalk.bold('Services:'));\n\n // Context service\n const ctx = status.services.context;\n console.log(\n ` Context: ${ctx.enabled ? chalk.green('Enabled') : chalk.gray('Disabled')}`\n );\n if (ctx.enabled) {\n console.log(chalk.gray(` Interval: ${config.context.interval} min`));\n if (ctx.saveCount) {\n console.log(chalk.gray(` Saves: ${ctx.saveCount}`));\n }\n if (ctx.lastRun) {\n const ago = Math.round((Date.now() - ctx.lastRun) / 1000 / 60);\n console.log(chalk.gray(` Last save: ${ago} min ago`));\n }\n }\n\n // Linear service\n const lin = status.services.linear;\n console.log(\n ` Linear: ${lin.enabled ? chalk.green('Enabled') : chalk.gray('Disabled')}`\n );\n if (lin.enabled) {\n console.log(chalk.gray(` Interval: ${config.linear.interval} min`));\n if (config.linear.quietHours) {\n console.log(\n chalk.gray(\n ` Quiet hours: ${config.linear.quietHours.start}:00 - ${config.linear.quietHours.end}:00`\n )\n );\n }\n if (lin.syncCount) {\n console.log(chalk.gray(` Syncs: ${lin.syncCount}`));\n }\n }\n\n // File watch\n const fw = status.services.fileWatch;\n console.log(\n ` FileWatch: ${fw.enabled ? chalk.green('Enabled') : chalk.gray('Disabled')}`\n );\n\n // Errors\n if (status.errors && status.errors.length > 0) {\n console.log('');\n console.log(chalk.bold('Recent Errors:'));\n status.errors.slice(-3).forEach((err) => {\n console.log(chalk.red(` - ${err.slice(0, 80)}`));\n });\n }\n\n if (!status.running) {\n console.log('');\n console.log(chalk.bold('To start: stackmemory daemon start'));\n }\n });\n\n // Logs command\n cmd\n .command('logs')\n .description('View daemon logs')\n .option('-n, --lines <number>', 'Number of lines to show', '50')\n .option('-f, --follow', 'Follow log output')\n .option('--level <level>', 'Filter by log level')\n .action((options) => {\n const { logFile } = getDaemonPaths();\n\n if (!existsSync(logFile)) {\n console.log(chalk.yellow('No log file found'));\n console.log(\n chalk.gray('Start the daemon first: stackmemory daemon start')\n );\n return;\n }\n\n if (options.follow) {\n const tail = spawn('tail', ['-f', logFile], { stdio: 'inherit' });\n tail.on('error', () => {\n console.log(chalk.red('Could not follow logs'));\n });\n return;\n }\n\n const content = readFileSync(logFile, 'utf8');\n const lines = content.trim().split('\\n');\n const count = parseInt(options.lines, 10);\n let recent = lines.slice(-count);\n\n // Filter by level if specified\n if (options.level) {\n const level = options.level.toUpperCase();\n recent = recent.filter((line) => {\n try {\n const entry = JSON.parse(line);\n return entry.level === level;\n } catch {\n return false;\n }\n });\n }\n\n console.log(chalk.bold(`\\nDaemon logs (${recent.length} lines):\\n`));\n\n for (const line of recent) {\n try {\n const entry = JSON.parse(line);\n const time = entry.timestamp.split('T')[1].split('.')[0];\n const levelColor =\n entry.level === 'ERROR'\n ? chalk.red\n : entry.level === 'WARN'\n ? chalk.yellow\n : entry.level === 'DEBUG'\n ? chalk.gray\n : chalk.white;\n\n console.log(\n `${chalk.gray(time)} ${levelColor(`[${entry.level}]`)} ${chalk.cyan(`[${entry.service}]`)} ${entry.message}`\n );\n } catch {\n console.log(line);\n }\n }\n });\n\n // Config command\n cmd\n .command('config')\n .description('Show or edit daemon configuration')\n .option('--edit', 'Open config in editor')\n .option('--reset', 'Reset to default configuration')\n .option('--set <key=value>', 'Set a config value')\n .action((options) => {\n const { configFile } = getDaemonPaths();\n\n if (options.reset) {\n saveDaemonConfig(DEFAULT_DAEMON_CONFIG);\n console.log(chalk.green('Configuration reset to defaults'));\n return;\n }\n\n if (options.edit) {\n const editor = process.env['EDITOR'] || 'vim';\n spawn(editor, [configFile], { stdio: 'inherit' });\n return;\n }\n\n if (options.set) {\n const [key, value] = options.set.split('=');\n const config = loadDaemonConfig();\n\n // Parse the key path (e.g., \"context.interval\")\n const parts = key.split('.');\n let target: Record<string, unknown> = config as unknown as Record<\n string,\n unknown\n >;\n for (let i = 0; i < parts.length - 1; i++) {\n if (target[parts[i]] && typeof target[parts[i]] === 'object') {\n target = target[parts[i]] as Record<string, unknown>;\n } else {\n console.log(chalk.red(`Invalid config key: ${key}`));\n return;\n }\n }\n\n const lastKey = parts[parts.length - 1];\n const parsed =\n value === 'true'\n ? true\n : value === 'false'\n ? false\n : isNaN(Number(value))\n ? value\n : Number(value);\n target[lastKey] = parsed;\n\n saveDaemonConfig(config);\n console.log(chalk.green(`Set ${key} = ${value}`));\n return;\n }\n\n // Show config\n const config = loadDaemonConfig();\n\n console.log(chalk.bold('\\nDaemon Configuration\\n'));\n console.log(chalk.gray(`File: ${configFile}`));\n console.log('');\n\n console.log(chalk.bold('Context Service:'));\n console.log(` Enabled: ${config.context.enabled}`);\n console.log(` Interval: ${config.context.interval} minutes`);\n\n console.log('');\n console.log(chalk.bold('Linear Service:'));\n console.log(` Enabled: ${config.linear.enabled}`);\n console.log(` Interval: ${config.linear.interval} minutes`);\n if (config.linear.quietHours) {\n console.log(\n ` Quiet hours: ${config.linear.quietHours.start}:00 - ${config.linear.quietHours.end}:00`\n );\n }\n\n console.log('');\n console.log(chalk.bold('File Watch:'));\n console.log(` Enabled: ${config.fileWatch.enabled}`);\n console.log(` Extensions: ${config.fileWatch.extensions.join(', ')}`);\n\n console.log('');\n console.log(chalk.bold('General:'));\n console.log(` Heartbeat: ${config.heartbeatInterval} seconds`);\n console.log(` Log level: ${config.logLevel}`);\n });\n\n // Default action\n cmd.action(() => {\n const status = readDaemonStatus();\n\n console.log(chalk.bold('\\nStackMemory Daemon\\n'));\n console.log(\n `Status: ${status.running ? chalk.green('Running') : chalk.yellow('Stopped')}`\n );\n\n if (!status.running) {\n console.log('');\n console.log(chalk.bold('Quick start:'));\n console.log(' stackmemory daemon start Start background services');\n } else {\n console.log('');\n console.log(chalk.bold('Commands:'));\n console.log(' stackmemory daemon status View detailed status');\n console.log(' stackmemory daemon logs View daemon logs');\n console.log(' stackmemory daemon stop Stop the daemon');\n }\n });\n\n return cmd;\n}\n\n/**\n * Get path to daemon script\n */\nfunction getDaemonScriptPath(): string | null {\n // Check various locations\n const candidates = [\n join(__dirname, '../../daemon/unified-daemon.js'),\n join(process.cwd(), 'dist/daemon/unified-daemon.js'),\n join(\n process.cwd(),\n 'node_modules/@stackmemoryai/stackmemory/dist/daemon/unified-daemon.js'\n ),\n ];\n\n for (const candidate of candidates) {\n if (existsSync(candidate)) {\n return candidate;\n }\n }\n\n return candidates[0]; // Return first candidate as fallback\n}\n\nexport default createDaemonCommand();\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["/**\n * Daemon CLI Command\n * Manage StackMemory unified daemon\n */\n\nimport { Command } from 'commander';\nimport chalk from 'chalk';\nimport ora from 'ora';\nimport { existsSync, readFileSync, unlinkSync } from 'fs';\nimport { spawn } from 'child_process';\nimport { join } from 'path';\nimport {\n loadDaemonConfig,\n saveDaemonConfig,\n readDaemonStatus,\n getDaemonPaths,\n DEFAULT_DAEMON_CONFIG,\n type DaemonConfig,\n} from '../../daemon/daemon-config.js';\n\nexport function createDaemonCommand(): Command {\n const cmd = new Command('daemon')\n .description('Manage StackMemory unified daemon for background services')\n .addHelpText(\n 'after',\n `\nExamples:\n stackmemory daemon start Start the daemon\n stackmemory daemon stop Stop the daemon\n stackmemory daemon status Check daemon status\n stackmemory daemon logs View daemon logs\n stackmemory daemon config Show/edit configuration\n\nThe daemon provides:\n - Context auto-save (default: every 15 minutes)\n - Linear sync (optional, if configured)\n - File watch (optional, for change detection)\n`\n );\n\n // Start command\n cmd\n .command('start')\n .description('Start the unified daemon')\n .option('--foreground', 'Run in foreground (for debugging)')\n .option('--save-interval <minutes>', 'Context save interval in minutes')\n .option('--linear-interval <minutes>', 'Linear sync interval in minutes')\n .option('--no-linear', 'Disable Linear sync')\n .option('--log-level <level>', 'Log level (debug|info|warn|error)')\n .action(async (options) => {\n const status = readDaemonStatus();\n\n if (status.running) {\n console.log(\n chalk.yellow('Daemon already running'),\n chalk.gray(`(pid: ${status.pid})`)\n );\n return;\n }\n\n const spinner = ora('Starting unified daemon...').start();\n\n try {\n // Build args\n const args = ['daemon-run'];\n\n if (options.saveInterval) {\n args.push('--save-interval', options.saveInterval);\n }\n if (options.linearInterval) {\n args.push('--linear-interval', options.linearInterval);\n }\n if (options.linear === false) {\n args.push('--no-linear');\n }\n if (options.logLevel) {\n args.push('--log-level', options.logLevel);\n }\n\n if (options.foreground) {\n spinner.stop();\n console.log(chalk.cyan('Running in foreground (Ctrl+C to stop)'));\n const { UnifiedDaemon } =\n await import('../../daemon/unified-daemon.js');\n const config: Partial<DaemonConfig> = {};\n if (options.saveInterval) {\n config.context = {\n enabled: true,\n interval: parseInt(options.saveInterval, 10),\n };\n }\n if (options.linearInterval) {\n config.linear = {\n enabled: true,\n interval: parseInt(options.linearInterval, 10),\n retryAttempts: 3,\n retryDelay: 30000,\n };\n }\n if (options.linear === false) {\n config.linear = {\n enabled: false,\n interval: 60,\n retryAttempts: 3,\n retryDelay: 30000,\n };\n }\n const daemon = new UnifiedDaemon(config);\n await daemon.start();\n return;\n }\n\n // Get path to daemon script\n const daemonScript = getDaemonScriptPath();\n if (!daemonScript) {\n spinner.fail(chalk.red('Daemon script not found'));\n return;\n }\n\n // Start in background\n const daemonProcess = spawn('node', [daemonScript, ...args.slice(1)], {\n detached: true,\n stdio: 'ignore',\n env: { ...process.env },\n });\n\n daemonProcess.unref();\n\n // Wait for startup\n await new Promise((r) => setTimeout(r, 1000));\n const newStatus = readDaemonStatus();\n\n if (newStatus.running) {\n spinner.succeed(chalk.green('Daemon started'));\n console.log(chalk.gray(`PID: ${newStatus.pid}`));\n\n // Show enabled services\n const services = [];\n if (newStatus.services.context.enabled) services.push('context');\n if (newStatus.services.linear.enabled) services.push('linear');\n if (newStatus.services.maintenance?.enabled)\n services.push('maintenance');\n if (newStatus.services.fileWatch.enabled) services.push('file-watch');\n if (services.length > 0) {\n console.log(chalk.gray(`Services: ${services.join(', ')}`));\n }\n } else {\n spinner.fail(chalk.red('Failed to start daemon'));\n console.log(chalk.gray('Check logs: stackmemory daemon logs'));\n }\n } catch (error) {\n spinner.fail(chalk.red('Failed to start daemon'));\n console.log(chalk.gray((error as Error).message));\n }\n });\n\n // Stop command\n cmd\n .command('stop')\n .description('Stop the unified daemon')\n .action(() => {\n const status = readDaemonStatus();\n\n if (!status.running || !status.pid) {\n console.log(chalk.yellow('Daemon not running'));\n return;\n }\n\n try {\n process.kill(status.pid, 'SIGTERM');\n console.log(chalk.green('Daemon stopped'));\n } catch (err) {\n console.log(chalk.red('Failed to stop daemon'));\n console.log(chalk.gray((err as Error).message));\n\n // Clean up stale PID file\n const { pidFile } = getDaemonPaths();\n if (existsSync(pidFile)) {\n unlinkSync(pidFile);\n console.log(chalk.gray('Cleaned up stale PID file'));\n }\n }\n });\n\n // Restart command\n cmd\n .command('restart')\n .description('Restart the unified daemon')\n .action(async () => {\n const status = readDaemonStatus();\n\n if (status.running && status.pid) {\n try {\n process.kill(status.pid, 'SIGTERM');\n await new Promise((r) => setTimeout(r, 1000));\n } catch {\n // Ignore\n }\n }\n\n // Get saved config\n const config = loadDaemonConfig();\n\n // Start with same config\n const daemonScript = getDaemonScriptPath();\n if (!daemonScript) {\n console.log(chalk.red('Daemon script not found'));\n return;\n }\n\n const args: string[] = [];\n if (config.context.interval !== 15) {\n args.push('--save-interval', String(config.context.interval));\n }\n if (!config.linear.enabled) {\n args.push('--no-linear');\n } else if (config.linear.interval !== 60) {\n args.push('--linear-interval', String(config.linear.interval));\n }\n\n const daemonProcess = spawn('node', [daemonScript, ...args], {\n detached: true,\n stdio: 'ignore',\n });\n daemonProcess.unref();\n\n await new Promise((r) => setTimeout(r, 1000));\n const newStatus = readDaemonStatus();\n\n if (newStatus.running) {\n console.log(\n chalk.green('Daemon restarted'),\n chalk.gray(`(pid: ${newStatus.pid})`)\n );\n } else {\n console.log(chalk.red('Failed to restart daemon'));\n }\n });\n\n // Status command\n cmd\n .command('status')\n .description('Check daemon status')\n .action(() => {\n const status = readDaemonStatus();\n const config = loadDaemonConfig();\n\n console.log(chalk.bold('\\nStackMemory Unified Daemon\\n'));\n\n console.log(\n `Status: ${status.running ? chalk.green('Running') : chalk.yellow('Stopped')}`\n );\n\n if (status.running) {\n console.log(chalk.gray(` PID: ${status.pid}`));\n if (status.uptime) {\n const uptime = Math.round(status.uptime / 1000);\n const hours = Math.floor(uptime / 3600);\n const mins = Math.floor((uptime % 3600) / 60);\n const secs = uptime % 60;\n console.log(chalk.gray(` Uptime: ${hours}h ${mins}m ${secs}s`));\n }\n }\n\n console.log('');\n console.log(chalk.bold('Services:'));\n\n // Context service\n const ctx = status.services.context;\n console.log(\n ` Context: ${ctx.enabled ? chalk.green('Enabled') : chalk.gray('Disabled')}`\n );\n if (ctx.enabled) {\n console.log(chalk.gray(` Interval: ${config.context.interval} min`));\n if (ctx.saveCount) {\n console.log(chalk.gray(` Saves: ${ctx.saveCount}`));\n }\n if (ctx.lastRun) {\n const ago = Math.round((Date.now() - ctx.lastRun) / 1000 / 60);\n console.log(chalk.gray(` Last save: ${ago} min ago`));\n }\n }\n\n // Linear service\n const lin = status.services.linear;\n console.log(\n ` Linear: ${lin.enabled ? chalk.green('Enabled') : chalk.gray('Disabled')}`\n );\n if (lin.enabled) {\n console.log(chalk.gray(` Interval: ${config.linear.interval} min`));\n if (config.linear.quietHours) {\n console.log(\n chalk.gray(\n ` Quiet hours: ${config.linear.quietHours.start}:00 - ${config.linear.quietHours.end}:00`\n )\n );\n }\n if (lin.syncCount) {\n console.log(chalk.gray(` Syncs: ${lin.syncCount}`));\n }\n }\n\n // Maintenance service\n const maint = status.services.maintenance;\n if (maint) {\n console.log(\n ` Maintenance: ${maint.enabled ? chalk.green('Enabled') : chalk.gray('Disabled')}`\n );\n if (maint.enabled) {\n console.log(\n chalk.gray(` Interval: ${config.maintenance.interval} min`)\n );\n if (maint.staleFramesCleaned) {\n console.log(\n chalk.gray(\n ` Stale frames cleaned: ${maint.staleFramesCleaned}`\n )\n );\n }\n if (maint.ftsRebuilds) {\n console.log(chalk.gray(` FTS rebuilds: ${maint.ftsRebuilds}`));\n }\n if (maint.lastRun) {\n const ago = Math.round((Date.now() - maint.lastRun) / 1000 / 60);\n console.log(chalk.gray(` Last run: ${ago} min ago`));\n }\n }\n }\n\n // File watch\n const fw = status.services.fileWatch;\n console.log(\n ` FileWatch: ${fw.enabled ? chalk.green('Enabled') : chalk.gray('Disabled')}`\n );\n\n // Errors\n if (status.errors && status.errors.length > 0) {\n console.log('');\n console.log(chalk.bold('Recent Errors:'));\n status.errors.slice(-3).forEach((err) => {\n console.log(chalk.red(` - ${err.slice(0, 80)}`));\n });\n }\n\n if (!status.running) {\n console.log('');\n console.log(chalk.bold('To start: stackmemory daemon start'));\n }\n });\n\n // Logs command\n cmd\n .command('logs')\n .description('View daemon logs')\n .option('-n, --lines <number>', 'Number of lines to show', '50')\n .option('-f, --follow', 'Follow log output')\n .option('--level <level>', 'Filter by log level')\n .action((options) => {\n const { logFile } = getDaemonPaths();\n\n if (!existsSync(logFile)) {\n console.log(chalk.yellow('No log file found'));\n console.log(\n chalk.gray('Start the daemon first: stackmemory daemon start')\n );\n return;\n }\n\n if (options.follow) {\n const tail = spawn('tail', ['-f', logFile], { stdio: 'inherit' });\n tail.on('error', () => {\n console.log(chalk.red('Could not follow logs'));\n });\n return;\n }\n\n const content = readFileSync(logFile, 'utf8');\n const lines = content.trim().split('\\n');\n const count = parseInt(options.lines, 10);\n let recent = lines.slice(-count);\n\n // Filter by level if specified\n if (options.level) {\n const level = options.level.toUpperCase();\n recent = recent.filter((line) => {\n try {\n const entry = JSON.parse(line);\n return entry.level === level;\n } catch {\n return false;\n }\n });\n }\n\n console.log(chalk.bold(`\\nDaemon logs (${recent.length} lines):\\n`));\n\n for (const line of recent) {\n try {\n const entry = JSON.parse(line);\n const time = entry.timestamp.split('T')[1].split('.')[0];\n const levelColor =\n entry.level === 'ERROR'\n ? chalk.red\n : entry.level === 'WARN'\n ? chalk.yellow\n : entry.level === 'DEBUG'\n ? chalk.gray\n : chalk.white;\n\n console.log(\n `${chalk.gray(time)} ${levelColor(`[${entry.level}]`)} ${chalk.cyan(`[${entry.service}]`)} ${entry.message}`\n );\n } catch {\n console.log(line);\n }\n }\n });\n\n // Config command\n cmd\n .command('config')\n .description('Show or edit daemon configuration')\n .option('--edit', 'Open config in editor')\n .option('--reset', 'Reset to default configuration')\n .option('--set <key=value>', 'Set a config value')\n .action((options) => {\n const { configFile } = getDaemonPaths();\n\n if (options.reset) {\n saveDaemonConfig(DEFAULT_DAEMON_CONFIG);\n console.log(chalk.green('Configuration reset to defaults'));\n return;\n }\n\n if (options.edit) {\n const editor = process.env['EDITOR'] || 'vim';\n spawn(editor, [configFile], { stdio: 'inherit' });\n return;\n }\n\n if (options.set) {\n const [key, value] = options.set.split('=');\n const config = loadDaemonConfig();\n\n // Parse the key path (e.g., \"context.interval\")\n const parts = key.split('.');\n let target: Record<string, unknown> = config as unknown as Record<\n string,\n unknown\n >;\n for (let i = 0; i < parts.length - 1; i++) {\n if (target[parts[i]] && typeof target[parts[i]] === 'object') {\n target = target[parts[i]] as Record<string, unknown>;\n } else {\n console.log(chalk.red(`Invalid config key: ${key}`));\n return;\n }\n }\n\n const lastKey = parts[parts.length - 1];\n const parsed =\n value === 'true'\n ? true\n : value === 'false'\n ? false\n : isNaN(Number(value))\n ? value\n : Number(value);\n target[lastKey] = parsed;\n\n saveDaemonConfig(config);\n console.log(chalk.green(`Set ${key} = ${value}`));\n return;\n }\n\n // Show config\n const config = loadDaemonConfig();\n\n console.log(chalk.bold('\\nDaemon Configuration\\n'));\n console.log(chalk.gray(`File: ${configFile}`));\n console.log('');\n\n console.log(chalk.bold('Context Service:'));\n console.log(` Enabled: ${config.context.enabled}`);\n console.log(` Interval: ${config.context.interval} minutes`);\n\n console.log('');\n console.log(chalk.bold('Linear Service:'));\n console.log(` Enabled: ${config.linear.enabled}`);\n console.log(` Interval: ${config.linear.interval} minutes`);\n if (config.linear.quietHours) {\n console.log(\n ` Quiet hours: ${config.linear.quietHours.start}:00 - ${config.linear.quietHours.end}:00`\n );\n }\n\n console.log('');\n console.log(chalk.bold('File Watch:'));\n console.log(` Enabled: ${config.fileWatch.enabled}`);\n console.log(` Extensions: ${config.fileWatch.extensions.join(', ')}`);\n\n console.log('');\n console.log(chalk.bold('General:'));\n console.log(` Heartbeat: ${config.heartbeatInterval} seconds`);\n console.log(` Log level: ${config.logLevel}`);\n });\n\n // Default action\n cmd.action(() => {\n const status = readDaemonStatus();\n\n console.log(chalk.bold('\\nStackMemory Daemon\\n'));\n console.log(\n `Status: ${status.running ? chalk.green('Running') : chalk.yellow('Stopped')}`\n );\n\n if (!status.running) {\n console.log('');\n console.log(chalk.bold('Quick start:'));\n console.log(' stackmemory daemon start Start background services');\n } else {\n console.log('');\n console.log(chalk.bold('Commands:'));\n console.log(' stackmemory daemon status View detailed status');\n console.log(' stackmemory daemon logs View daemon logs');\n console.log(' stackmemory daemon stop Stop the daemon');\n }\n });\n\n return cmd;\n}\n\n/**\n * Get path to daemon script\n */\nfunction getDaemonScriptPath(): string | null {\n // Check various locations\n const candidates = [\n join(__dirname, '../../daemon/unified-daemon.js'),\n join(process.cwd(), 'dist/daemon/unified-daemon.js'),\n join(\n process.cwd(),\n 'node_modules/@stackmemoryai/stackmemory/dist/daemon/unified-daemon.js'\n ),\n ];\n\n for (const candidate of candidates) {\n if (existsSync(candidate)) {\n return candidate;\n }\n }\n\n return candidates[0]; // Return first candidate as fallback\n}\n\nexport default createDaemonCommand();\n"],
|
|
5
|
+
"mappings": ";;;;AAKA,SAAS,eAAe;AACxB,OAAO,WAAW;AAClB,OAAO,SAAS;AAChB,SAAS,YAAY,cAAc,kBAAkB;AACrD,SAAS,aAAa;AACtB,SAAS,YAAY;AACrB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAEK;AAEA,SAAS,sBAA+B;AAC7C,QAAM,MAAM,IAAI,QAAQ,QAAQ,EAC7B,YAAY,2DAA2D,EACvE;AAAA,IACC;AAAA,IACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaF;AAGF,MACG,QAAQ,OAAO,EACf,YAAY,0BAA0B,EACtC,OAAO,gBAAgB,mCAAmC,EAC1D,OAAO,6BAA6B,kCAAkC,EACtE,OAAO,+BAA+B,iCAAiC,EACvE,OAAO,eAAe,qBAAqB,EAC3C,OAAO,uBAAuB,mCAAmC,EACjE,OAAO,OAAO,YAAY;AACzB,UAAM,SAAS,iBAAiB;AAEhC,QAAI,OAAO,SAAS;AAClB,cAAQ;AAAA,QACN,MAAM,OAAO,wBAAwB;AAAA,QACrC,MAAM,KAAK,SAAS,OAAO,GAAG,GAAG;AAAA,MACnC;AACA;AAAA,IACF;AAEA,UAAM,UAAU,IAAI,4BAA4B,EAAE,MAAM;AAExD,QAAI;AAEF,YAAM,OAAO,CAAC,YAAY;AAE1B,UAAI,QAAQ,cAAc;AACxB,aAAK,KAAK,mBAAmB,QAAQ,YAAY;AAAA,MACnD;AACA,UAAI,QAAQ,gBAAgB;AAC1B,aAAK,KAAK,qBAAqB,QAAQ,cAAc;AAAA,MACvD;AACA,UAAI,QAAQ,WAAW,OAAO;AAC5B,aAAK,KAAK,aAAa;AAAA,MACzB;AACA,UAAI,QAAQ,UAAU;AACpB,aAAK,KAAK,eAAe,QAAQ,QAAQ;AAAA,MAC3C;AAEA,UAAI,QAAQ,YAAY;AACtB,gBAAQ,KAAK;AACb,gBAAQ,IAAI,MAAM,KAAK,wCAAwC,CAAC;AAChE,cAAM,EAAE,cAAc,IACpB,MAAM,OAAO,gCAAgC;AAC/C,cAAM,SAAgC,CAAC;AACvC,YAAI,QAAQ,cAAc;AACxB,iBAAO,UAAU;AAAA,YACf,SAAS;AAAA,YACT,UAAU,SAAS,QAAQ,cAAc,EAAE;AAAA,UAC7C;AAAA,QACF;AACA,YAAI,QAAQ,gBAAgB;AAC1B,iBAAO,SAAS;AAAA,YACd,SAAS;AAAA,YACT,UAAU,SAAS,QAAQ,gBAAgB,EAAE;AAAA,YAC7C,eAAe;AAAA,YACf,YAAY;AAAA,UACd;AAAA,QACF;AACA,YAAI,QAAQ,WAAW,OAAO;AAC5B,iBAAO,SAAS;AAAA,YACd,SAAS;AAAA,YACT,UAAU;AAAA,YACV,eAAe;AAAA,YACf,YAAY;AAAA,UACd;AAAA,QACF;AACA,cAAM,SAAS,IAAI,cAAc,MAAM;AACvC,cAAM,OAAO,MAAM;AACnB;AAAA,MACF;AAGA,YAAM,eAAe,oBAAoB;AACzC,UAAI,CAAC,cAAc;AACjB,gBAAQ,KAAK,MAAM,IAAI,yBAAyB,CAAC;AACjD;AAAA,MACF;AAGA,YAAM,gBAAgB,MAAM,QAAQ,CAAC,cAAc,GAAG,KAAK,MAAM,CAAC,CAAC,GAAG;AAAA,QACpE,UAAU;AAAA,QACV,OAAO;AAAA,QACP,KAAK,EAAE,GAAG,QAAQ,IAAI;AAAA,MACxB,CAAC;AAED,oBAAc,MAAM;AAGpB,YAAM,IAAI,QAAQ,CAAC,MAAM,WAAW,GAAG,GAAI,CAAC;AAC5C,YAAM,YAAY,iBAAiB;AAEnC,UAAI,UAAU,SAAS;AACrB,gBAAQ,QAAQ,MAAM,MAAM,gBAAgB,CAAC;AAC7C,gBAAQ,IAAI,MAAM,KAAK,QAAQ,UAAU,GAAG,EAAE,CAAC;AAG/C,cAAM,WAAW,CAAC;AAClB,YAAI,UAAU,SAAS,QAAQ,QAAS,UAAS,KAAK,SAAS;AAC/D,YAAI,UAAU,SAAS,OAAO,QAAS,UAAS,KAAK,QAAQ;AAC7D,YAAI,UAAU,SAAS,aAAa;AAClC,mBAAS,KAAK,aAAa;AAC7B,YAAI,UAAU,SAAS,UAAU,QAAS,UAAS,KAAK,YAAY;AACpE,YAAI,SAAS,SAAS,GAAG;AACvB,kBAAQ,IAAI,MAAM,KAAK,aAAa,SAAS,KAAK,IAAI,CAAC,EAAE,CAAC;AAAA,QAC5D;AAAA,MACF,OAAO;AACL,gBAAQ,KAAK,MAAM,IAAI,wBAAwB,CAAC;AAChD,gBAAQ,IAAI,MAAM,KAAK,qCAAqC,CAAC;AAAA,MAC/D;AAAA,IACF,SAAS,OAAO;AACd,cAAQ,KAAK,MAAM,IAAI,wBAAwB,CAAC;AAChD,cAAQ,IAAI,MAAM,KAAM,MAAgB,OAAO,CAAC;AAAA,IAClD;AAAA,EACF,CAAC;AAGH,MACG,QAAQ,MAAM,EACd,YAAY,yBAAyB,EACrC,OAAO,MAAM;AACZ,UAAM,SAAS,iBAAiB;AAEhC,QAAI,CAAC,OAAO,WAAW,CAAC,OAAO,KAAK;AAClC,cAAQ,IAAI,MAAM,OAAO,oBAAoB,CAAC;AAC9C;AAAA,IACF;AAEA,QAAI;AACF,cAAQ,KAAK,OAAO,KAAK,SAAS;AAClC,cAAQ,IAAI,MAAM,MAAM,gBAAgB,CAAC;AAAA,IAC3C,SAAS,KAAK;AACZ,cAAQ,IAAI,MAAM,IAAI,uBAAuB,CAAC;AAC9C,cAAQ,IAAI,MAAM,KAAM,IAAc,OAAO,CAAC;AAG9C,YAAM,EAAE,QAAQ,IAAI,eAAe;AACnC,UAAI,WAAW,OAAO,GAAG;AACvB,mBAAW,OAAO;AAClB,gBAAQ,IAAI,MAAM,KAAK,2BAA2B,CAAC;AAAA,MACrD;AAAA,IACF;AAAA,EACF,CAAC;AAGH,MACG,QAAQ,SAAS,EACjB,YAAY,4BAA4B,EACxC,OAAO,YAAY;AAClB,UAAM,SAAS,iBAAiB;AAEhC,QAAI,OAAO,WAAW,OAAO,KAAK;AAChC,UAAI;AACF,gBAAQ,KAAK,OAAO,KAAK,SAAS;AAClC,cAAM,IAAI,QAAQ,CAAC,MAAM,WAAW,GAAG,GAAI,CAAC;AAAA,MAC9C,QAAQ;AAAA,MAER;AAAA,IACF;AAGA,UAAM,SAAS,iBAAiB;AAGhC,UAAM,eAAe,oBAAoB;AACzC,QAAI,CAAC,cAAc;AACjB,cAAQ,IAAI,MAAM,IAAI,yBAAyB,CAAC;AAChD;AAAA,IACF;AAEA,UAAM,OAAiB,CAAC;AACxB,QAAI,OAAO,QAAQ,aAAa,IAAI;AAClC,WAAK,KAAK,mBAAmB,OAAO,OAAO,QAAQ,QAAQ,CAAC;AAAA,IAC9D;AACA,QAAI,CAAC,OAAO,OAAO,SAAS;AAC1B,WAAK,KAAK,aAAa;AAAA,IACzB,WAAW,OAAO,OAAO,aAAa,IAAI;AACxC,WAAK,KAAK,qBAAqB,OAAO,OAAO,OAAO,QAAQ,CAAC;AAAA,IAC/D;AAEA,UAAM,gBAAgB,MAAM,QAAQ,CAAC,cAAc,GAAG,IAAI,GAAG;AAAA,MAC3D,UAAU;AAAA,MACV,OAAO;AAAA,IACT,CAAC;AACD,kBAAc,MAAM;AAEpB,UAAM,IAAI,QAAQ,CAAC,MAAM,WAAW,GAAG,GAAI,CAAC;AAC5C,UAAM,YAAY,iBAAiB;AAEnC,QAAI,UAAU,SAAS;AACrB,cAAQ;AAAA,QACN,MAAM,MAAM,kBAAkB;AAAA,QAC9B,MAAM,KAAK,SAAS,UAAU,GAAG,GAAG;AAAA,MACtC;AAAA,IACF,OAAO;AACL,cAAQ,IAAI,MAAM,IAAI,0BAA0B,CAAC;AAAA,IACnD;AAAA,EACF,CAAC;AAGH,MACG,QAAQ,QAAQ,EAChB,YAAY,qBAAqB,EACjC,OAAO,MAAM;AACZ,UAAM,SAAS,iBAAiB;AAChC,UAAM,SAAS,iBAAiB;AAEhC,YAAQ,IAAI,MAAM,KAAK,gCAAgC,CAAC;AAExD,YAAQ;AAAA,MACN,WAAW,OAAO,UAAU,MAAM,MAAM,SAAS,IAAI,MAAM,OAAO,SAAS,CAAC;AAAA,IAC9E;AAEA,QAAI,OAAO,SAAS;AAClB,cAAQ,IAAI,MAAM,KAAK,UAAU,OAAO,GAAG,EAAE,CAAC;AAC9C,UAAI,OAAO,QAAQ;AACjB,cAAM,SAAS,KAAK,MAAM,OAAO,SAAS,GAAI;AAC9C,cAAM,QAAQ,KAAK,MAAM,SAAS,IAAI;AACtC,cAAM,OAAO,KAAK,MAAO,SAAS,OAAQ,EAAE;AAC5C,cAAM,OAAO,SAAS;AACtB,gBAAQ,IAAI,MAAM,KAAK,aAAa,KAAK,KAAK,IAAI,KAAK,IAAI,GAAG,CAAC;AAAA,MACjE;AAAA,IACF;AAEA,YAAQ,IAAI,EAAE;AACd,YAAQ,IAAI,MAAM,KAAK,WAAW,CAAC;AAGnC,UAAM,MAAM,OAAO,SAAS;AAC5B,YAAQ;AAAA,MACN,cAAc,IAAI,UAAU,MAAM,MAAM,SAAS,IAAI,MAAM,KAAK,UAAU,CAAC;AAAA,IAC7E;AACA,QAAI,IAAI,SAAS;AACf,cAAQ,IAAI,MAAM,KAAK,iBAAiB,OAAO,QAAQ,QAAQ,MAAM,CAAC;AACtE,UAAI,IAAI,WAAW;AACjB,gBAAQ,IAAI,MAAM,KAAK,cAAc,IAAI,SAAS,EAAE,CAAC;AAAA,MACvD;AACA,UAAI,IAAI,SAAS;AACf,cAAM,MAAM,KAAK,OAAO,KAAK,IAAI,IAAI,IAAI,WAAW,MAAO,EAAE;AAC7D,gBAAQ,IAAI,MAAM,KAAK,kBAAkB,GAAG,UAAU,CAAC;AAAA,MACzD;AAAA,IACF;AAGA,UAAM,MAAM,OAAO,SAAS;AAC5B,YAAQ;AAAA,MACN,aAAa,IAAI,UAAU,MAAM,MAAM,SAAS,IAAI,MAAM,KAAK,UAAU,CAAC;AAAA,IAC5E;AACA,QAAI,IAAI,SAAS;AACf,cAAQ,IAAI,MAAM,KAAK,iBAAiB,OAAO,OAAO,QAAQ,MAAM,CAAC;AACrE,UAAI,OAAO,OAAO,YAAY;AAC5B,gBAAQ;AAAA,UACN,MAAM;AAAA,YACJ,oBAAoB,OAAO,OAAO,WAAW,KAAK,SAAS,OAAO,OAAO,WAAW,GAAG;AAAA,UACzF;AAAA,QACF;AAAA,MACF;AACA,UAAI,IAAI,WAAW;AACjB,gBAAQ,IAAI,MAAM,KAAK,cAAc,IAAI,SAAS,EAAE,CAAC;AAAA,MACvD;AAAA,IACF;AAGA,UAAM,QAAQ,OAAO,SAAS;AAC9B,QAAI,OAAO;AACT,cAAQ;AAAA,QACN,kBAAkB,MAAM,UAAU,MAAM,MAAM,SAAS,IAAI,MAAM,KAAK,UAAU,CAAC;AAAA,MACnF;AACA,UAAI,MAAM,SAAS;AACjB,gBAAQ;AAAA,UACN,MAAM,KAAK,iBAAiB,OAAO,YAAY,QAAQ,MAAM;AAAA,QAC/D;AACA,YAAI,MAAM,oBAAoB;AAC5B,kBAAQ;AAAA,YACN,MAAM;AAAA,cACJ,6BAA6B,MAAM,kBAAkB;AAAA,YACvD;AAAA,UACF;AAAA,QACF;AACA,YAAI,MAAM,aAAa;AACrB,kBAAQ,IAAI,MAAM,KAAK,qBAAqB,MAAM,WAAW,EAAE,CAAC;AAAA,QAClE;AACA,YAAI,MAAM,SAAS;AACjB,gBAAM,MAAM,KAAK,OAAO,KAAK,IAAI,IAAI,MAAM,WAAW,MAAO,EAAE;AAC/D,kBAAQ,IAAI,MAAM,KAAK,iBAAiB,GAAG,UAAU,CAAC;AAAA,QACxD;AAAA,MACF;AAAA,IACF;AAGA,UAAM,KAAK,OAAO,SAAS;AAC3B,YAAQ;AAAA,MACN,gBAAgB,GAAG,UAAU,MAAM,MAAM,SAAS,IAAI,MAAM,KAAK,UAAU,CAAC;AAAA,IAC9E;AAGA,QAAI,OAAO,UAAU,OAAO,OAAO,SAAS,GAAG;AAC7C,cAAQ,IAAI,EAAE;AACd,cAAQ,IAAI,MAAM,KAAK,gBAAgB,CAAC;AACxC,aAAO,OAAO,MAAM,EAAE,EAAE,QAAQ,CAAC,QAAQ;AACvC,gBAAQ,IAAI,MAAM,IAAI,OAAO,IAAI,MAAM,GAAG,EAAE,CAAC,EAAE,CAAC;AAAA,MAClD,CAAC;AAAA,IACH;AAEA,QAAI,CAAC,OAAO,SAAS;AACnB,cAAQ,IAAI,EAAE;AACd,cAAQ,IAAI,MAAM,KAAK,oCAAoC,CAAC;AAAA,IAC9D;AAAA,EACF,CAAC;AAGH,MACG,QAAQ,MAAM,EACd,YAAY,kBAAkB,EAC9B,OAAO,wBAAwB,2BAA2B,IAAI,EAC9D,OAAO,gBAAgB,mBAAmB,EAC1C,OAAO,mBAAmB,qBAAqB,EAC/C,OAAO,CAAC,YAAY;AACnB,UAAM,EAAE,QAAQ,IAAI,eAAe;AAEnC,QAAI,CAAC,WAAW,OAAO,GAAG;AACxB,cAAQ,IAAI,MAAM,OAAO,mBAAmB,CAAC;AAC7C,cAAQ;AAAA,QACN,MAAM,KAAK,kDAAkD;AAAA,MAC/D;AACA;AAAA,IACF;AAEA,QAAI,QAAQ,QAAQ;AAClB,YAAM,OAAO,MAAM,QAAQ,CAAC,MAAM,OAAO,GAAG,EAAE,OAAO,UAAU,CAAC;AAChE,WAAK,GAAG,SAAS,MAAM;AACrB,gBAAQ,IAAI,MAAM,IAAI,uBAAuB,CAAC;AAAA,MAChD,CAAC;AACD;AAAA,IACF;AAEA,UAAM,UAAU,aAAa,SAAS,MAAM;AAC5C,UAAM,QAAQ,QAAQ,KAAK,EAAE,MAAM,IAAI;AACvC,UAAM,QAAQ,SAAS,QAAQ,OAAO,EAAE;AACxC,QAAI,SAAS,MAAM,MAAM,CAAC,KAAK;AAG/B,QAAI,QAAQ,OAAO;AACjB,YAAM,QAAQ,QAAQ,MAAM,YAAY;AACxC,eAAS,OAAO,OAAO,CAAC,SAAS;AAC/B,YAAI;AACF,gBAAM,QAAQ,KAAK,MAAM,IAAI;AAC7B,iBAAO,MAAM,UAAU;AAAA,QACzB,QAAQ;AACN,iBAAO;AAAA,QACT;AAAA,MACF,CAAC;AAAA,IACH;AAEA,YAAQ,IAAI,MAAM,KAAK;AAAA,eAAkB,OAAO,MAAM;AAAA,CAAY,CAAC;AAEnE,eAAW,QAAQ,QAAQ;AACzB,UAAI;AACF,cAAM,QAAQ,KAAK,MAAM,IAAI;AAC7B,cAAM,OAAO,MAAM,UAAU,MAAM,GAAG,EAAE,CAAC,EAAE,MAAM,GAAG,EAAE,CAAC;AACvD,cAAM,aACJ,MAAM,UAAU,UACZ,MAAM,MACN,MAAM,UAAU,SACd,MAAM,SACN,MAAM,UAAU,UACd,MAAM,OACN,MAAM;AAEhB,gBAAQ;AAAA,UACN,GAAG,MAAM,KAAK,IAAI,CAAC,IAAI,WAAW,IAAI,MAAM,KAAK,GAAG,CAAC,IAAI,MAAM,KAAK,IAAI,MAAM,OAAO,GAAG,CAAC,IAAI,MAAM,OAAO;AAAA,QAC5G;AAAA,MACF,QAAQ;AACN,gBAAQ,IAAI,IAAI;AAAA,MAClB;AAAA,IACF;AAAA,EACF,CAAC;AAGH,MACG,QAAQ,QAAQ,EAChB,YAAY,mCAAmC,EAC/C,OAAO,UAAU,uBAAuB,EACxC,OAAO,WAAW,gCAAgC,EAClD,OAAO,qBAAqB,oBAAoB,EAChD,OAAO,CAAC,YAAY;AACnB,UAAM,EAAE,WAAW,IAAI,eAAe;AAEtC,QAAI,QAAQ,OAAO;AACjB,uBAAiB,qBAAqB;AACtC,cAAQ,IAAI,MAAM,MAAM,iCAAiC,CAAC;AAC1D;AAAA,IACF;AAEA,QAAI,QAAQ,MAAM;AAChB,YAAM,SAAS,QAAQ,IAAI,QAAQ,KAAK;AACxC,YAAM,QAAQ,CAAC,UAAU,GAAG,EAAE,OAAO,UAAU,CAAC;AAChD;AAAA,IACF;AAEA,QAAI,QAAQ,KAAK;AACf,YAAM,CAAC,KAAK,KAAK,IAAI,QAAQ,IAAI,MAAM,GAAG;AAC1C,YAAMA,UAAS,iBAAiB;AAGhC,YAAM,QAAQ,IAAI,MAAM,GAAG;AAC3B,UAAI,SAAkCA;AAItC,eAAS,IAAI,GAAG,IAAI,MAAM,SAAS,GAAG,KAAK;AACzC,YAAI,OAAO,MAAM,CAAC,CAAC,KAAK,OAAO,OAAO,MAAM,CAAC,CAAC,MAAM,UAAU;AAC5D,mBAAS,OAAO,MAAM,CAAC,CAAC;AAAA,QAC1B,OAAO;AACL,kBAAQ,IAAI,MAAM,IAAI,uBAAuB,GAAG,EAAE,CAAC;AACnD;AAAA,QACF;AAAA,MACF;AAEA,YAAM,UAAU,MAAM,MAAM,SAAS,CAAC;AACtC,YAAM,SACJ,UAAU,SACN,OACA,UAAU,UACR,QACA,MAAM,OAAO,KAAK,CAAC,IACjB,QACA,OAAO,KAAK;AACtB,aAAO,OAAO,IAAI;AAElB,uBAAiBA,OAAM;AACvB,cAAQ,IAAI,MAAM,MAAM,OAAO,GAAG,MAAM,KAAK,EAAE,CAAC;AAChD;AAAA,IACF;AAGA,UAAM,SAAS,iBAAiB;AAEhC,YAAQ,IAAI,MAAM,KAAK,0BAA0B,CAAC;AAClD,YAAQ,IAAI,MAAM,KAAK,SAAS,UAAU,EAAE,CAAC;AAC7C,YAAQ,IAAI,EAAE;AAEd,YAAQ,IAAI,MAAM,KAAK,kBAAkB,CAAC;AAC1C,YAAQ,IAAI,cAAc,OAAO,QAAQ,OAAO,EAAE;AAClD,YAAQ,IAAI,eAAe,OAAO,QAAQ,QAAQ,UAAU;AAE5D,YAAQ,IAAI,EAAE;AACd,YAAQ,IAAI,MAAM,KAAK,iBAAiB,CAAC;AACzC,YAAQ,IAAI,cAAc,OAAO,OAAO,OAAO,EAAE;AACjD,YAAQ,IAAI,eAAe,OAAO,OAAO,QAAQ,UAAU;AAC3D,QAAI,OAAO,OAAO,YAAY;AAC5B,cAAQ;AAAA,QACN,kBAAkB,OAAO,OAAO,WAAW,KAAK,SAAS,OAAO,OAAO,WAAW,GAAG;AAAA,MACvF;AAAA,IACF;AAEA,YAAQ,IAAI,EAAE;AACd,YAAQ,IAAI,MAAM,KAAK,aAAa,CAAC;AACrC,YAAQ,IAAI,cAAc,OAAO,UAAU,OAAO,EAAE;AACpD,YAAQ,IAAI,iBAAiB,OAAO,UAAU,WAAW,KAAK,IAAI,CAAC,EAAE;AAErE,YAAQ,IAAI,EAAE;AACd,YAAQ,IAAI,MAAM,KAAK,UAAU,CAAC;AAClC,YAAQ,IAAI,gBAAgB,OAAO,iBAAiB,UAAU;AAC9D,YAAQ,IAAI,gBAAgB,OAAO,QAAQ,EAAE;AAAA,EAC/C,CAAC;AAGH,MAAI,OAAO,MAAM;AACf,UAAM,SAAS,iBAAiB;AAEhC,YAAQ,IAAI,MAAM,KAAK,wBAAwB,CAAC;AAChD,YAAQ;AAAA,MACN,WAAW,OAAO,UAAU,MAAM,MAAM,SAAS,IAAI,MAAM,OAAO,SAAS,CAAC;AAAA,IAC9E;AAEA,QAAI,CAAC,OAAO,SAAS;AACnB,cAAQ,IAAI,EAAE;AACd,cAAQ,IAAI,MAAM,KAAK,cAAc,CAAC;AACtC,cAAQ,IAAI,yDAAyD;AAAA,IACvE,OAAO;AACL,cAAQ,IAAI,EAAE;AACd,cAAQ,IAAI,MAAM,KAAK,WAAW,CAAC;AACnC,cAAQ,IAAI,oDAAoD;AAChE,cAAQ,IAAI,gDAAgD;AAC5D,cAAQ,IAAI,+CAA+C;AAAA,IAC7D;AAAA,EACF,CAAC;AAED,SAAO;AACT;AAKA,SAAS,sBAAqC;AAE5C,QAAM,aAAa;AAAA,IACjB,KAAK,WAAW,gCAAgC;AAAA,IAChD,KAAK,QAAQ,IAAI,GAAG,+BAA+B;AAAA,IACnD;AAAA,MACE,QAAQ,IAAI;AAAA,MACZ;AAAA,IACF;AAAA,EACF;AAEA,aAAW,aAAa,YAAY;AAClC,QAAI,WAAW,SAAS,GAAG;AACzB,aAAO;AAAA,IACT;AAAA,EACF;AAEA,SAAO,WAAW,CAAC;AACrB;AAEA,IAAO,iBAAQ,oBAAoB;",
|
|
6
6
|
"names": ["config"]
|
|
7
7
|
}
|
|
@@ -27,9 +27,18 @@ class FrameDatabase {
|
|
|
27
27
|
*/
|
|
28
28
|
initSchema() {
|
|
29
29
|
try {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
30
|
+
try {
|
|
31
|
+
this.db.pragma("journal_mode = WAL");
|
|
32
|
+
} catch {
|
|
33
|
+
}
|
|
34
|
+
try {
|
|
35
|
+
this.db.pragma("synchronous = NORMAL");
|
|
36
|
+
} catch {
|
|
37
|
+
}
|
|
38
|
+
try {
|
|
39
|
+
this.db.pragma("foreign_keys = ON");
|
|
40
|
+
} catch {
|
|
41
|
+
}
|
|
33
42
|
this.db.exec(`
|
|
34
43
|
CREATE TABLE IF NOT EXISTS frames (
|
|
35
44
|
frame_id TEXT PRIMARY KEY,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/core/context/frame-database.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Frame Database Operations\n * Handles all database interactions for frames, events, and anchors\n */\n\nimport Database from 'better-sqlite3';\nimport { Frame, Event, Anchor } from './frame-types.js';\nimport { logger } from '../monitoring/logger.js';\nimport { DatabaseError, ErrorCode } from '../errors/index.js';\n\n// Database row types for type-safe queries\ninterface FrameRow {\n frame_id: string;\n run_id: string;\n project_id: string;\n parent_frame_id: string | null;\n depth: number;\n type: string;\n name: string;\n state: string;\n inputs: string;\n outputs: string;\n digest_text: string | null;\n digest_json: string;\n created_at: number;\n closed_at: number | null;\n}\n\ninterface EventRow {\n event_id: string;\n frame_id: string;\n run_id: string;\n seq: number;\n event_type: string;\n payload: string;\n ts: number;\n}\n\ninterface AnchorRow {\n anchor_id: string;\n frame_id: string;\n type: string;\n text: string;\n priority: number;\n metadata: string;\n created_at: number;\n}\n\ninterface CountRow {\n count: number;\n}\n\ninterface MaxSeqRow {\n max_seq: number | null;\n}\n\n// Default limits to prevent unbounded queries\nexport const DEFAULT_FRAME_LIMIT = 1000;\nexport const DEFAULT_EVENT_LIMIT = 500;\nexport const DEFAULT_ANCHOR_LIMIT = 200;\n\n// Safe JSON parse with fallback\nfunction safeJsonParse<T>(json: string | null | undefined, fallback: T): T {\n if (!json) return fallback;\n try {\n return JSON.parse(json) as T;\n } catch {\n logger.warn('Failed to parse JSON, using fallback', {\n json: json.substring(0, 100),\n });\n return fallback;\n }\n}\n\nexport class FrameDatabase {\n constructor(private db: Database.Database) {}\n\n /**\n * Initialize database schema\n */\n initSchema(): void {\n try {\n // Enable WAL mode for better concurrency\n this.db.pragma('journal_mode = WAL');\n this.db.pragma('synchronous = NORMAL');\n // Enforce referential integrity\n this.db.pragma('foreign_keys = ON');\n\n // Create frames table\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS frames (\n frame_id TEXT PRIMARY KEY,\n run_id TEXT NOT NULL,\n project_id TEXT NOT NULL,\n parent_frame_id TEXT,\n depth INTEGER NOT NULL DEFAULT 0,\n type TEXT NOT NULL,\n name TEXT NOT NULL,\n state TEXT NOT NULL DEFAULT 'active',\n inputs TEXT DEFAULT '{}',\n outputs TEXT DEFAULT '{}',\n digest_text TEXT,\n digest_json TEXT DEFAULT '{}',\n created_at INTEGER NOT NULL DEFAULT (unixepoch()),\n closed_at INTEGER,\n FOREIGN KEY (parent_frame_id) REFERENCES frames(frame_id)\n );\n `);\n\n // Create events table\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS events (\n event_id TEXT PRIMARY KEY,\n frame_id TEXT NOT NULL,\n run_id TEXT NOT NULL,\n seq INTEGER NOT NULL,\n event_type TEXT NOT NULL,\n payload TEXT NOT NULL DEFAULT '{}',\n ts INTEGER NOT NULL DEFAULT (unixepoch() * 1000),\n FOREIGN KEY (frame_id) REFERENCES frames(frame_id) ON DELETE CASCADE\n );\n `);\n\n // Create anchors table\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS anchors (\n anchor_id TEXT PRIMARY KEY,\n frame_id TEXT NOT NULL,\n type TEXT NOT NULL,\n text TEXT NOT NULL,\n priority INTEGER NOT NULL DEFAULT 5,\n metadata TEXT DEFAULT '{}',\n created_at INTEGER NOT NULL DEFAULT (unixepoch()),\n FOREIGN KEY (frame_id) REFERENCES frames(frame_id) ON DELETE CASCADE\n );\n `);\n\n // Create indexes for performance\n this.db.exec(`\n CREATE INDEX IF NOT EXISTS idx_frames_project_state ON frames(project_id, state);\n CREATE INDEX IF NOT EXISTS idx_frames_parent ON frames(parent_frame_id);\n CREATE INDEX IF NOT EXISTS idx_events_frame_seq ON events(frame_id, seq);\n CREATE INDEX IF NOT EXISTS idx_anchors_frame_priority ON anchors(frame_id, priority DESC);\n `);\n\n logger.info('Frame database schema initialized');\n } catch (error: unknown) {\n throw new DatabaseError(\n 'Failed to initialize frame database schema',\n ErrorCode.DB_SCHEMA_ERROR,\n { operation: 'initSchema' },\n error instanceof Error ? error : undefined\n );\n }\n }\n\n /**\n * Insert new frame\n */\n insertFrame(frame: Omit<Frame, 'created_at' | 'closed_at'>): Frame {\n try {\n const stmt = this.db.prepare(`\n INSERT INTO frames (frame_id, run_id, project_id, parent_frame_id, depth, type, name, state, inputs, outputs, digest_json)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n `);\n\n const result = stmt.run(\n frame.frame_id,\n frame.run_id,\n frame.project_id,\n frame.parent_frame_id || null,\n frame.depth,\n frame.type,\n frame.name,\n frame.state,\n JSON.stringify(frame.inputs),\n JSON.stringify(frame.outputs),\n JSON.stringify(frame.digest_json)\n );\n\n if (result.changes === 0) {\n throw new DatabaseError(\n 'Frame insertion failed - no rows affected',\n ErrorCode.DB_INSERT_FAILED,\n { frameId: frame.frame_id, operation: 'insertFrame' }\n );\n }\n\n // Return the created frame with timestamp\n const createdFrame = this.getFrame(frame.frame_id);\n if (!createdFrame) {\n throw new DatabaseError(\n 'Failed to retrieve created frame',\n ErrorCode.DB_QUERY_FAILED,\n { frameId: frame.frame_id, operation: 'insertFrame' }\n );\n }\n\n return createdFrame;\n } catch (error: unknown) {\n throw new DatabaseError(\n `Failed to insert frame: ${frame.frame_id}`,\n ErrorCode.DB_INSERT_FAILED,\n {\n frameId: frame.frame_id,\n frameName: frame.name,\n operation: 'insertFrame',\n },\n error instanceof Error ? error : undefined\n );\n }\n }\n\n /**\n * Get frame by ID\n */\n getFrame(frameId: string): Frame | undefined {\n try {\n const row = this.db\n .prepare('SELECT * FROM frames WHERE frame_id = ?')\n .get(frameId) as FrameRow | undefined;\n\n if (!row) return undefined;\n\n return {\n ...row,\n parent_frame_id: row.parent_frame_id ?? undefined,\n inputs: safeJsonParse<Record<string, unknown>>(row.inputs, {}),\n outputs: safeJsonParse<Record<string, unknown>>(row.outputs, {}),\n digest_json: safeJsonParse<Record<string, unknown>>(\n row.digest_json,\n {}\n ),\n } as Frame;\n } catch (error: unknown) {\n logger.warn(`Failed to get frame: ${frameId}`, { error });\n return undefined;\n }\n }\n\n /**\n * Update frame state and outputs\n */\n updateFrame(frameId: string, updates: Partial<Frame>): void {\n try {\n const setClauses: string[] = [];\n const values: (string | number | null)[] = [];\n\n if (updates.state !== undefined) {\n setClauses.push('state = ?');\n values.push(updates.state);\n }\n\n if (updates.outputs !== undefined) {\n setClauses.push('outputs = ?');\n values.push(JSON.stringify(updates.outputs));\n }\n\n if (updates.digest_text !== undefined) {\n setClauses.push('digest_text = ?');\n values.push(updates.digest_text);\n }\n\n if (updates.digest_json !== undefined) {\n setClauses.push('digest_json = ?');\n values.push(JSON.stringify(updates.digest_json));\n }\n\n if (updates.closed_at !== undefined) {\n setClauses.push('closed_at = ?');\n values.push(updates.closed_at);\n }\n\n if (updates.parent_frame_id !== undefined) {\n setClauses.push('parent_frame_id = ?');\n values.push(updates.parent_frame_id);\n }\n\n if (updates.depth !== undefined) {\n setClauses.push('depth = ?');\n values.push(updates.depth);\n }\n\n if (setClauses.length === 0) {\n return; // No updates to apply\n }\n\n values.push(frameId);\n\n const stmt = this.db.prepare(`\n UPDATE frames SET ${setClauses.join(', ')} WHERE frame_id = ?\n `);\n\n const result = stmt.run(...values);\n\n if (result.changes === 0) {\n throw new DatabaseError(\n `Frame not found: ${frameId}`,\n ErrorCode.DB_UPDATE_FAILED,\n { frameId, operation: 'updateFrame' }\n );\n }\n } catch (error: unknown) {\n throw new DatabaseError(\n `Failed to update frame: ${frameId}`,\n ErrorCode.DB_UPDATE_FAILED,\n { frameId, updates, operation: 'updateFrame' },\n error instanceof Error ? error : undefined\n );\n }\n }\n\n /**\n * Get frames by project and state\n */\n getFramesByProject(\n projectId: string,\n state?: 'active' | 'closed',\n limit: number = DEFAULT_FRAME_LIMIT\n ): Frame[] {\n try {\n const query = state\n ? 'SELECT * FROM frames WHERE project_id = ? AND state = ? ORDER BY created_at LIMIT ?'\n : 'SELECT * FROM frames WHERE project_id = ? ORDER BY created_at LIMIT ?';\n\n const params = state ? [projectId, state, limit] : [projectId, limit];\n const rows = this.db.prepare(query).all(...params) as FrameRow[];\n\n return rows.map((row) => ({\n ...row,\n parent_frame_id: row.parent_frame_id ?? undefined,\n inputs: safeJsonParse<Record<string, unknown>>(row.inputs, {}),\n outputs: safeJsonParse<Record<string, unknown>>(row.outputs, {}),\n digest_json: safeJsonParse<Record<string, unknown>>(\n row.digest_json,\n {}\n ),\n })) as Frame[];\n } catch (error: unknown) {\n throw new DatabaseError(\n `Failed to get frames for project: ${projectId}`,\n ErrorCode.DB_QUERY_FAILED,\n { projectId, state, operation: 'getFramesByProject' },\n error instanceof Error ? error : undefined\n );\n }\n }\n\n /**\n * Insert event\n */\n insertEvent(event: Omit<Event, 'ts'>): Event {\n try {\n const stmt = this.db.prepare(`\n INSERT INTO events (event_id, frame_id, run_id, seq, event_type, payload)\n VALUES (?, ?, ?, ?, ?, ?)\n `);\n\n const result = stmt.run(\n event.event_id,\n event.frame_id,\n event.run_id,\n event.seq,\n event.event_type,\n JSON.stringify(event.payload)\n );\n\n if (result.changes === 0) {\n throw new DatabaseError(\n 'Event insertion failed - no rows affected',\n ErrorCode.DB_INSERT_FAILED,\n {\n eventId: event.event_id,\n frameId: event.frame_id,\n operation: 'insertEvent',\n }\n );\n }\n\n // Return the created event with timestamp\n const createdEvent = this.db\n .prepare('SELECT * FROM events WHERE event_id = ?')\n .get(event.event_id) as EventRow;\n\n return {\n ...createdEvent,\n payload: safeJsonParse<Record<string, unknown>>(\n createdEvent.payload,\n {}\n ),\n } as Event;\n } catch (error: unknown) {\n throw new DatabaseError(\n `Failed to insert event: ${event.event_id}`,\n ErrorCode.DB_INSERT_FAILED,\n {\n eventId: event.event_id,\n frameId: event.frame_id,\n operation: 'insertEvent',\n },\n error instanceof Error ? error : undefined\n );\n }\n }\n\n /**\n * Get events for a frame\n */\n getFrameEvents(\n frameId: string,\n limit: number = DEFAULT_EVENT_LIMIT\n ): Event[] {\n try {\n const query =\n 'SELECT * FROM events WHERE frame_id = ? ORDER BY seq DESC LIMIT ?';\n const params = [frameId, limit];\n const rows = this.db.prepare(query).all(...params) as EventRow[];\n\n return rows.map((row) => ({\n ...row,\n payload: safeJsonParse<Record<string, unknown>>(row.payload, {}),\n })) as Event[];\n } catch (error: unknown) {\n throw new DatabaseError(\n `Failed to get events for frame: ${frameId}`,\n ErrorCode.DB_QUERY_FAILED,\n { frameId, limit, operation: 'getFrameEvents' },\n error instanceof Error ? error : undefined\n );\n }\n }\n\n /**\n * Get next event sequence number\n */\n getNextEventSequence(frameId: string): number {\n try {\n const result = this.db\n .prepare('SELECT MAX(seq) as max_seq FROM events WHERE frame_id = ?')\n .get(frameId) as MaxSeqRow;\n\n return (result.max_seq || 0) + 1;\n } catch (error: unknown) {\n throw new DatabaseError(\n `Failed to get next event sequence for frame: ${frameId}`,\n ErrorCode.DB_QUERY_FAILED,\n { frameId, operation: 'getNextEventSequence' },\n error instanceof Error ? error : undefined\n );\n }\n }\n\n /**\n * Insert anchor\n */\n insertAnchor(anchor: Omit<Anchor, 'created_at'>): Anchor {\n try {\n const stmt = this.db.prepare(`\n INSERT INTO anchors (anchor_id, frame_id, type, text, priority, metadata)\n VALUES (?, ?, ?, ?, ?, ?)\n `);\n\n const result = stmt.run(\n anchor.anchor_id,\n anchor.frame_id,\n anchor.type,\n anchor.text,\n anchor.priority,\n JSON.stringify(anchor.metadata)\n );\n\n if (result.changes === 0) {\n throw new DatabaseError(\n 'Anchor insertion failed - no rows affected',\n ErrorCode.DB_INSERT_FAILED,\n {\n anchorId: anchor.anchor_id,\n frameId: anchor.frame_id,\n operation: 'insertAnchor',\n }\n );\n }\n\n // Return the created anchor with timestamp\n const createdAnchor = this.db\n .prepare('SELECT * FROM anchors WHERE anchor_id = ?')\n .get(anchor.anchor_id) as AnchorRow;\n\n return {\n ...createdAnchor,\n metadata: safeJsonParse<Record<string, unknown>>(\n createdAnchor.metadata,\n {}\n ),\n } as Anchor;\n } catch (error: unknown) {\n throw new DatabaseError(\n `Failed to insert anchor: ${anchor.anchor_id}`,\n ErrorCode.DB_INSERT_FAILED,\n {\n anchorId: anchor.anchor_id,\n frameId: anchor.frame_id,\n operation: 'insertAnchor',\n },\n error instanceof Error ? error : undefined\n );\n }\n }\n\n /**\n * Get anchors for a frame\n */\n getFrameAnchors(\n frameId: string,\n limit: number = DEFAULT_ANCHOR_LIMIT\n ): Anchor[] {\n try {\n const rows = this.db\n .prepare(\n 'SELECT * FROM anchors WHERE frame_id = ? ORDER BY priority DESC, created_at ASC LIMIT ?'\n )\n .all(frameId, limit) as AnchorRow[];\n\n return rows.map((row) => ({\n ...row,\n metadata: safeJsonParse<Record<string, unknown>>(row.metadata, {}),\n })) as Anchor[];\n } catch (error: unknown) {\n throw new DatabaseError(\n `Failed to get anchors for frame: ${frameId}`,\n ErrorCode.DB_QUERY_FAILED,\n { frameId, operation: 'getFrameAnchors' },\n error instanceof Error ? error : undefined\n );\n }\n }\n\n /**\n * Delete frame and all related data\n */\n deleteFrame(frameId: string): void {\n try {\n // Delete in order due to foreign keys\n this.db.prepare('DELETE FROM anchors WHERE frame_id = ?').run(frameId);\n this.db.prepare('DELETE FROM events WHERE frame_id = ?').run(frameId);\n this.db.prepare('DELETE FROM frames WHERE frame_id = ?').run(frameId);\n\n logger.info('Frame deleted', { frameId });\n } catch (error: unknown) {\n throw new DatabaseError(\n `Failed to delete frame: ${frameId}`,\n ErrorCode.DB_DELETE_FAILED,\n { frameId, operation: 'deleteFrame' },\n error instanceof Error ? error : undefined\n );\n }\n }\n\n /**\n * Count frames by project and state (without loading all data)\n */\n countFrames(projectId?: string, state?: 'active' | 'closed'): number {\n try {\n let query = 'SELECT COUNT(*) as count FROM frames';\n const params: (string | undefined)[] = [];\n\n if (projectId) {\n query += ' WHERE project_id = ?';\n params.push(projectId);\n if (state) {\n query += ' AND state = ?';\n params.push(state);\n }\n } else if (state) {\n query += ' WHERE state = ?';\n params.push(state);\n }\n\n const result = this.db.prepare(query).get(...params) as CountRow;\n return result.count;\n } catch (error: unknown) {\n logger.warn('Failed to count frames', { error, projectId, state });\n return 0;\n }\n }\n\n /**\n * Get database statistics\n */\n getStatistics(): Record<string, number> {\n try {\n const frameCount = this.db\n .prepare('SELECT COUNT(*) as count FROM frames')\n .get() as CountRow;\n const eventCount = this.db\n .prepare('SELECT COUNT(*) as count FROM events')\n .get() as CountRow;\n const anchorCount = this.db\n .prepare('SELECT COUNT(*) as count FROM anchors')\n .get() as CountRow;\n const activeFrames = this.db\n .prepare(\"SELECT COUNT(*) as count FROM frames WHERE state = 'active'\")\n .get() as CountRow;\n\n return {\n totalFrames: frameCount.count,\n totalEvents: eventCount.count,\n totalAnchors: anchorCount.count,\n activeFrames: activeFrames.count,\n };\n } catch (error: unknown) {\n logger.warn('Failed to get database statistics', {\n error: error instanceof Error ? error.message : String(error),\n });\n return {};\n }\n }\n}\n"],
|
|
5
|
-
"mappings": ";;;;AAOA,SAAS,cAAc;AACvB,SAAS,eAAe,iBAAiB;AAiDlC,MAAM,sBAAsB;AAC5B,MAAM,sBAAsB;AAC5B,MAAM,uBAAuB;AAGpC,SAAS,cAAiB,MAAiC,UAAgB;AACzE,MAAI,CAAC,KAAM,QAAO;AAClB,MAAI;AACF,WAAO,KAAK,MAAM,IAAI;AAAA,EACxB,QAAQ;AACN,WAAO,KAAK,wCAAwC;AAAA,MAClD,MAAM,KAAK,UAAU,GAAG,GAAG;AAAA,IAC7B,CAAC;AACD,WAAO;AAAA,EACT;AACF;AAEO,MAAM,cAAc;AAAA,EACzB,YAAoB,IAAuB;AAAvB;AAAA,EAAwB;AAAA;AAAA;AAAA;AAAA,EAK5C,aAAmB;AACjB,QAAI;
|
|
4
|
+
"sourcesContent": ["/**\n * Frame Database Operations\n * Handles all database interactions for frames, events, and anchors\n */\n\nimport Database from 'better-sqlite3';\nimport { Frame, Event, Anchor } from './frame-types.js';\nimport { logger } from '../monitoring/logger.js';\nimport { DatabaseError, ErrorCode } from '../errors/index.js';\n\n// Database row types for type-safe queries\ninterface FrameRow {\n frame_id: string;\n run_id: string;\n project_id: string;\n parent_frame_id: string | null;\n depth: number;\n type: string;\n name: string;\n state: string;\n inputs: string;\n outputs: string;\n digest_text: string | null;\n digest_json: string;\n created_at: number;\n closed_at: number | null;\n}\n\ninterface EventRow {\n event_id: string;\n frame_id: string;\n run_id: string;\n seq: number;\n event_type: string;\n payload: string;\n ts: number;\n}\n\ninterface AnchorRow {\n anchor_id: string;\n frame_id: string;\n type: string;\n text: string;\n priority: number;\n metadata: string;\n created_at: number;\n}\n\ninterface CountRow {\n count: number;\n}\n\ninterface MaxSeqRow {\n max_seq: number | null;\n}\n\n// Default limits to prevent unbounded queries\nexport const DEFAULT_FRAME_LIMIT = 1000;\nexport const DEFAULT_EVENT_LIMIT = 500;\nexport const DEFAULT_ANCHOR_LIMIT = 200;\n\n// Safe JSON parse with fallback\nfunction safeJsonParse<T>(json: string | null | undefined, fallback: T): T {\n if (!json) return fallback;\n try {\n return JSON.parse(json) as T;\n } catch {\n logger.warn('Failed to parse JSON, using fallback', {\n json: json.substring(0, 100),\n });\n return fallback;\n }\n}\n\nexport class FrameDatabase {\n constructor(private db: Database.Database) {}\n\n /**\n * Initialize database schema\n */\n initSchema(): void {\n try {\n // Pragmas may fail if another component already opened this database\n // and left an implicit transaction (e.g. SQLiteAdapter.connect()).\n // Wrap each in try/catch so schema creation still proceeds.\n try {\n this.db.pragma('journal_mode = WAL');\n } catch {\n // WAL mode likely already set by adapter\n }\n try {\n this.db.pragma('synchronous = NORMAL');\n } catch {\n // Safety level cannot change inside a transaction \u2014 skip\n }\n try {\n this.db.pragma('foreign_keys = ON');\n } catch {\n // Foreign keys likely already enabled\n }\n\n // Create frames table\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS frames (\n frame_id TEXT PRIMARY KEY,\n run_id TEXT NOT NULL,\n project_id TEXT NOT NULL,\n parent_frame_id TEXT,\n depth INTEGER NOT NULL DEFAULT 0,\n type TEXT NOT NULL,\n name TEXT NOT NULL,\n state TEXT NOT NULL DEFAULT 'active',\n inputs TEXT DEFAULT '{}',\n outputs TEXT DEFAULT '{}',\n digest_text TEXT,\n digest_json TEXT DEFAULT '{}',\n created_at INTEGER NOT NULL DEFAULT (unixepoch()),\n closed_at INTEGER,\n FOREIGN KEY (parent_frame_id) REFERENCES frames(frame_id)\n );\n `);\n\n // Create events table\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS events (\n event_id TEXT PRIMARY KEY,\n frame_id TEXT NOT NULL,\n run_id TEXT NOT NULL,\n seq INTEGER NOT NULL,\n event_type TEXT NOT NULL,\n payload TEXT NOT NULL DEFAULT '{}',\n ts INTEGER NOT NULL DEFAULT (unixepoch() * 1000),\n FOREIGN KEY (frame_id) REFERENCES frames(frame_id) ON DELETE CASCADE\n );\n `);\n\n // Create anchors table\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS anchors (\n anchor_id TEXT PRIMARY KEY,\n frame_id TEXT NOT NULL,\n type TEXT NOT NULL,\n text TEXT NOT NULL,\n priority INTEGER NOT NULL DEFAULT 5,\n metadata TEXT DEFAULT '{}',\n created_at INTEGER NOT NULL DEFAULT (unixepoch()),\n FOREIGN KEY (frame_id) REFERENCES frames(frame_id) ON DELETE CASCADE\n );\n `);\n\n // Create indexes for performance\n this.db.exec(`\n CREATE INDEX IF NOT EXISTS idx_frames_project_state ON frames(project_id, state);\n CREATE INDEX IF NOT EXISTS idx_frames_parent ON frames(parent_frame_id);\n CREATE INDEX IF NOT EXISTS idx_events_frame_seq ON events(frame_id, seq);\n CREATE INDEX IF NOT EXISTS idx_anchors_frame_priority ON anchors(frame_id, priority DESC);\n `);\n\n logger.info('Frame database schema initialized');\n } catch (error: unknown) {\n throw new DatabaseError(\n 'Failed to initialize frame database schema',\n ErrorCode.DB_SCHEMA_ERROR,\n { operation: 'initSchema' },\n error instanceof Error ? error : undefined\n );\n }\n }\n\n /**\n * Insert new frame\n */\n insertFrame(frame: Omit<Frame, 'created_at' | 'closed_at'>): Frame {\n try {\n const stmt = this.db.prepare(`\n INSERT INTO frames (frame_id, run_id, project_id, parent_frame_id, depth, type, name, state, inputs, outputs, digest_json)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n `);\n\n const result = stmt.run(\n frame.frame_id,\n frame.run_id,\n frame.project_id,\n frame.parent_frame_id || null,\n frame.depth,\n frame.type,\n frame.name,\n frame.state,\n JSON.stringify(frame.inputs),\n JSON.stringify(frame.outputs),\n JSON.stringify(frame.digest_json)\n );\n\n if (result.changes === 0) {\n throw new DatabaseError(\n 'Frame insertion failed - no rows affected',\n ErrorCode.DB_INSERT_FAILED,\n { frameId: frame.frame_id, operation: 'insertFrame' }\n );\n }\n\n // Return the created frame with timestamp\n const createdFrame = this.getFrame(frame.frame_id);\n if (!createdFrame) {\n throw new DatabaseError(\n 'Failed to retrieve created frame',\n ErrorCode.DB_QUERY_FAILED,\n { frameId: frame.frame_id, operation: 'insertFrame' }\n );\n }\n\n return createdFrame;\n } catch (error: unknown) {\n throw new DatabaseError(\n `Failed to insert frame: ${frame.frame_id}`,\n ErrorCode.DB_INSERT_FAILED,\n {\n frameId: frame.frame_id,\n frameName: frame.name,\n operation: 'insertFrame',\n },\n error instanceof Error ? error : undefined\n );\n }\n }\n\n /**\n * Get frame by ID\n */\n getFrame(frameId: string): Frame | undefined {\n try {\n const row = this.db\n .prepare('SELECT * FROM frames WHERE frame_id = ?')\n .get(frameId) as FrameRow | undefined;\n\n if (!row) return undefined;\n\n return {\n ...row,\n parent_frame_id: row.parent_frame_id ?? undefined,\n inputs: safeJsonParse<Record<string, unknown>>(row.inputs, {}),\n outputs: safeJsonParse<Record<string, unknown>>(row.outputs, {}),\n digest_json: safeJsonParse<Record<string, unknown>>(\n row.digest_json,\n {}\n ),\n } as Frame;\n } catch (error: unknown) {\n logger.warn(`Failed to get frame: ${frameId}`, { error });\n return undefined;\n }\n }\n\n /**\n * Update frame state and outputs\n */\n updateFrame(frameId: string, updates: Partial<Frame>): void {\n try {\n const setClauses: string[] = [];\n const values: (string | number | null)[] = [];\n\n if (updates.state !== undefined) {\n setClauses.push('state = ?');\n values.push(updates.state);\n }\n\n if (updates.outputs !== undefined) {\n setClauses.push('outputs = ?');\n values.push(JSON.stringify(updates.outputs));\n }\n\n if (updates.digest_text !== undefined) {\n setClauses.push('digest_text = ?');\n values.push(updates.digest_text);\n }\n\n if (updates.digest_json !== undefined) {\n setClauses.push('digest_json = ?');\n values.push(JSON.stringify(updates.digest_json));\n }\n\n if (updates.closed_at !== undefined) {\n setClauses.push('closed_at = ?');\n values.push(updates.closed_at);\n }\n\n if (updates.parent_frame_id !== undefined) {\n setClauses.push('parent_frame_id = ?');\n values.push(updates.parent_frame_id);\n }\n\n if (updates.depth !== undefined) {\n setClauses.push('depth = ?');\n values.push(updates.depth);\n }\n\n if (setClauses.length === 0) {\n return; // No updates to apply\n }\n\n values.push(frameId);\n\n const stmt = this.db.prepare(`\n UPDATE frames SET ${setClauses.join(', ')} WHERE frame_id = ?\n `);\n\n const result = stmt.run(...values);\n\n if (result.changes === 0) {\n throw new DatabaseError(\n `Frame not found: ${frameId}`,\n ErrorCode.DB_UPDATE_FAILED,\n { frameId, operation: 'updateFrame' }\n );\n }\n } catch (error: unknown) {\n throw new DatabaseError(\n `Failed to update frame: ${frameId}`,\n ErrorCode.DB_UPDATE_FAILED,\n { frameId, updates, operation: 'updateFrame' },\n error instanceof Error ? error : undefined\n );\n }\n }\n\n /**\n * Get frames by project and state\n */\n getFramesByProject(\n projectId: string,\n state?: 'active' | 'closed',\n limit: number = DEFAULT_FRAME_LIMIT\n ): Frame[] {\n try {\n const query = state\n ? 'SELECT * FROM frames WHERE project_id = ? AND state = ? ORDER BY created_at LIMIT ?'\n : 'SELECT * FROM frames WHERE project_id = ? ORDER BY created_at LIMIT ?';\n\n const params = state ? [projectId, state, limit] : [projectId, limit];\n const rows = this.db.prepare(query).all(...params) as FrameRow[];\n\n return rows.map((row) => ({\n ...row,\n parent_frame_id: row.parent_frame_id ?? undefined,\n inputs: safeJsonParse<Record<string, unknown>>(row.inputs, {}),\n outputs: safeJsonParse<Record<string, unknown>>(row.outputs, {}),\n digest_json: safeJsonParse<Record<string, unknown>>(\n row.digest_json,\n {}\n ),\n })) as Frame[];\n } catch (error: unknown) {\n throw new DatabaseError(\n `Failed to get frames for project: ${projectId}`,\n ErrorCode.DB_QUERY_FAILED,\n { projectId, state, operation: 'getFramesByProject' },\n error instanceof Error ? error : undefined\n );\n }\n }\n\n /**\n * Insert event\n */\n insertEvent(event: Omit<Event, 'ts'>): Event {\n try {\n const stmt = this.db.prepare(`\n INSERT INTO events (event_id, frame_id, run_id, seq, event_type, payload)\n VALUES (?, ?, ?, ?, ?, ?)\n `);\n\n const result = stmt.run(\n event.event_id,\n event.frame_id,\n event.run_id,\n event.seq,\n event.event_type,\n JSON.stringify(event.payload)\n );\n\n if (result.changes === 0) {\n throw new DatabaseError(\n 'Event insertion failed - no rows affected',\n ErrorCode.DB_INSERT_FAILED,\n {\n eventId: event.event_id,\n frameId: event.frame_id,\n operation: 'insertEvent',\n }\n );\n }\n\n // Return the created event with timestamp\n const createdEvent = this.db\n .prepare('SELECT * FROM events WHERE event_id = ?')\n .get(event.event_id) as EventRow;\n\n return {\n ...createdEvent,\n payload: safeJsonParse<Record<string, unknown>>(\n createdEvent.payload,\n {}\n ),\n } as Event;\n } catch (error: unknown) {\n throw new DatabaseError(\n `Failed to insert event: ${event.event_id}`,\n ErrorCode.DB_INSERT_FAILED,\n {\n eventId: event.event_id,\n frameId: event.frame_id,\n operation: 'insertEvent',\n },\n error instanceof Error ? error : undefined\n );\n }\n }\n\n /**\n * Get events for a frame\n */\n getFrameEvents(\n frameId: string,\n limit: number = DEFAULT_EVENT_LIMIT\n ): Event[] {\n try {\n const query =\n 'SELECT * FROM events WHERE frame_id = ? ORDER BY seq DESC LIMIT ?';\n const params = [frameId, limit];\n const rows = this.db.prepare(query).all(...params) as EventRow[];\n\n return rows.map((row) => ({\n ...row,\n payload: safeJsonParse<Record<string, unknown>>(row.payload, {}),\n })) as Event[];\n } catch (error: unknown) {\n throw new DatabaseError(\n `Failed to get events for frame: ${frameId}`,\n ErrorCode.DB_QUERY_FAILED,\n { frameId, limit, operation: 'getFrameEvents' },\n error instanceof Error ? error : undefined\n );\n }\n }\n\n /**\n * Get next event sequence number\n */\n getNextEventSequence(frameId: string): number {\n try {\n const result = this.db\n .prepare('SELECT MAX(seq) as max_seq FROM events WHERE frame_id = ?')\n .get(frameId) as MaxSeqRow;\n\n return (result.max_seq || 0) + 1;\n } catch (error: unknown) {\n throw new DatabaseError(\n `Failed to get next event sequence for frame: ${frameId}`,\n ErrorCode.DB_QUERY_FAILED,\n { frameId, operation: 'getNextEventSequence' },\n error instanceof Error ? error : undefined\n );\n }\n }\n\n /**\n * Insert anchor\n */\n insertAnchor(anchor: Omit<Anchor, 'created_at'>): Anchor {\n try {\n const stmt = this.db.prepare(`\n INSERT INTO anchors (anchor_id, frame_id, type, text, priority, metadata)\n VALUES (?, ?, ?, ?, ?, ?)\n `);\n\n const result = stmt.run(\n anchor.anchor_id,\n anchor.frame_id,\n anchor.type,\n anchor.text,\n anchor.priority,\n JSON.stringify(anchor.metadata)\n );\n\n if (result.changes === 0) {\n throw new DatabaseError(\n 'Anchor insertion failed - no rows affected',\n ErrorCode.DB_INSERT_FAILED,\n {\n anchorId: anchor.anchor_id,\n frameId: anchor.frame_id,\n operation: 'insertAnchor',\n }\n );\n }\n\n // Return the created anchor with timestamp\n const createdAnchor = this.db\n .prepare('SELECT * FROM anchors WHERE anchor_id = ?')\n .get(anchor.anchor_id) as AnchorRow;\n\n return {\n ...createdAnchor,\n metadata: safeJsonParse<Record<string, unknown>>(\n createdAnchor.metadata,\n {}\n ),\n } as Anchor;\n } catch (error: unknown) {\n throw new DatabaseError(\n `Failed to insert anchor: ${anchor.anchor_id}`,\n ErrorCode.DB_INSERT_FAILED,\n {\n anchorId: anchor.anchor_id,\n frameId: anchor.frame_id,\n operation: 'insertAnchor',\n },\n error instanceof Error ? error : undefined\n );\n }\n }\n\n /**\n * Get anchors for a frame\n */\n getFrameAnchors(\n frameId: string,\n limit: number = DEFAULT_ANCHOR_LIMIT\n ): Anchor[] {\n try {\n const rows = this.db\n .prepare(\n 'SELECT * FROM anchors WHERE frame_id = ? ORDER BY priority DESC, created_at ASC LIMIT ?'\n )\n .all(frameId, limit) as AnchorRow[];\n\n return rows.map((row) => ({\n ...row,\n metadata: safeJsonParse<Record<string, unknown>>(row.metadata, {}),\n })) as Anchor[];\n } catch (error: unknown) {\n throw new DatabaseError(\n `Failed to get anchors for frame: ${frameId}`,\n ErrorCode.DB_QUERY_FAILED,\n { frameId, operation: 'getFrameAnchors' },\n error instanceof Error ? error : undefined\n );\n }\n }\n\n /**\n * Delete frame and all related data\n */\n deleteFrame(frameId: string): void {\n try {\n // Delete in order due to foreign keys\n this.db.prepare('DELETE FROM anchors WHERE frame_id = ?').run(frameId);\n this.db.prepare('DELETE FROM events WHERE frame_id = ?').run(frameId);\n this.db.prepare('DELETE FROM frames WHERE frame_id = ?').run(frameId);\n\n logger.info('Frame deleted', { frameId });\n } catch (error: unknown) {\n throw new DatabaseError(\n `Failed to delete frame: ${frameId}`,\n ErrorCode.DB_DELETE_FAILED,\n { frameId, operation: 'deleteFrame' },\n error instanceof Error ? error : undefined\n );\n }\n }\n\n /**\n * Count frames by project and state (without loading all data)\n */\n countFrames(projectId?: string, state?: 'active' | 'closed'): number {\n try {\n let query = 'SELECT COUNT(*) as count FROM frames';\n const params: (string | undefined)[] = [];\n\n if (projectId) {\n query += ' WHERE project_id = ?';\n params.push(projectId);\n if (state) {\n query += ' AND state = ?';\n params.push(state);\n }\n } else if (state) {\n query += ' WHERE state = ?';\n params.push(state);\n }\n\n const result = this.db.prepare(query).get(...params) as CountRow;\n return result.count;\n } catch (error: unknown) {\n logger.warn('Failed to count frames', { error, projectId, state });\n return 0;\n }\n }\n\n /**\n * Get database statistics\n */\n getStatistics(): Record<string, number> {\n try {\n const frameCount = this.db\n .prepare('SELECT COUNT(*) as count FROM frames')\n .get() as CountRow;\n const eventCount = this.db\n .prepare('SELECT COUNT(*) as count FROM events')\n .get() as CountRow;\n const anchorCount = this.db\n .prepare('SELECT COUNT(*) as count FROM anchors')\n .get() as CountRow;\n const activeFrames = this.db\n .prepare(\"SELECT COUNT(*) as count FROM frames WHERE state = 'active'\")\n .get() as CountRow;\n\n return {\n totalFrames: frameCount.count,\n totalEvents: eventCount.count,\n totalAnchors: anchorCount.count,\n activeFrames: activeFrames.count,\n };\n } catch (error: unknown) {\n logger.warn('Failed to get database statistics', {\n error: error instanceof Error ? error.message : String(error),\n });\n return {};\n }\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { fileURLToPath as __fileURLToPath } from 'url';
|
|
2
|
+
import { dirname as __pathDirname } from 'path';
|
|
3
|
+
const __filename = __fileURLToPath(import.meta.url);
|
|
4
|
+
const __dirname = __pathDirname(__filename);
|
|
5
|
+
class NoOpEmbeddingProvider {
|
|
6
|
+
dimension = 0;
|
|
7
|
+
async embed(_text) {
|
|
8
|
+
return [];
|
|
9
|
+
}
|
|
10
|
+
async embedBatch(_texts) {
|
|
11
|
+
return [];
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
export {
|
|
15
|
+
NoOpEmbeddingProvider
|
|
16
|
+
};
|
|
17
|
+
//# sourceMappingURL=embedding-provider.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/core/database/embedding-provider.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Embedding Provider Interface\n * Abstraction for generating vector embeddings from text\n */\n\nexport interface EmbeddingProvider {\n /** Generate embedding for a single text */\n embed(text: string): Promise<number[]>;\n /** Generate embeddings for multiple texts */\n embedBatch(texts: string[]): Promise<number[][]>;\n /** Dimensionality of the embedding vectors */\n dimension: number;\n}\n\n/**\n * No-op provider that disables vector search.\n * Used as default when no real provider is configured.\n */\nexport class NoOpEmbeddingProvider implements EmbeddingProvider {\n readonly dimension = 0;\n\n async embed(_text: string): Promise<number[]> {\n return [];\n }\n\n async embedBatch(_texts: string[]): Promise<number[][]> {\n return [];\n }\n}\n"],
|
|
5
|
+
"mappings": ";;;;AAkBO,MAAM,sBAAmD;AAAA,EACrD,YAAY;AAAA,EAErB,MAAM,MAAM,OAAkC;AAC5C,WAAO,CAAC;AAAA,EACV;AAAA,EAEA,MAAM,WAAW,QAAuC;AACtD,WAAO,CAAC;AAAA,EACV;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|