@stackmemoryai/stackmemory 1.2.1 → 1.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/cli/commands/skills.js +123 -1
- package/dist/src/hooks/graphiti-hooks.js +149 -0
- package/dist/src/hooks/session-summary.js +30 -0
- package/dist/src/integrations/graphiti/linear-graphiti-bridge.js +115 -0
- package/dist/src/integrations/greptile/client.js +101 -0
- package/dist/src/integrations/greptile/config.js +14 -0
- package/dist/src/integrations/greptile/index.js +11 -0
- package/dist/src/integrations/greptile/types.js +4 -0
- package/dist/src/integrations/linear/webhook.js +16 -0
- package/dist/src/integrations/mcp/handlers/greptile-handlers.js +456 -0
- package/dist/src/integrations/mcp/server.js +27 -0
- package/dist/src/skills/claude-skills.js +46 -1
- package/dist/src/skills/parallel-agent-skill.js +514 -0
- package/package.json +1 -1
- package/scripts/gepa/.before-optimize.md +140 -159
- package/scripts/gepa/config.json +7 -1
- package/scripts/gepa/evals/fixtures/api-endpoint.ts +31 -0
- package/scripts/gepa/evals/fixtures/brittle-integration.ts +38 -0
- package/scripts/gepa/evals/fixtures/fts5-triggers.sql +23 -0
- package/scripts/gepa/evals/fixtures/leaky-service.ts +70 -0
- package/scripts/gepa/evals/fixtures/mcp-dispatch-stub.ts +39 -0
- package/scripts/gepa/evals/fixtures/pr-diff.txt +24 -0
- package/scripts/gepa/evals/fixtures/unsafe-webhook.ts +34 -0
- package/scripts/gepa/evals/fixtures/unwrapped-db-op.ts +42 -0
- package/scripts/gepa/evals/stackmemory-tasks.jsonl +8 -0
- package/scripts/gepa/generations/gen-000/baseline.md +172 -159
- package/scripts/gepa/generations/gen-001/baseline.md +172 -159
- package/scripts/gepa/generations/gen-001/variant-a.md +156 -146
- package/scripts/gepa/generations/gen-001/variant-b.md +199 -170
- package/scripts/gepa/generations/gen-001/variant-c.md +127 -46
- package/scripts/gepa/generations/gen-001/variant-d.md +160 -107
- package/scripts/gepa/hooks/reflect.js +44 -5
- package/scripts/gepa/optimize.js +281 -39
- package/scripts/gepa/results/eval-1-baseline.json +187 -10
- package/scripts/gepa/results/eval-1-variant-a.json +188 -11
- package/scripts/gepa/results/eval-1-variant-b.json +188 -11
- package/scripts/gepa/results/eval-1-variant-c.json +168 -11
- package/scripts/gepa/results/eval-1-variant-d.json +169 -12
- package/scripts/gepa/state.json +18 -18
|
@@ -1,119 +1,172 @@
|
|
|
1
|
-
#
|
|
1
|
+
# StackMemory - Project Configuration
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
StackMemory is an agent programming platform with CLI, MCP server, and Linear integration.
|
|
6
|
+
|
|
7
|
+
**Primary**: /Users/jwu/Dev/stackmemory
|
|
8
|
+
**Tech**: TypeScript, Node.js, SQLite, Vitest, ESLint, esbuild
|
|
9
|
+
|
|
10
|
+
## Architecture
|
|
2
11
|
|
|
3
|
-
## Quick Reference
|
|
4
12
|
```
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
13
|
+
src/
|
|
14
|
+
cli/ # CLI entry (index.ts)
|
|
15
|
+
core/ # Business logic
|
|
16
|
+
context/ # Frame management (frame-manager.ts)
|
|
17
|
+
database/ # Storage adapters (sqlite-adapter.ts)
|
|
18
|
+
digest/ # Digest generation
|
|
19
|
+
query/ # Query routing
|
|
20
|
+
integrations/ # Linear, MCP (mcp/server.ts)
|
|
21
|
+
services/ # Business services
|
|
22
|
+
skills/ # Claude Code skills
|
|
23
|
+
utils/ # Shared utilities
|
|
14
24
|
```
|
|
15
25
|
|
|
16
|
-
##
|
|
26
|
+
## Documentation
|
|
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
|
|
41
|
+
|
|
42
|
+
## Commands
|
|
43
|
+
|
|
17
44
|
```bash
|
|
18
|
-
#
|
|
19
|
-
npm run
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
45
|
+
# Build & Quality
|
|
46
|
+
npm run build # Compile (esbuild)
|
|
47
|
+
npm run lint # Check
|
|
48
|
+
npm run lint:fix # Auto-fix
|
|
49
|
+
npm test # Watch mode
|
|
50
|
+
npm run test:run # Run once
|
|
23
51
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
**Security**: NEVER commit secrets|exec untrusted|expose PII|force push
|
|
27
|
-
ALWAYS validate input|parameterized queries|hash passwords
|
|
28
|
-
BLOCK ~/.ssh|~/.aws|/api[_-]?key|token|secret/i
|
|
29
|
-
**ESM**: add .js to relative imports | use ts-node-lint-fixer on ERR_MODULE_NOT_FOUND
|
|
30
|
-
**Reliability**: return undefined>throw | log+continue>crash | filter nulls
|
|
31
|
-
**Style**: no emojis | comments only for complex logic | short names | concise output
|
|
32
|
-
|
|
33
|
-
## Workflow [H:8-9]
|
|
34
|
-
**Tasks**: TodoWrite for 3+ steps | one in_progress | update immediately
|
|
35
|
-
**Files**: read before write | edit>write | no docs unless asked
|
|
36
|
-
**Git**: status→branch→fetch→pull --rebase | clean commits | type(scope): message
|
|
37
|
-
Branches: feature/|fix/|chore/ prefix
|
|
38
|
-
NO Co-Authored-By lines
|
|
39
|
-
**Validate**: lint→test→build→run | never assume success | maintain test coverage
|
|
40
|
-
**Parallel**: independent tool calls in one message | sequential only for dependencies
|
|
41
|
-
**Recovery**: try alt→explain→suggest | never silent fail
|
|
52
|
+
# Integration
|
|
53
|
+
npm run linear:sync # Sync Linear
|
|
42
54
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
**Patterns**: DI via deps objects | Mock providers in tests | Bull queues | AES-256-GCM KMS
|
|
47
|
-
**Provenance**: every data point = source + timestamp + lineage | multi-tenant isolation
|
|
48
|
-
**SSE**: adapter.streamLLM() → query/stream → frontend ReadableStream
|
|
49
|
-
**Graph**: optional graphService in query router (null when GRAPHITI_URL unset)
|
|
50
|
-
|
|
51
|
-
## Standards [H:8]
|
|
52
|
-
**Design**: KISS|YAGNI|SOLID | <20 lines/fn | <5 complexity
|
|
53
|
-
**Testing**: Jest+SWC | @jest/globals imports | DB/fetch mocks via DI
|
|
54
|
-
Supertest: pass Express app (NOT server)
|
|
55
|
-
Redis: skip connect in NODE_ENV=test
|
|
56
|
-
afterAll: Promise.race + .unref() timer
|
|
57
|
-
Parallel suites: test:unit|test:core|test:integrations (~9s vs 18s)
|
|
58
|
-
**After code changes**: run targeted sub-suite in background
|
|
59
|
-
**Coverage**: maintain or improve | no untested paths
|
|
60
|
-
|
|
61
|
-
## Key Context
|
|
62
|
-
- All 20 PROMPT_PLAN.md prompts complete | 80 suites, 1547 tests passing
|
|
63
|
-
- KG: FalkorDB port 6380 + Graphiti MCP port 8100 | MCP protocol (not REST)
|
|
64
|
-
- @provenantai/cli@1.0.0 published | Railway deployed | Bundle: 236KB+346KB
|
|
65
|
-
- Stripe: Growth (prod_TyNYCJmlKbMdlz) $1499/mo | Scale (prod_TyNY5SGKvVlbpo) $4499/mo
|
|
66
|
-
- Clerk: test keys active | production validator: scripts/setup-clerk-production.sh
|
|
67
|
-
- Dashboard: /app/ base | SSE to /api/v1/query | Sidebar in localStorage
|
|
68
|
-
- Slack: OAuth v2 (migration 030) | delivery.js listens nudge:created | demo: seed-demo-data.js
|
|
69
|
-
|
|
70
|
-
## Key Files
|
|
71
|
-
```
|
|
72
|
-
src/graph/{client.ts,service.ts} # MCP client + graph logic
|
|
73
|
-
src/llm/adapter.js # SYSTEM_PROMPT + streaming
|
|
74
|
-
src/routes/query.js # Query + KG enrichment
|
|
75
|
-
src/auth/auth.middleware.js # Clerk + API key + test mode
|
|
76
|
-
src/nudge/{rule-engine,nudge-engine,delivery}.js # Rules + lifecycle + Slack
|
|
77
|
-
src/integrations/slack/app.js # OAuth v2 + token mgmt
|
|
78
|
-
scripts/{create-stripe-products,seed-demo-data}.js
|
|
79
|
-
dashboard-app/src/pages/{pricing/PricingPage,checkout/*}.tsx
|
|
80
|
-
docs/content/{linkedin-pillar1-drafts,gtm-launch-materials}.md
|
|
81
|
-
docs/business/{CONTENT_INBOUND_STRATEGY,FRACTIONAL_CMO_AGENT}.md
|
|
55
|
+
# CLI
|
|
56
|
+
stackmemory capture # Save session state
|
|
57
|
+
stackmemory restore # Restore session
|
|
82
58
|
```
|
|
83
59
|
|
|
84
|
-
##
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
60
|
+
## Validation Checklist
|
|
61
|
+
|
|
62
|
+
After EVERY code change:
|
|
63
|
+
|
|
64
|
+
1. **Lint**: `npm run lint` - fix ALL errors AND warnings
|
|
65
|
+
2. **Test**: `npm run test:run` - verify no regressions
|
|
66
|
+
3. **Build**: `npm run build` - ensure compilation
|
|
67
|
+
4. **Run**: Execute code to verify functionality
|
|
68
|
+
|
|
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
|
|
73
|
+
|
|
74
|
+
**Never**: Assume success | Skip testing | Use mock fallbacks
|
|
75
|
+
|
|
76
|
+
## Git Workflow
|
|
77
|
+
|
|
78
|
+
**Commit format**: `type(scope): message`
|
|
79
|
+
**Branch naming**: `feature/STA-XXX-desc` | `fix/STA-XXX-desc` | `chore/desc`
|
|
80
|
+
|
|
81
|
+
**Critical rules**:
|
|
82
|
+
- NEVER use `--no-verify` on commit/push
|
|
83
|
+
- ALWAYS fix lint/test errors before pushing
|
|
84
|
+
- Run `npm run lint && npm run test:run` before pushing
|
|
85
|
+
- If pre-push hooks fail, fix the underlying issue
|
|
86
|
+
|
|
87
|
+
## Task Delegation Model
|
|
89
88
|
|
|
90
|
-
|
|
91
|
-
|
|
89
|
+
Route effort by complexity:
|
|
90
|
+
|
|
91
|
+
### AUTOMATE
|
|
92
|
+
Execute immediately, lint+test is sufficient:
|
|
93
|
+
- CRUD, boilerplate, formatting, simple transforms
|
|
94
|
+
- Tool handler following existing switch/case
|
|
95
|
+
- Config additions (env var, feature flag)
|
|
96
|
+
|
|
97
|
+
### STANDARD
|
|
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)
|
|
121
|
+
|
|
122
|
+
## Security
|
|
123
|
+
|
|
124
|
+
**NEVER hardcode secrets** - use process.env with dotenv/config:
|
|
125
|
+
|
|
126
|
+
```javascript
|
|
127
|
+
import 'dotenv/config';
|
|
128
|
+
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
|
+
}
|
|
92
133
|
```
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
134
|
+
|
|
135
|
+
**Env sources** (check in order):
|
|
136
|
+
1. .env file
|
|
137
|
+
2. .env.local
|
|
138
|
+
3. ~/.zshrc
|
|
139
|
+
4. Process environment
|
|
140
|
+
|
|
141
|
+
**Block patterns**: lin_api_* | lin_oauth_* | sk-* | npm_*
|
|
142
|
+
|
|
143
|
+
## Deployment
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
# npm publish (uses NPM_TOKEN from .env, no OTP)
|
|
147
|
+
git stash -- scripts/gepa/ # stash GEPA state
|
|
148
|
+
NPM_TOKEN=$(grep '^NPM_TOKEN=' .env | cut -d= -f2) \
|
|
149
|
+
npm publish --registry https://registry.npmjs.org/ \
|
|
150
|
+
--//registry.npmjs.org/:_authToken="$NPM_TOKEN"
|
|
151
|
+
git stash pop # restore GEPA state
|
|
152
|
+
|
|
153
|
+
# Railway
|
|
154
|
+
railway up
|
|
155
|
+
|
|
156
|
+
# Note: Pre-publish checks require clean git status
|
|
96
157
|
```
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
- Commit uncommitted agent work (SlackSettings, Nudges polish, smoke tests)
|
|
113
|
-
- Clerk: swap to production keys (user action in dashboard)
|
|
114
|
-
- Slack: create app at api.slack.com, run migration 030
|
|
115
|
-
- Content: schedule pillar posts in Typefully, record Loom demo
|
|
116
|
-
- Design partners: outreach to 3-5 ICP companies
|
|
117
|
-
- Ad platform connectors: Google Ads / Meta for attribution story
|
|
118
|
-
|
|
119
|
-
<!-- Update docs/reference/PROJECT.md when verbose docs change -->
|
|
158
|
+
|
|
159
|
+
## Task Management
|
|
160
|
+
|
|
161
|
+
- Use TodoWrite for 3+ steps or multiple requests
|
|
162
|
+
- Keep one task in_progress at a time
|
|
163
|
+
- Update status immediately on completion
|
|
164
|
+
|
|
165
|
+
## Workflow Tips
|
|
166
|
+
|
|
167
|
+
- Check .env for API keys before asking
|
|
168
|
+
- Run `npm run linear:sync` after task completion
|
|
169
|
+
- Use browser MCP for visual testing
|
|
170
|
+
- Review recent commits and stackmemory.json on session start
|
|
171
|
+
- Use subagents for multi-step tasks
|
|
172
|
+
- Ask 1-3 clarifying questions for complex commands (one at a time)
|
|
@@ -9,9 +9,51 @@
|
|
|
9
9
|
import fs from 'fs';
|
|
10
10
|
import path from 'path';
|
|
11
11
|
import { fileURLToPath } from 'url';
|
|
12
|
-
import {
|
|
12
|
+
import { spawn } from 'child_process';
|
|
13
13
|
|
|
14
14
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
15
|
+
const PROJECT_ROOT = path.resolve(__dirname, '../../..');
|
|
16
|
+
|
|
17
|
+
// Load .env from project root
|
|
18
|
+
const envPath = path.join(PROJECT_ROOT, '.env');
|
|
19
|
+
if (fs.existsSync(envPath)) {
|
|
20
|
+
for (const line of fs.readFileSync(envPath, 'utf8').split('\n')) {
|
|
21
|
+
const match = line.match(/^([A-Z_][A-Z0-9_]*)=(.*)$/);
|
|
22
|
+
if (match && !process.env[match[1]]) {
|
|
23
|
+
process.env[match[1]] = match[2].replace(/^["']|["']$/g, '');
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Call Claude CLI via spawn (stdin pipe, no shell interpolation)
|
|
30
|
+
*/
|
|
31
|
+
function spawnClaude(prompt) {
|
|
32
|
+
return new Promise((resolve, reject) => {
|
|
33
|
+
const child = spawn('claude', ['--print'], {
|
|
34
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
35
|
+
env: { ...process.env },
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
let stdout = '';
|
|
39
|
+
let stderr = '';
|
|
40
|
+
|
|
41
|
+
child.stdout.on('data', (d) => (stdout += d));
|
|
42
|
+
child.stderr.on('data', (d) => (stderr += d));
|
|
43
|
+
|
|
44
|
+
child.on('close', (code) => {
|
|
45
|
+
if (code !== 0 && !stdout)
|
|
46
|
+
return reject(new Error(stderr || `claude exited ${code}`));
|
|
47
|
+
resolve(stdout);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
child.on('error', reject);
|
|
51
|
+
|
|
52
|
+
child.stdin.write(prompt);
|
|
53
|
+
child.stdin.end();
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
|
|
15
57
|
const GEPA_DIR = path.join(__dirname, '..');
|
|
16
58
|
const RESULTS_DIR = path.join(GEPA_DIR, 'results');
|
|
17
59
|
const GENERATIONS_DIR = path.join(GEPA_DIR, 'generations');
|
|
@@ -212,10 +254,7 @@ Format as JSON:
|
|
|
212
254
|
}`;
|
|
213
255
|
|
|
214
256
|
try {
|
|
215
|
-
const result =
|
|
216
|
-
`echo ${JSON.stringify(reflectionPrompt)} | claude --print`,
|
|
217
|
-
{ encoding: 'utf8', maxBuffer: 10 * 1024 * 1024 }
|
|
218
|
-
);
|
|
257
|
+
const result = await spawnClaude(reflectionPrompt);
|
|
219
258
|
|
|
220
259
|
// Parse JSON from response
|
|
221
260
|
const jsonMatch = result.match(/\{[\s\S]*\}/);
|