@stackmemoryai/stackmemory 1.5.2 → 1.5.4
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 +24 -1
- package/dist/src/cli/commands/dashboard.js +47 -1
- package/dist/src/cli/commands/orchestrate.js +82 -5
- package/dist/src/cli/commands/orchestrator.js +428 -61
- package/package.json +2 -2
- package/scripts/gepa/.before-optimize.md +89 -53
- package/scripts/gepa/generations/gen-000/baseline.md +8 -0
- package/scripts/gepa/generations/gen-001/baseline.md +8 -0
- package/scripts/gepa/generations/gen-001/variant-a.md +81 -81
- package/scripts/gepa/generations/gen-001/variant-b.md +78 -64
- package/scripts/gepa/generations/gen-001/variant-c.md +54 -74
- package/scripts/gepa/generations/gen-001/variant-d.md +79 -113
- package/scripts/gepa/results/eval-1-baseline.json +74 -74
- package/scripts/gepa/results/eval-1-variant-a.json +64 -64
- package/scripts/gepa/results/eval-1-variant-b.json +65 -65
- package/scripts/gepa/results/eval-1-variant-c.json +78 -58
- package/scripts/gepa/results/eval-1-variant-d.json +77 -57
- package/scripts/gepa/state.json +14 -14
|
@@ -1,150 +1,115 @@
|
|
|
1
|
+
```markdown
|
|
1
2
|
# StackMemory - Project Configuration
|
|
2
3
|
|
|
3
|
-
##
|
|
4
|
+
## Quick Reference
|
|
4
5
|
|
|
5
|
-
|
|
6
|
+
**Entry points:** `src/cli/index.ts` · `src/integrations/mcp/server.ts`
|
|
7
|
+
**Key files:** `src/core/context/frame-manager.ts` · `src/core/database/sqlite-adapter.ts` · `src/core/worktree/{capture,preflight}.ts` · `src/cli/commands/orchestrator.ts` · `src/core/utils/{git,text,fs}.ts`
|
|
6
8
|
|
|
7
|
-
**
|
|
8
|
-
**Tech**: TypeScript, Node.js, SQLite, Vitest, ESLint, esbuild
|
|
9
|
+
**Docs:** `agent_docs/` (quick ref) · `docs/` (full: principles, architecture, SPEC, API_REFERENCE, DEVELOPMENT, SETUP)
|
|
9
10
|
|
|
10
|
-
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Project Structure
|
|
11
14
|
|
|
12
15
|
```
|
|
13
16
|
src/
|
|
14
|
-
cli/ # CLI entry
|
|
15
|
-
core/
|
|
16
|
-
context/ # Frame management
|
|
17
|
-
database/ #
|
|
17
|
+
cli/ # CLI commands and entry point
|
|
18
|
+
core/
|
|
19
|
+
context/ # Frame and context management
|
|
20
|
+
database/ # Database adapters (SQLite, ParadeDB)
|
|
18
21
|
digest/ # Digest generation
|
|
19
|
-
query/ # Query routing
|
|
20
|
-
integrations/ # Linear, MCP
|
|
22
|
+
query/ # Query parsing and routing
|
|
23
|
+
integrations/ # External integrations (Linear, MCP)
|
|
21
24
|
services/ # Business services
|
|
22
25
|
skills/ # Claude Code skills
|
|
23
26
|
utils/ # Shared utilities
|
|
27
|
+
scripts/ # Build and utility scripts
|
|
28
|
+
config/ # Configuration files
|
|
29
|
+
docs/ # Documentation
|
|
24
30
|
```
|
|
25
31
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
**Quick reference** (agent_docs/):
|
|
29
|
-
- linear_integration.md
|
|
30
|
-
- mcp_server.md
|
|
31
|
-
- database_storage.md
|
|
32
|
-
- claude_hooks.md
|
|
33
|
-
|
|
34
|
-
**Full docs** (docs/):
|
|
35
|
-
- principles.md - Agent paradigm
|
|
36
|
-
- architecture.md - Extension model
|
|
37
|
-
- SPEC.md - Technical spec
|
|
38
|
-
- API_REFERENCE.md
|
|
39
|
-
- DEVELOPMENT.md
|
|
40
|
-
- SETUP.md
|
|
32
|
+
---
|
|
41
33
|
|
|
42
34
|
## Commands
|
|
43
35
|
|
|
44
36
|
```bash
|
|
45
37
|
# Build & Quality
|
|
46
|
-
npm run build # Compile (esbuild)
|
|
47
|
-
npm run lint #
|
|
48
|
-
npm run lint:fix # Auto-fix
|
|
49
|
-
npm test #
|
|
50
|
-
npm run test:run # Run once
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
#
|
|
56
|
-
stackmemory
|
|
57
|
-
stackmemory
|
|
38
|
+
npm run build # Compile TypeScript (esbuild)
|
|
39
|
+
npm run lint # ESLint check
|
|
40
|
+
npm run lint:fix # Auto-fix lint issues
|
|
41
|
+
npm test # Run Vitest (watch)
|
|
42
|
+
npm run test:run # Run tests once
|
|
43
|
+
npm run linear:sync # Sync with Linear
|
|
44
|
+
|
|
45
|
+
# StackMemory CLI
|
|
46
|
+
stackmemory capture # Save session state for handoff
|
|
47
|
+
stackmemory restore # Restore from captured state
|
|
48
|
+
stackmemory snapshot save # Post-run context snapshot (alias: snap)
|
|
49
|
+
stackmemory snapshot list # List recent snapshots
|
|
50
|
+
stackmemory preflight # File overlap check for parallel tasks (alias: pf)
|
|
51
|
+
stackmemory conductor start # Autonomous Linear→worktree→agent orchestrator
|
|
58
52
|
```
|
|
59
53
|
|
|
60
|
-
|
|
54
|
+
---
|
|
61
55
|
|
|
62
|
-
|
|
56
|
+
## Validation (MUST DO)
|
|
63
57
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
58
|
+
After every code change:
|
|
59
|
+
1. `npm run lint` — fix all errors AND warnings
|
|
60
|
+
2. `npm run test:run` — verify no regressions
|
|
61
|
+
3. `npm run build` — ensure compilation
|
|
62
|
+
4. Run the code to verify it works
|
|
68
63
|
|
|
69
|
-
**Test coverage
|
|
70
|
-
- New features require tests in `src/**/__tests__/`
|
|
71
|
-
- Maintain or improve coverage (no untested paths)
|
|
72
|
-
- Critical: context management, handoff, Linear sync
|
|
64
|
+
**Test coverage:** New features require tests in `src/**/__tests__/`. Maintain or improve coverage. Critical paths: context management, handoff, Linear sync.
|
|
73
65
|
|
|
74
|
-
|
|
66
|
+
Never: assume success · skip testing · use mock data as fallback
|
|
75
67
|
|
|
76
|
-
|
|
68
|
+
---
|
|
77
69
|
|
|
78
|
-
|
|
79
|
-
**Branch naming**: `feature/STA-XXX-desc` | `fix/STA-XXX-desc` | `chore/desc`
|
|
70
|
+
## Git Rules (CRITICAL)
|
|
80
71
|
|
|
81
|
-
|
|
82
|
-
-
|
|
83
|
-
- ALWAYS fix lint/test errors before pushing
|
|
72
|
+
- NEVER use `--no-verify` on git push or commit
|
|
73
|
+
- ALWAYS fix lint/test errors before pushing; if pre-push hooks fail, fix the issue
|
|
84
74
|
- Run `npm run lint && npm run test:run` before pushing
|
|
85
|
-
-
|
|
75
|
+
- Commit: `type(scope): message`
|
|
76
|
+
- Branch: `feature/STA-XXX-description` · `fix/STA-XXX-description` · `chore/description`
|
|
77
|
+
|
|
78
|
+
---
|
|
86
79
|
|
|
87
80
|
## Task Delegation Model
|
|
88
81
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
Normal workflow, lint+test+build:
|
|
99
|
-
- Features, bug fixes, refactoring
|
|
100
|
-
- Test coverage, documentation
|
|
101
|
-
- Integration wiring (server.ts dispatch)
|
|
102
|
-
|
|
103
|
-
### CAREFUL
|
|
104
|
-
Review approach before implementation:
|
|
105
|
-
- API/schema changes, database migrations, auth
|
|
106
|
-
- New integration patterns (MCP tools, webhooks)
|
|
107
|
-
- Changes to frame-manager, sqlite-adapter, daemon lifecycle
|
|
108
|
-
- Error handling chains
|
|
109
|
-
|
|
110
|
-
### ARCHITECT
|
|
111
|
-
Plan mode required, explore patterns first:
|
|
112
|
-
- New service boundaries, system integrations
|
|
113
|
-
- Performance-critical (FTS5 queries, search scoring)
|
|
114
|
-
- Breaking changes (MCP protocol, CLI interface)
|
|
115
|
-
|
|
116
|
-
### HUMAN
|
|
117
|
-
Explicit approval before changes:
|
|
118
|
-
- Security decisions, secret handling
|
|
119
|
-
- Irreversible operations (migrations, schema drops)
|
|
120
|
-
- Publishing (npm, Railway)
|
|
82
|
+
| Tier | When | Gates |
|
|
83
|
+
|------|------|-------|
|
|
84
|
+
| **AUTOMATE** | CRUD, boilerplate, config additions, simple switch/case handlers | lint + test |
|
|
85
|
+
| **STANDARD** | Features, bug fixes, refactoring, new tests, integration wiring | lint + test + build |
|
|
86
|
+
| **CAREFUL** | API/schema changes, DB migrations, auth, MCP tools, frame-manager/sqlite-adapter/daemon lifecycle | Review approach first |
|
|
87
|
+
| **ARCHITECT** | New service boundaries, FTS5/search perf, breaking MCP/CLI changes | Plan mode required |
|
|
88
|
+
| **HUMAN** | Security decisions, secret handling, irreversible ops, publishing | Explicit approval |
|
|
89
|
+
|
|
90
|
+
---
|
|
121
91
|
|
|
122
92
|
## Security
|
|
123
93
|
|
|
124
|
-
|
|
94
|
+
NEVER hardcode secrets — use `process.env` with dotenv/config:
|
|
125
95
|
|
|
126
96
|
```javascript
|
|
127
97
|
import 'dotenv/config';
|
|
128
98
|
const API_KEY = process.env.LINEAR_API_KEY;
|
|
129
|
-
if (!API_KEY) {
|
|
130
|
-
console.error('LINEAR_API_KEY not set');
|
|
131
|
-
process.exit(1);
|
|
132
|
-
}
|
|
99
|
+
if (!API_KEY) { console.error('LINEAR_API_KEY not set'); process.exit(1); }
|
|
133
100
|
```
|
|
134
101
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
3. ~/.zshrc
|
|
139
|
-
4. Process environment
|
|
102
|
+
Env lookup order: `.env` → `.env.local` → `~/.zshrc` → process env
|
|
103
|
+
|
|
104
|
+
Block patterns: `lin_api_*` · `lin_oauth_*` · `sk-*` · `npm_*`
|
|
140
105
|
|
|
141
|
-
|
|
106
|
+
---
|
|
142
107
|
|
|
143
|
-
##
|
|
108
|
+
## Deploy
|
|
144
109
|
|
|
145
110
|
```bash
|
|
146
|
-
# npm publish (uses NPM_TOKEN from .env, no OTP)
|
|
147
|
-
git stash -- scripts/gepa/ # stash GEPA state
|
|
111
|
+
# npm publish (uses NPM_TOKEN from .env, no OTP needed)
|
|
112
|
+
git stash -- scripts/gepa/ # stash GEPA state (dirties working tree)
|
|
148
113
|
NPM_TOKEN=$(grep '^NPM_TOKEN=' .env | cut -d= -f2) \
|
|
149
114
|
npm publish --registry https://registry.npmjs.org/ \
|
|
150
115
|
--//registry.npmjs.org/:_authToken="$NPM_TOKEN"
|
|
@@ -152,21 +117,22 @@ git stash pop # restore GEPA state
|
|
|
152
117
|
|
|
153
118
|
# Railway
|
|
154
119
|
railway up
|
|
155
|
-
|
|
156
|
-
# Note: Pre-publish checks require clean git status
|
|
157
120
|
```
|
|
158
121
|
|
|
159
|
-
|
|
122
|
+
Pre-publish checks require clean git status — stash GEPA files first.
|
|
160
123
|
|
|
161
|
-
|
|
162
|
-
- Keep one task in_progress at a time
|
|
163
|
-
- Update status immediately on completion
|
|
124
|
+
---
|
|
164
125
|
|
|
165
|
-
## Workflow
|
|
126
|
+
## Workflow
|
|
166
127
|
|
|
167
|
-
- Check
|
|
128
|
+
- Check `.env` for API keys before asking
|
|
129
|
+
- Review recent commits and `stackmemory.json` on session start
|
|
130
|
+
- Use subagents for multi-step tasks
|
|
168
131
|
- Run `npm run linear:sync` after task completion
|
|
169
132
|
- Use browser MCP for visual testing
|
|
170
|
-
-
|
|
171
|
-
|
|
172
|
-
|
|
133
|
+
- Ask 1–3 clarifying questions for complex commands (one at a time)
|
|
134
|
+
|
|
135
|
+
**Task management:** Use TodoWrite for 3+ steps. Keep one task `in_progress`. Update status immediately on completion.
|
|
136
|
+
|
|
137
|
+
**Working directory:** PRIMARY `/Users/jwu/Dev/stackmemory` · TEMP `/tmp`
|
|
138
|
+
```
|
|
@@ -6,25 +6,25 @@
|
|
|
6
6
|
"taskId": "eval-001",
|
|
7
7
|
"taskName": "simple_function",
|
|
8
8
|
"weight": 1,
|
|
9
|
-
"passed":
|
|
10
|
-
"passRate": 0,
|
|
9
|
+
"passed": true,
|
|
10
|
+
"passRate": 0.6666666666666666,
|
|
11
11
|
"criteria": {
|
|
12
12
|
"has_function": {
|
|
13
|
-
"passed":
|
|
14
|
-
"reason": "
|
|
13
|
+
"passed": true,
|
|
14
|
+
"reason": "A complete, working TypeScript function named isPalindrome is defined with proper syntax and logic"
|
|
15
15
|
},
|
|
16
16
|
"handles_edge_cases": {
|
|
17
|
-
"passed":
|
|
18
|
-
"reason": "
|
|
17
|
+
"passed": true,
|
|
18
|
+
"reason": "The function handles edge cases by converting to lowercase, removing non-alphanumeric characters with regex, and properly comparing the cleaned string with its reverse"
|
|
19
19
|
},
|
|
20
20
|
"is_tested": {
|
|
21
21
|
"passed": false,
|
|
22
|
-
"reason": "
|
|
22
|
+
"reason": "No test cases, test assertions, or test suite is provided in the output"
|
|
23
23
|
}
|
|
24
24
|
},
|
|
25
25
|
"judgeMode": "llm",
|
|
26
|
-
"duration":
|
|
27
|
-
"output": "
|
|
26
|
+
"duration": 7677,
|
|
27
|
+
"output": "```typescript\nfunction isPalindrome(s: string): boolean {\n const clean = s.toLowerCase().replace(/[^a-z0-9]/g, '');\n return clean === clean.split('').reverse().join('');\n}\n```\n"
|
|
28
28
|
},
|
|
29
29
|
{
|
|
30
30
|
"taskId": "eval-002",
|
|
@@ -35,20 +35,20 @@
|
|
|
35
35
|
"criteria": {
|
|
36
36
|
"uses_async": {
|
|
37
37
|
"passed": false,
|
|
38
|
-
"reason": "No async/await code
|
|
38
|
+
"reason": "No async/await code was provided. The output is a request for input rather than a refactored code example."
|
|
39
39
|
},
|
|
40
40
|
"preserves_behavior": {
|
|
41
41
|
"passed": false,
|
|
42
|
-
"reason": "No refactored code
|
|
42
|
+
"reason": "No refactored code was provided to verify that behavior is preserved."
|
|
43
43
|
},
|
|
44
44
|
"no_nested_callbacks": {
|
|
45
45
|
"passed": false,
|
|
46
|
-
"reason": "No code
|
|
46
|
+
"reason": "No refactored code was provided to demonstrate elimination of nested callbacks."
|
|
47
47
|
}
|
|
48
48
|
},
|
|
49
49
|
"judgeMode": "llm",
|
|
50
|
-
"duration":
|
|
51
|
-
"output": "
|
|
50
|
+
"duration": 8113,
|
|
51
|
+
"output": "Which file or code snippet would you like me to refactor? Please share the file path or paste the code.\n"
|
|
52
52
|
},
|
|
53
53
|
{
|
|
54
54
|
"taskId": "eval-003",
|
|
@@ -59,160 +59,160 @@
|
|
|
59
59
|
"criteria": {
|
|
60
60
|
"bug_fixed": {
|
|
61
61
|
"passed": false,
|
|
62
|
-
"reason": "No
|
|
62
|
+
"reason": "No code was provided to the AI, so no bug could be fixed. The AI correctly identified the missing input but did not fix any actual bug."
|
|
63
63
|
},
|
|
64
64
|
"no_new_bugs": {
|
|
65
65
|
"passed": true,
|
|
66
|
-
"reason": "
|
|
66
|
+
"reason": "The AI did not write any code, so no new bugs were introduced."
|
|
67
67
|
},
|
|
68
68
|
"explains_fix": {
|
|
69
69
|
"passed": false,
|
|
70
|
-
"reason": "No
|
|
70
|
+
"reason": "No fix was explained because no code was provided. The AI only asked for the code to be shared."
|
|
71
71
|
}
|
|
72
72
|
},
|
|
73
73
|
"judgeMode": "llm",
|
|
74
|
-
"duration":
|
|
75
|
-
"output": "I'
|
|
74
|
+
"duration": 8142,
|
|
75
|
+
"output": "I don't see any code or file provided. Could you share the code with the loop you'd like me to fix?\n"
|
|
76
76
|
},
|
|
77
77
|
{
|
|
78
78
|
"taskId": "eval-004",
|
|
79
79
|
"taskName": "add_feature",
|
|
80
80
|
"weight": 1.5,
|
|
81
81
|
"passed": false,
|
|
82
|
-
"passRate": 0
|
|
82
|
+
"passRate": 0,
|
|
83
83
|
"criteria": {
|
|
84
84
|
"has_pagination": {
|
|
85
|
-
"passed":
|
|
86
|
-
"reason": "
|
|
85
|
+
"passed": false,
|
|
86
|
+
"reason": "No pagination code is implemented. The AI only asks for clarification instead of providing a solution."
|
|
87
87
|
},
|
|
88
88
|
"has_limit": {
|
|
89
|
-
"passed":
|
|
90
|
-
"reason": "
|
|
89
|
+
"passed": false,
|
|
90
|
+
"reason": "No limit parameter is defined or implemented in the output."
|
|
91
91
|
},
|
|
92
92
|
"has_offset": {
|
|
93
93
|
"passed": false,
|
|
94
|
-
"reason": "
|
|
94
|
+
"reason": "No offset parameter is defined or implemented in the output."
|
|
95
95
|
},
|
|
96
96
|
"backwards_compatible": {
|
|
97
97
|
"passed": false,
|
|
98
|
-
"reason": "No
|
|
98
|
+
"reason": "No code is provided to evaluate backward compatibility. The output is a question, not an implementation."
|
|
99
99
|
}
|
|
100
100
|
},
|
|
101
101
|
"judgeMode": "llm",
|
|
102
|
-
"duration":
|
|
103
|
-
"output": "
|
|
102
|
+
"duration": 11208,
|
|
103
|
+
"output": "Which API endpoint should I add pagination to? Please share the file path or describe the endpoint.\n"
|
|
104
104
|
},
|
|
105
105
|
{
|
|
106
106
|
"taskId": "eval-005",
|
|
107
107
|
"taskName": "code_review",
|
|
108
108
|
"weight": 1.3,
|
|
109
|
-
"passed":
|
|
110
|
-
"passRate": 0
|
|
109
|
+
"passed": false,
|
|
110
|
+
"passRate": 0,
|
|
111
111
|
"criteria": {
|
|
112
112
|
"identifies_security_issue": {
|
|
113
|
-
"passed":
|
|
114
|
-
"reason": "The output
|
|
113
|
+
"passed": false,
|
|
114
|
+
"reason": "The AI output does not review any PR or identify any security issues. It only requests the PR details."
|
|
115
115
|
},
|
|
116
116
|
"identifies_performance_issue": {
|
|
117
117
|
"passed": false,
|
|
118
|
-
"reason": "The output does not
|
|
118
|
+
"reason": "The AI output does not review any PR or identify any performance issues. It only requests the PR details."
|
|
119
119
|
},
|
|
120
120
|
"actionable_feedback": {
|
|
121
|
-
"passed":
|
|
122
|
-
"reason": "The output provides
|
|
121
|
+
"passed": false,
|
|
122
|
+
"reason": "The AI output provides no feedback on code, only asks for a PR to review. No actionable suggestions are provided."
|
|
123
123
|
}
|
|
124
124
|
},
|
|
125
125
|
"judgeMode": "llm",
|
|
126
|
-
"duration":
|
|
127
|
-
"output": "
|
|
126
|
+
"duration": 12081,
|
|
127
|
+
"output": "Which PR would you like me to review? Please provide the PR number, URL, or branch name.\n"
|
|
128
128
|
},
|
|
129
129
|
{
|
|
130
130
|
"taskId": "sm-001",
|
|
131
131
|
"taskName": "add_mcp_tool_handler",
|
|
132
132
|
"weight": 1.5,
|
|
133
|
-
"passed":
|
|
134
|
-
"passRate":
|
|
133
|
+
"passed": true,
|
|
134
|
+
"passRate": 1,
|
|
135
135
|
"criteria": {
|
|
136
136
|
"has_switch_case": {
|
|
137
|
-
"passed":
|
|
138
|
-
"reason": "
|
|
137
|
+
"passed": true,
|
|
138
|
+
"reason": "Code includes a case statement 'get_frame_summary' within what appears to be a switch/case dispatch pattern"
|
|
139
139
|
},
|
|
140
140
|
"has_zod_schema": {
|
|
141
|
-
"passed":
|
|
142
|
-
"reason": "
|
|
141
|
+
"passed": true,
|
|
142
|
+
"reason": "Zod schema is defined inline: z.object({ frameId: z.string().min(1) })"
|
|
143
143
|
},
|
|
144
144
|
"validates_input": {
|
|
145
|
-
"passed":
|
|
146
|
-
"reason": "
|
|
145
|
+
"passed": true,
|
|
146
|
+
"reason": "Input validation occurs via z.object().parse(args), which will throw if validation fails"
|
|
147
147
|
},
|
|
148
148
|
"returns_typed_response": {
|
|
149
|
-
"passed":
|
|
150
|
-
"reason": "
|
|
149
|
+
"passed": true,
|
|
150
|
+
"reason": "Returns an object with all required fields: frameId, name, status, eventCount matching the specified return type"
|
|
151
151
|
},
|
|
152
152
|
"handles_not_found": {
|
|
153
|
-
"passed":
|
|
154
|
-
"reason": "
|
|
153
|
+
"passed": true,
|
|
154
|
+
"reason": "Code checks if frame exists and throws an error with descriptive message if not found"
|
|
155
155
|
}
|
|
156
156
|
},
|
|
157
157
|
"judgeMode": "llm",
|
|
158
|
-
"duration":
|
|
159
|
-
"output": "
|
|
158
|
+
"duration": 27658,
|
|
159
|
+
"output": "Please approve the file write to add the handler. The change replaces the `// TODO` comment with:\n\n```typescript\ncase 'get_frame_summary': {\n const input = z.object({ frameId: z.string().min(1) }).parse(args);\n const frame = frames.get(input.frameId);\n if (!frame) throw new Error(`Frame not found: ${input.frameId}`);\n return { frameId: frame.id, name: frame.name, status: frame.status, eventCount: frame.events.length };\n}\n```\n"
|
|
160
160
|
},
|
|
161
161
|
{
|
|
162
162
|
"taskId": "sm-002",
|
|
163
163
|
"taskName": "fix_fts5_trigger_bug",
|
|
164
164
|
"weight": 1.8,
|
|
165
|
-
"passed":
|
|
166
|
-
"passRate":
|
|
165
|
+
"passed": true,
|
|
166
|
+
"passRate": 1,
|
|
167
167
|
"criteria": {
|
|
168
168
|
"has_delete_trigger": {
|
|
169
|
-
"passed":
|
|
170
|
-
"reason": "
|
|
169
|
+
"passed": true,
|
|
170
|
+
"reason": "A DELETE trigger named 'frames_ad' is defined with AFTER DELETE ON frames syntax, creating an actual trigger that will execute on row deletion."
|
|
171
171
|
},
|
|
172
172
|
"uses_fts_delete_syntax": {
|
|
173
|
-
"passed":
|
|
174
|
-
"reason": "
|
|
173
|
+
"passed": true,
|
|
174
|
+
"reason": "The trigger uses the FTS5 external content delete syntax: INSERT INTO frames_fts with the special 'delete' command as the first value, which is the correct way to remove entries from an FTS5 index."
|
|
175
175
|
},
|
|
176
176
|
"references_old_row": {
|
|
177
|
-
"passed":
|
|
178
|
-
"reason": "
|
|
177
|
+
"passed": true,
|
|
178
|
+
"reason": "The trigger correctly references old.rowid, old.name, old.digest_text, and old.inputs, old.outputs to capture the deleted row's values before deletion."
|
|
179
179
|
},
|
|
180
180
|
"matches_column_list": {
|
|
181
|
-
"passed":
|
|
182
|
-
"reason": "The
|
|
181
|
+
"passed": true,
|
|
182
|
+
"reason": "The column list (name, digest_text, inputs, outputs) matches the FTS5 indexed columns and follows the same pattern as the existing INSERT and UPDATE triggers shown in the task description."
|
|
183
183
|
}
|
|
184
184
|
},
|
|
185
185
|
"judgeMode": "llm",
|
|
186
|
-
"duration":
|
|
187
|
-
"output": "
|
|
186
|
+
"duration": 28714,
|
|
187
|
+
"output": "Waiting for your approval to write to `fts5-triggers.sql`. The change replaces the bug comment with:\n\n```sql\n-- Sync trigger: DELETE\nCREATE TRIGGER IF NOT EXISTS frames_ad AFTER DELETE ON frames BEGIN\n INSERT INTO frames_fts(frames_fts, rowid, name, digest_text, inputs, outputs)\n VALUES ('delete', old.rowid, old.name, old.digest_text, old.inputs, old.outputs);\nEND;\n```\n\nThis follows the FTS5 external content pattern — the `'delete'` command removes the row from the index using the `old.*` values, matching the first half of the UPDATE trigger.\n"
|
|
188
188
|
},
|
|
189
189
|
{
|
|
190
190
|
"taskId": "sm-003",
|
|
191
191
|
"taskName": "daemon_service_lifecycle",
|
|
192
192
|
"weight": 1.5,
|
|
193
|
-
"passed":
|
|
194
|
-
"passRate":
|
|
193
|
+
"passed": true,
|
|
194
|
+
"passRate": 1,
|
|
195
195
|
"criteria": {
|
|
196
196
|
"clears_old_interval": {
|
|
197
|
-
"passed":
|
|
198
|
-
"reason": "The
|
|
197
|
+
"passed": true,
|
|
198
|
+
"reason": "The start() method includes `if (this.intervalId) { clearInterval(this.intervalId); this.intervalId = undefined; }` which explicitly clears any existing interval before creating a new one."
|
|
199
199
|
},
|
|
200
200
|
"prevents_double_start": {
|
|
201
201
|
"passed": true,
|
|
202
|
-
"reason": "The
|
|
202
|
+
"reason": "The guard in start() that clears the existing intervalId before creating a new one prevents the timer leak when start() is called while already running."
|
|
203
203
|
},
|
|
204
204
|
"has_getstate_method": {
|
|
205
|
-
"passed":
|
|
206
|
-
"reason": "
|
|
205
|
+
"passed": true,
|
|
206
|
+
"reason": "A getState() method is defined that returns a ServiceState object with the required properties."
|
|
207
207
|
},
|
|
208
208
|
"returns_correct_state_shape": {
|
|
209
|
-
"passed":
|
|
210
|
-
"reason": "
|
|
209
|
+
"passed": true,
|
|
210
|
+
"reason": "The getState() method returns an object with all four required properties: isRunning, intervalMs (calculated correctly), lastRunTime, and errorCount."
|
|
211
211
|
}
|
|
212
212
|
},
|
|
213
213
|
"judgeMode": "llm",
|
|
214
|
-
"duration":
|
|
215
|
-
"output": "
|
|
214
|
+
"duration": 38931,
|
|
215
|
+
"output": "It seems write permission hasn't been granted. Please approve the file write when prompted, then I can apply both changes. Here's exactly what I'll do:\n\n**Fix 1 — `start()` guard** (lines 25-37): Clear any existing interval before creating a new one, removing the stale comment:\n\n```ts\nstart(): void {\n if (this.intervalId) {\n clearInterval(this.intervalId);\n this.intervalId = undefined;\n }\n this.isRunning = true;\n const intervalMs = this.config.interval * 60 * 1000;\n\n this.doWork(); // initial run\n\n this.intervalId = setInterval(() => {\n this.doWork();\n }, intervalMs);\n}\n```\n\nThis fixes both the double-`start()` leak and `updateConfig()`'s stop→start path — `stop()` already clears `intervalId`, but now `start()` is also safe if called directly while running.\n\n**Fix 2 — remove stale `updateConfig` comment + add `getState()`** (lines 47-57):\n\n```ts\nupdateConfig(config: Partial<ServiceConfig>): void {\n const wasRunning = this.isRunning;\n if (wasRunning) this.stop();\n this.config = { ...this.config, ...config };\n if (wasRunning && this.config.enabled) this.start();\n}\n\ngetState(): ServiceState {\n return {\n isRunning: this.isRunning,\n intervalMs: this.config.interval * 60 * 1000,\n lastRunTime: this.lastRunTime,\n errorCount: this.errorCount,\n };\n}\n```\n\nOnce you grant write access I'll apply both edits. The root fix is in `start()` — making it idempotent means `updateConfig()` is also correct regardless of `stop()`'s state.\n"
|
|
216
216
|
}
|
|
217
217
|
]
|
|
218
218
|
}
|