Skip to content

Commit 260085c

Browse files
author
StackMemory Bot (CLI)
committed
feat(cli): add skill subcommand for knowledge skill management
New `stackmemory skill` command for managing .skill.md knowledge files: - list: discover skills from global + project dirs - match: keyword-match skills against a prompt - show: display full skill content - add: install from local file or URL - refresh: check freshness, flag expired skills - init: scaffold new .skill.md with template
1 parent f2e806b commit 260085c

7 files changed

Lines changed: 855 additions & 0 deletions

File tree

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
---
2+
name: better-sqlite3
3+
version: 2025.12.1
4+
domain: database
5+
expires: 2026-12-01
6+
activates_on: [sqlite, better-sqlite3, database, db, query, fts, fts5, pragma, wal, transaction]
7+
sources:
8+
- https://github.com/WiseLibs/better-sqlite3/blob/master/docs/api.md
9+
context7: WiseLibs/better-sqlite3
10+
---
11+
12+
# better-sqlite3
13+
14+
## Basics
15+
- Open: `new Database(path)` or `new Database(':memory:')`
16+
- **Synchronous API** — no async/await, no callbacks
17+
- Prepare + run: `db.prepare('SELECT * FROM t WHERE id = ?').get(id)`
18+
- All rows: `.all(params)` | Single row: `.get(params)` | Execute: `.run(params)`
19+
- Params: positional `?` or named `$name` / `:name` / `@name`
20+
21+
## Transactions
22+
```js
23+
const insert = db.prepare('INSERT INTO t (a, b) VALUES (?, ?)');
24+
const insertMany = db.transaction((items) => {
25+
for (const item of items) insert.run(item.a, item.b);
26+
});
27+
insertMany(items); // atomic, auto-rollback on error
28+
```
29+
- `db.transaction()` returns a reusable function — best pattern for batch ops
30+
- Nested transactions: use `.deferred()`, `.immediate()`, `.exclusive()`
31+
32+
## FTS5 (Full-Text Search)
33+
- Create: `CREATE VIRTUAL TABLE t_fts USING fts5(content, tokenize='porter unicode61')`
34+
- Search: `SELECT * FROM t_fts WHERE t_fts MATCH 'query'`
35+
- Rank: `SELECT *, rank FROM t_fts WHERE t_fts MATCH 'query' ORDER BY rank`
36+
- BM25: `SELECT *, bm25(t_fts) as score FROM t_fts WHERE t_fts MATCH ?`
37+
- Highlight: `highlight(t_fts, 0, '<b>', '</b>')`
38+
39+
## WAL Mode
40+
- Enable: `db.pragma('journal_mode = WAL')` — concurrent reads, single writer
41+
- Always enable for production — significant performance improvement
42+
- `db.pragma('busy_timeout = 5000')` — wait up to 5s for write lock
43+
44+
## Performance
45+
- `db.pragma('cache_size = -64000')` — 64MB cache
46+
- `db.pragma('synchronous = NORMAL')` — faster writes (WAL mode safe)
47+
- `db.prepare()` caches the statement plan — reuse prepared statements
48+
- Batch inserts: always wrap in `db.transaction()` — 100x faster than individual inserts
49+
50+
## ESM Import
51+
- CJS native addon: `import Database from 'better-sqlite3'`
52+
- Mark as `external` in esbuild — can't bundle native `.node` files
53+
- Prebuilt binaries: `npm install` downloads correct platform binary
54+
55+
## Gotchas
56+
- Synchronous — blocks event loop on large queries; use worker_threads for heavy ops
57+
- `.get()` returns `undefined` if no row (not `null`)
58+
- `.run()` returns `{ changes, lastInsertRowid }` — not the row itself
59+
- Column names are case-sensitive in result objects
60+
- VACUUM: locks entire DB — run during maintenance windows only
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
---
2+
name: commander-cli
3+
version: 2025.12.1
4+
domain: cli
5+
expires: 2026-12-01
6+
activates_on: [commander, cli, command, option, argument, subcommand, parse, program, action]
7+
sources:
8+
- https://github.com/tj/commander.js#readme
9+
context7: tj/commander.js
10+
---
11+
12+
# Commander.js CLI Framework
13+
14+
## Basic Setup
15+
```ts
16+
import { Command } from 'commander';
17+
const program = new Command();
18+
program
19+
.name('mycli')
20+
.version('1.0.0')
21+
.description('description');
22+
```
23+
24+
## Commands
25+
```ts
26+
program
27+
.command('serve')
28+
.description('Start server')
29+
.option('-p, --port <number>', 'port', '3000')
30+
.option('-v, --verbose', 'verbose output')
31+
.argument('<dir>', 'directory to serve')
32+
.action((dir, options) => {
33+
console.log(dir, options.port, options.verbose);
34+
});
35+
```
36+
37+
## Subcommands
38+
```ts
39+
const parent = program.command('db');
40+
parent.command('migrate').action(() => { ... });
41+
parent.command('seed').action(() => { ... });
42+
// Usage: mycli db migrate
43+
```
44+
45+
## Options
46+
- Required value: `-p, --port <number>` (angle brackets)
47+
- Optional value: `-p, --port [number]` (square brackets)
48+
- Boolean flag: `-v, --verbose` (no value)
49+
- Variadic: `-f, --files <items...>` (collects into array)
50+
- Default: `.option('-p, --port <n>', 'desc', '3000')`
51+
- Choices: `.addOption(new Option('--env <e>').choices(['dev', 'prod']))`
52+
- Negatable: `--no-color` (sets `options.color = false`)
53+
54+
## Patterns for This Project
55+
- 70+ commands — use subcommand groups (`skill`, `frame`, `session`, `linear`, etc.)
56+
- Action handlers: async functions with try/catch + `process.exit(1)` on error
57+
- Global options: define on `program` before subcommands
58+
- Help: auto-generated — add `.addHelpText('after', text)` for examples
59+
60+
## Gotchas
61+
- Option values are strings by default — parse with `.argParser(parseInt)` or coerce in action
62+
- `program.parse()` must be called last (or `program.parseAsync()` for async actions)
63+
- `.command('*')` for catch-all unknown commands
64+
- Negative options: `--no-foo` creates `options.foo = false` — conflicts if `--foo` also defined
65+
- ESM: Commander works fine, but ensure `#!/usr/bin/env node` in bin entry
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
---
2+
name: esbuild-esm
3+
version: 2025.12.1
4+
domain: build
5+
expires: 2026-12-01
6+
activates_on: [esbuild, build, bundle, esm, import, export, module, cjs, commonjs, dist, entry]
7+
sources:
8+
- https://esbuild.github.io/api/
9+
- https://nodejs.org/api/esm.html
10+
context7: evanw/esbuild
11+
---
12+
13+
# esbuild + ESM
14+
15+
## esbuild Config
16+
- Entry: `esbuild.build({ entryPoints, bundle, platform, format, outdir })`
17+
- Platform: `'node'` for CLI tools (excludes node builtins from bundle)
18+
- Format: `'esm'` — this project is ESM-first (`"type": "module"` in package.json)
19+
- External: mark `better-sqlite3`, native addons as external (can't bundle .node files)
20+
- Sourcemaps: `sourcemap: true` for debugging
21+
22+
## ESM Rules (Node.js)
23+
- **Always** add `.js` extension to relative imports: `import { foo } from './bar.js'`
24+
- `__dirname` / `__filename` not available — use `import.meta.url` + `fileURLToPath()`
25+
- `require()` not available — use `createRequire(import.meta.url)` for CJS interop
26+
- Top-level `await` works in ESM
27+
- JSON imports: `import data from './file.json' with { type: 'json' }` (or createRequire)
28+
29+
## CJS Interop
30+
- Import CJS from ESM: default import works (`import pkg from 'cjs-pkg'`)
31+
- Named exports: may need `import pkg from 'pkg'; const { named } = pkg;`
32+
- `better-sqlite3`: CJS native addon — import as default, mark external in esbuild
33+
34+
## Package.json
35+
- `"type": "module"` — all .js files are ESM
36+
- `"exports"` field for package entry points (not just "main")
37+
- `"bin"` field for CLI executables — ensure shebang `#!/usr/bin/env node`
38+
39+
## Gotchas
40+
- Missing `.js` extension → `ERR_MODULE_NOT_FOUND` (most common error)
41+
- esbuild `bundle: true` inlines deps — use `external` for native modules
42+
- `--packages=external` excludes all node_modules (useful for dev builds)
43+
- Watch mode: `esbuild.context().then(ctx => ctx.watch())` — not `--watch` flag in API
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
---
2+
name: mcp-protocol
3+
version: 2025.12.1
4+
domain: protocol
5+
expires: 2026-06-01
6+
activates_on: [mcp, model context protocol, tool, resource, prompt, server, transport, stdio, sse, streamable]
7+
sources:
8+
- https://modelcontextprotocol.io/docs
9+
- https://github.com/modelcontextprotocol/typescript-sdk
10+
context7: modelcontextprotocol/typescript-sdk
11+
---
12+
13+
# Model Context Protocol (MCP)
14+
15+
## SDK (@modelcontextprotocol/sdk)
16+
```ts
17+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
18+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
19+
20+
const server = new McpServer({ name: 'my-server', version: '1.0.0' });
21+
```
22+
23+
## Tools
24+
```ts
25+
server.tool('tool_name', 'description', {
26+
param: z.string().describe('param description'), // Zod schema
27+
}, async ({ param }) => {
28+
return { content: [{ type: 'text', text: result }] };
29+
});
30+
```
31+
- Input schema: Zod objects auto-converted to JSON Schema
32+
- Return: `{ content: [{ type: 'text' | 'image' | 'resource', ... }] }`
33+
- Error: `{ isError: true, content: [{ type: 'text', text: errorMsg }] }`
34+
35+
## Resources
36+
```ts
37+
server.resource('resource://uri', 'description', async (uri) => {
38+
return { contents: [{ uri, mimeType: 'text/plain', text: data }] };
39+
});
40+
```
41+
- Static URI or template: `resource://users/{id}`
42+
- `list_changed` notification when resources update
43+
44+
## Transports
45+
- **Stdio**: `StdioServerTransport` — for CLI-launched servers (Claude Code default)
46+
- **Streamable HTTP**: `StreamableHTTPServerTransport` — for networked servers
47+
- **SSE** (deprecated): use Streamable HTTP instead for new servers
48+
49+
## Prompts
50+
```ts
51+
server.prompt('prompt_name', 'description', { arg: z.string() }, ({ arg }) => {
52+
return { messages: [{ role: 'user', content: { type: 'text', text: `...${arg}...` } }] };
53+
});
54+
```
55+
56+
## Client Side
57+
```ts
58+
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
59+
const client = new Client({ name: 'my-client', version: '1.0.0' });
60+
await client.connect(transport);
61+
const result = await client.callTool({ name: 'tool_name', arguments: { param: 'value' } });
62+
```
63+
64+
## Gotchas
65+
- Tool names: snake_case convention (not camelCase)
66+
- Stdio transport: server MUST NOT write to stdout except MCP messages (use stderr for logs)
67+
- Zod schemas: `.describe()` on each field — LLMs use descriptions for tool calling
68+
- Error handling: return error content, don't throw (throws crash the server)
69+
- Transport cleanup: `await server.close()` on shutdown
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
---
2+
name: vitest
3+
version: 2025.12.1
4+
domain: testing
5+
expires: 2026-12-01
6+
activates_on: [vitest, test, spec, mock, spy, describe, it, expect, vi, beforeEach, coverage]
7+
sources:
8+
- https://vitest.dev/api/
9+
- https://vitest.dev/guide/mocking
10+
context7: vitest-dev/vitest
11+
---
12+
13+
# Vitest
14+
15+
## Config (this project)
16+
- Projects: unit, integration, live (API), bench
17+
- Coverage: v8 provider, thresholds: 25% statements, 20% branches, 30% functions
18+
- ESM native — no transform needed (unlike Jest + SWC)
19+
20+
## API (differs from Jest)
21+
- Mock function: `vi.fn()` (not `jest.fn()`)
22+
- Mock module: `vi.mock('./module')` — hoisted like Jest
23+
- Spy: `vi.spyOn(obj, 'method')`
24+
- Timers: `vi.useFakeTimers()` / `vi.advanceTimersByTime(ms)`
25+
- Clear: `vi.clearAllMocks()` / `vi.resetAllMocks()` / `vi.restoreAllMocks()`
26+
- Snapshot: `expect(val).toMatchSnapshot()` — same as Jest
27+
28+
## Mock Patterns
29+
```ts
30+
vi.mock('./dep.js', () => ({
31+
myFn: vi.fn().mockReturnValue('mocked'),
32+
}));
33+
34+
// Reset per test
35+
beforeEach(() => {
36+
vi.clearAllMocks();
37+
// re-set implementations after clear
38+
});
39+
```
40+
41+
## Inline vs Config Mocks
42+
- `vi.mock()` in test file — hoisted, file-scoped
43+
- `__mocks__/` directory — auto-mock (same as Jest convention)
44+
- `vi.hoisted()` — declare variables used in `vi.mock()` factory
45+
46+
## Key Differences from Jest
47+
- `vi` namespace instead of `jest` global
48+
- Native ESM — no `.js` extension issues in tests
49+
- `vi.stubEnv('KEY', 'val')` for env vars (cleaner than `process.env` mutation)
50+
- `--reporter=verbose` for detailed output
51+
- `vitest bench` for benchmarks (built-in, not separate tool)
52+
53+
## Gotchas
54+
- `vi.mock()` factory can't reference outer variables unless via `vi.hoisted()`
55+
- `vi.clearAllMocks()` resets calls + implementations (same gotcha as Jest)
56+
- `--pool=forks` vs `--pool=threads` — forks for better isolation, threads for speed
57+
- SQLite tests: use `:memory:` or temp file, not shared DB (parallel execution)

0 commit comments

Comments
 (0)