@gobing-ai/spur 0.1.8
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 +78 -0
- package/package.json +67 -0
- package/schemas/spur-config.schema.json +140 -0
- package/spur-cli/config/config.example.yaml +44 -0
- package/spur-cli/config/plugins/.gitkeep +0 -0
- package/spur-cli/config/rules/README.md +40 -0
- package/spur-cli/config/rules/boundary/dao-boundary.yaml +126 -0
- package/spur-cli/config/rules/migration/rg-dialect.yaml +44 -0
- package/spur-cli/config/rules/quality/coverage-gate.yaml +36 -0
- package/spur-cli/config/rules/quality/tsdoc-exports.yaml +29 -0
- package/spur-cli/config/rules/recommended-post-check.yaml +10 -0
- package/spur-cli/config/rules/recommended-pre-check.yaml +12 -0
- package/spur-cli/config/rules/rg-migration.yaml +14 -0
- package/spur-cli/config/rules/strict/http-boundaries.yaml +70 -0
- package/spur-cli/config/rules/strict/rule-files-structural.yaml +55 -0
- package/spur-cli/config/rules/strict/runtime-boundaries.yaml +64 -0
- package/spur-cli/config/rules/strict-check.yaml +15 -0
- package/spur-cli/config/rules/structure/protected-files.yaml +62 -0
- package/spur-cli/config/rules/structure/test-focus-skip.yaml +27 -0
- package/spur-cli/config/rules/structure/test-location.yaml +44 -0
- package/spur-cli/config/rules/surface/check-cli-surface.yaml +35 -0
- package/spur-cli/config/rules/typescript/bun-tooling.yaml +61 -0
- package/spur-cli/config/rules/typescript/no-biome-suppressions.yaml +29 -0
- package/spur-cli/config/rules/typescript/no-debugger.yaml +27 -0
- package/spur-cli/config/rules/typescript/output-boundaries.yaml +28 -0
- package/spur-cli/config/workflows/basic.yaml +58 -0
- package/spur.js +61107 -0
package/README.md
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# @gobing-ai/spur
|
|
2
|
+
|
|
3
|
+
**The `spur` command** — a local-first harness for mainstream coding agents (Claude Code, Codex,
|
|
4
|
+
Gemini CLI, Antigravity, pi, OpenCode, OpenClaw). Spur is **not** a coding agent; it wraps the agents
|
|
5
|
+
you already have with constraint checking, workflow orchestration, agent health checks, and
|
|
6
|
+
conversation-history analytics.
|
|
7
|
+
|
|
8
|
+
## Install
|
|
9
|
+
|
|
10
|
+
Pick the path that matches your setup. Both give you a global `spur` command and seed the default
|
|
11
|
+
config into `~/.config/spur/` on first run.
|
|
12
|
+
|
|
13
|
+
### If you have Bun (`bun >= 1.3.0`) — recommended
|
|
14
|
+
|
|
15
|
+
The npm package ships a Bun bundle and runs under the Bun runtime you already have.
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
# Install globally → use the `spur` command everywhere
|
|
19
|
+
bun install -g @gobing-ai/spur
|
|
20
|
+
spur --help
|
|
21
|
+
|
|
22
|
+
# …or run ad-hoc with no install
|
|
23
|
+
bunx @gobing-ai/spur --help
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### If you don't have Bun — standalone binary
|
|
27
|
+
|
|
28
|
+
A self-contained executable (Bun embedded) for macOS and Linux. No runtime to install.
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
# One-liner: downloads the binary, puts it on PATH, seeds config
|
|
32
|
+
curl -fsSL https://raw.githubusercontent.com/gobing-ai/spur/main/scripts/install.sh | sh
|
|
33
|
+
spur --help
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
The installer drops `spur` into `~/.local/bin` by default. Override the target with `SPUR_INSTALL`,
|
|
37
|
+
or pin a release with `SPUR_VERSION`:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
SPUR_INSTALL=/usr/local/bin SPUR_VERSION='@gobing-ai/spur-v0.1.7' \
|
|
41
|
+
sh -c "$(curl -fsSL https://raw.githubusercontent.com/gobing-ai/spur/main/scripts/install.sh)"
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
If `~/.local/bin` isn't already on your `PATH`, add it (e.g. `export PATH="$HOME/.local/bin:$PATH"`
|
|
45
|
+
in your shell profile). Supported targets: `darwin-arm64`, `darwin-x64`, `linux-arm64`, `linux-x64`.
|
|
46
|
+
Windows: use the Bun path under WSL.
|
|
47
|
+
|
|
48
|
+
### First run
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
spur init # seeds ~/.config/spur/ (config.yaml, rules/, workflows/) — idempotent, never clobbers
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
The standalone installer runs `spur init` for you; the Bun install does it on your first `spur init`.
|
|
55
|
+
|
|
56
|
+
## Usage
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
spur init # scaffold .spur/ + seed global rules
|
|
60
|
+
spur rule run --preset recommended # evaluate constraint rules
|
|
61
|
+
spur workflow run <workflow.yaml> # run an FSM workflow
|
|
62
|
+
spur agent run "<prompt>" --agent auto # execute a prompt via a coding agent
|
|
63
|
+
spur agent doctor # check agent readiness
|
|
64
|
+
spur history import --source claude --root <path>
|
|
65
|
+
spur history analyze
|
|
66
|
+
spur status
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Every command supports `--json` for machine-readable output.
|
|
70
|
+
|
|
71
|
+
## Documentation
|
|
72
|
+
|
|
73
|
+
Full docs, architecture, and the complete command surface live in the
|
|
74
|
+
[Spur repository](https://github.com/gobing-ai/spur).
|
|
75
|
+
|
|
76
|
+
## License
|
|
77
|
+
|
|
78
|
+
Apache-2.0 © [Robin Min](mailto:minlongbing@gmail.com)
|
package/package.json
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@gobing-ai/spur",
|
|
3
|
+
"version": "0.1.8",
|
|
4
|
+
"description": "Spur CLI — local-first harness for mainstream coding agents: constraint checking, workflow orchestration, agent health, and history analytics. Bun-native; exposes the `spur` command.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"spur",
|
|
7
|
+
"cli",
|
|
8
|
+
"coding-agents",
|
|
9
|
+
"bun",
|
|
10
|
+
"rule-engine",
|
|
11
|
+
"workflow"
|
|
12
|
+
],
|
|
13
|
+
"homepage": "https://github.com/gobing-ai/spur#readme",
|
|
14
|
+
"bugs": "https://github.com/gobing-ai/spur/issues",
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "git+https://github.com/gobing-ai/spur.git",
|
|
18
|
+
"directory": "apps/cli"
|
|
19
|
+
},
|
|
20
|
+
"license": "Apache-2.0",
|
|
21
|
+
"author": "Robin Min <minlongbing@gmail.com>",
|
|
22
|
+
"type": "module",
|
|
23
|
+
"bin": {
|
|
24
|
+
"spur": "spur.js"
|
|
25
|
+
},
|
|
26
|
+
"exports": {
|
|
27
|
+
"./schemas/*": "./schemas/*"
|
|
28
|
+
},
|
|
29
|
+
"files": [
|
|
30
|
+
"spur.js",
|
|
31
|
+
"spur-cli",
|
|
32
|
+
"schemas",
|
|
33
|
+
"README.md"
|
|
34
|
+
],
|
|
35
|
+
"engines": {
|
|
36
|
+
"bun": ">=1.3.0"
|
|
37
|
+
},
|
|
38
|
+
"publishConfig": {
|
|
39
|
+
"access": "public"
|
|
40
|
+
},
|
|
41
|
+
"scripts": {
|
|
42
|
+
"dev": "bun run src/index.ts",
|
|
43
|
+
"build": "bun build src/index.ts --compile --outfile ../../dist/cli/spur",
|
|
44
|
+
"build:binaries": "bun run ../../scripts/spur-dev.ts build-binaries",
|
|
45
|
+
"build:bundle": "bun build src/index.ts --target=bun --outfile spur.js && bun run ../../scripts/spur-dev.ts bundle-config spur-cli/config",
|
|
46
|
+
"test": "bun test tests --coverage --coverage-dir=../../.coverage --pass-with-no-tests",
|
|
47
|
+
"typecheck": "tsc --noEmit",
|
|
48
|
+
"prepublishOnly": "bun run build:bundle"
|
|
49
|
+
},
|
|
50
|
+
"devDependencies": {
|
|
51
|
+
"@commander-js/extra-typings": "catalog:",
|
|
52
|
+
"@gobing-ai/spur-app": "workspace:0.1.0",
|
|
53
|
+
"@gobing-ai/spur-config": "workspace:0.1.0",
|
|
54
|
+
"@gobing-ai/spur-domain": "workspace:0.1.0",
|
|
55
|
+
"@gobing-ai/ts-ai-runner": "catalog:",
|
|
56
|
+
"@gobing-ai/ts-dual-workflow-engine": "catalog:",
|
|
57
|
+
"@gobing-ai/ts-llm-jsonl-importer": "catalog:",
|
|
58
|
+
"@gobing-ai/ts-rule-engine": "catalog:",
|
|
59
|
+
"@gobing-ai/ts-runtime": "catalog:",
|
|
60
|
+
"@gobing-ai/ts-infra": "catalog:",
|
|
61
|
+
"@gobing-ai/ts-utils": "catalog:",
|
|
62
|
+
"@types/bun": "catalog:",
|
|
63
|
+
"@types/figlet": "^1.7.0",
|
|
64
|
+
"commander": "catalog:",
|
|
65
|
+
"figlet": "^1.11.0"
|
|
66
|
+
}
|
|
67
|
+
}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://github.com/gobing-ai/spur/schemas/spur-config.schema.json",
|
|
4
|
+
"title": "Spur Project Configuration",
|
|
5
|
+
"description": "Schema for .spur/config.yaml — the single project configuration surface consumed by spur and (future) spur-server.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": ["version", "name"],
|
|
8
|
+
"properties": {
|
|
9
|
+
"$schema": {
|
|
10
|
+
"type": "string",
|
|
11
|
+
"description": "Reference to this schema for IDE validation. spur resolves this at runtime via loadStructuredConfig."
|
|
12
|
+
},
|
|
13
|
+
"version": {
|
|
14
|
+
"type": "string",
|
|
15
|
+
"description": "Config schema version. Currently '1'."
|
|
16
|
+
},
|
|
17
|
+
"name": {
|
|
18
|
+
"type": "string",
|
|
19
|
+
"description": "Project name written by spur init."
|
|
20
|
+
},
|
|
21
|
+
"bootstrap": {
|
|
22
|
+
"type": "object",
|
|
23
|
+
"description": "Portable bootstrap block consumed by @gobing-ai/ts-infra runNodeApplication. Shared across spur and spur-server.",
|
|
24
|
+
"properties": {
|
|
25
|
+
"logging": {
|
|
26
|
+
"type": "object",
|
|
27
|
+
"properties": {
|
|
28
|
+
"enabled": {
|
|
29
|
+
"type": "boolean",
|
|
30
|
+
"description": "Enable structured logging via LogTape."
|
|
31
|
+
},
|
|
32
|
+
"level": {
|
|
33
|
+
"type": "string",
|
|
34
|
+
"enum": ["trace", "debug", "info", "warn", "error", "fatal"],
|
|
35
|
+
"description": "Minimum log level."
|
|
36
|
+
},
|
|
37
|
+
"console": {
|
|
38
|
+
"type": "boolean",
|
|
39
|
+
"description": "Emit log records to console (stderr)."
|
|
40
|
+
},
|
|
41
|
+
"json": {
|
|
42
|
+
"type": "boolean",
|
|
43
|
+
"description": "Format log records as JSON Lines. false = text format."
|
|
44
|
+
},
|
|
45
|
+
"file": {
|
|
46
|
+
"type": "boolean",
|
|
47
|
+
"description": "Write log records to a file sink. Uses filePath when set, otherwise disabled."
|
|
48
|
+
},
|
|
49
|
+
"filePath": {
|
|
50
|
+
"type": "string",
|
|
51
|
+
"description": "Path to the log file. Relative to project root. Default: .spur/logs/spur.log."
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
"telemetry": {
|
|
56
|
+
"type": "object",
|
|
57
|
+
"properties": {
|
|
58
|
+
"enabled": {
|
|
59
|
+
"type": "boolean",
|
|
60
|
+
"description": "Enable OpenTelemetry tracing/metrics export."
|
|
61
|
+
},
|
|
62
|
+
"serviceName": {
|
|
63
|
+
"type": "string",
|
|
64
|
+
"description": "Service name reported to OTel collectors."
|
|
65
|
+
},
|
|
66
|
+
"environment": {
|
|
67
|
+
"type": "string",
|
|
68
|
+
"description": "Deployment environment label."
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
"database": {
|
|
73
|
+
"type": "object",
|
|
74
|
+
"properties": {
|
|
75
|
+
"enabled": {
|
|
76
|
+
"type": "boolean",
|
|
77
|
+
"description": "Enable the SQLite database adapter."
|
|
78
|
+
},
|
|
79
|
+
"driver": {
|
|
80
|
+
"type": "string",
|
|
81
|
+
"enum": ["bun-sqlite"],
|
|
82
|
+
"description": "Database driver. Currently only bun-sqlite."
|
|
83
|
+
},
|
|
84
|
+
"url": {
|
|
85
|
+
"type": "string",
|
|
86
|
+
"description": "Database file path. Supports ${DATABASE_URL} interpolation. Default: .spur/spur.db."
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
"scheduler": {
|
|
91
|
+
"type": "object",
|
|
92
|
+
"properties": {
|
|
93
|
+
"enabled": {
|
|
94
|
+
"type": "boolean",
|
|
95
|
+
"description": "Enable the scheduled-task runner. OFF by default for CLI (run-once)."
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
"agent": {
|
|
102
|
+
"type": "object",
|
|
103
|
+
"properties": {
|
|
104
|
+
"default": {
|
|
105
|
+
"type": "string",
|
|
106
|
+
"description": "Default coding agent (e.g. pi, claude, codex)."
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
"rules": {
|
|
111
|
+
"type": "object",
|
|
112
|
+
"properties": {
|
|
113
|
+
"paths": {
|
|
114
|
+
"type": "array",
|
|
115
|
+
"items": { "type": "string" },
|
|
116
|
+
"description": "Glob paths to rule files."
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
"workflows": {
|
|
121
|
+
"type": "object",
|
|
122
|
+
"properties": {
|
|
123
|
+
"paths": {
|
|
124
|
+
"type": "array",
|
|
125
|
+
"items": { "type": "string" },
|
|
126
|
+
"description": "Glob paths to workflow directories."
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
},
|
|
130
|
+
"redaction": {
|
|
131
|
+
"type": "object",
|
|
132
|
+
"properties": {
|
|
133
|
+
"enabled": {
|
|
134
|
+
"type": "boolean",
|
|
135
|
+
"description": "Enable sensitive-data redaction in CLI output."
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Spur project configuration for spur-new
|
|
2
|
+
# Generated by `spur init`
|
|
3
|
+
|
|
4
|
+
$schema: "@gobing-ai/spur/schemas/spur-config.schema.json"
|
|
5
|
+
version: "1"
|
|
6
|
+
name: spur-new
|
|
7
|
+
|
|
8
|
+
# ── Portable bootstrap (consumed by @gobing-ai/ts-infra runNodeApplication) ──
|
|
9
|
+
# Shared across spur and (future) spur-server. Keys map 1:1 to ts-infra's
|
|
10
|
+
# LoggingOptions / TelemetryOptions / database / SchedulerOptions.
|
|
11
|
+
bootstrap:
|
|
12
|
+
logging:
|
|
13
|
+
enabled: true
|
|
14
|
+
level: info # debug | info | warn | error
|
|
15
|
+
console: false
|
|
16
|
+
json: false
|
|
17
|
+
file: true
|
|
18
|
+
filePath: .spur/spur.log # relative to project root
|
|
19
|
+
telemetry:
|
|
20
|
+
enabled: false # OFF by default for CLI (per-invocation latency)
|
|
21
|
+
serviceName: spur
|
|
22
|
+
environment: development
|
|
23
|
+
# endpoint: http://localhost:4318 # set => Node OTel exporter activates
|
|
24
|
+
database:
|
|
25
|
+
enabled: true
|
|
26
|
+
driver: bun-sqlite
|
|
27
|
+
url: .spur/spur.db # ${DATABASE_URL} interpolation supported
|
|
28
|
+
scheduler:
|
|
29
|
+
enabled: false # CLI is run-once; no scheduler
|
|
30
|
+
|
|
31
|
+
# ── Spur app section (validated by a local zod schema — UNCHANGED keys) ──
|
|
32
|
+
agent:
|
|
33
|
+
default: pi
|
|
34
|
+
|
|
35
|
+
rules:
|
|
36
|
+
paths:
|
|
37
|
+
- .spur/rules/**/*.yaml
|
|
38
|
+
|
|
39
|
+
workflows:
|
|
40
|
+
paths:
|
|
41
|
+
- .spur/workflows/
|
|
42
|
+
|
|
43
|
+
redaction:
|
|
44
|
+
enabled: false
|
|
File without changes
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Spur Rules
|
|
2
|
+
|
|
3
|
+
This directory is the **single source of truth** for Spur's quality-gate ruleset.
|
|
4
|
+
It is self-contained and authoritative — `spur rule run` resolves all categories
|
|
5
|
+
and presets from local `.spur/rules/**/*.yaml` with no fallback to a global
|
|
6
|
+
install or to ts-libs.
|
|
7
|
+
|
|
8
|
+
## Categories
|
|
9
|
+
|
|
10
|
+
| Category | Dir | Purpose |
|
|
11
|
+
|---|---|---|
|
|
12
|
+
| `typescript` | `typescript/` | TypeScript tooling, output boundaries, biome-suppression ban, no `debugger` |
|
|
13
|
+
| `strict` | `strict/` | Opt-in strict rules (runtime boundaries, HTTP boundaries, structural) |
|
|
14
|
+
| `boundary` | `boundary/` | DB/DAO boundary enforcement |
|
|
15
|
+
| `structure` | `structure/` | File layout, protected files, no focused/skipped tests |
|
|
16
|
+
| `quality` | `quality/` | Post-test gates (coverage) |
|
|
17
|
+
| `surface` | `surface/` | CLI surface consistency (registerXxxCommand wiring, --json serialization) |
|
|
18
|
+
|
|
19
|
+
## Presets
|
|
20
|
+
|
|
21
|
+
| Preset | When | Extends |
|
|
22
|
+
|---|---|---|
|
|
23
|
+
| `recommended-pre-check` | Before tests | `typescript`, `structure`, `boundary`, `surface` |
|
|
24
|
+
| `recommended-post-check` | After tests | `quality` |
|
|
25
|
+
| `strict-check` | Opt-in | `strict` |
|
|
26
|
+
|
|
27
|
+
## Relationship to ts-libs
|
|
28
|
+
|
|
29
|
+
Rules originally authored in `ts-libs/.spur/rules/` were **absorbed and adapted**
|
|
30
|
+
(here, not copied verbatim). Each absorbed file carries an `Absorbed from
|
|
31
|
+
ts-libs/.spur/rules/...` header documenting what was re-scoped, omitted, or
|
|
32
|
+
tuned for Spur's app-repo layout. After absorption, ts-libs and spur-new
|
|
33
|
+
maintain their rulesets independently.
|
|
34
|
+
|
|
35
|
+
## Not absorbed (Spur-irrelevant)
|
|
36
|
+
|
|
37
|
+
- `typescript/esm-build-conventions` — governs ts-libs' library publish/dist
|
|
38
|
+
flow. Spur apps don't publish libraries this way.
|
|
39
|
+
- `migration/rg-dialect` — one-time grep→rg migration helper.
|
|
40
|
+
- `migration/rg-migration` — one-time grep→rg migration helper.
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# DAO / database boundary rules — keep DB access centralized in packages/domain,
|
|
2
|
+
# drizzle confined to schema authoring, and table DDL derived (not hand-written).
|
|
3
|
+
# Enforces ADR-011 (ts-db consumed as a facade; tables are a single source of truth).
|
|
4
|
+
rules:
|
|
5
|
+
- id: ts-db-only-in-domain
|
|
6
|
+
description: >
|
|
7
|
+
@gobing-ai/ts-db may only be imported inside packages/domain. Apps and
|
|
8
|
+
other packages must consume persistence through @gobing-ai/spur-domain
|
|
9
|
+
DAOs, never the raw adapter. (ADR-011)
|
|
10
|
+
severity: error
|
|
11
|
+
evaluator:
|
|
12
|
+
type: forbidden-import
|
|
13
|
+
config:
|
|
14
|
+
forbidden:
|
|
15
|
+
- specifier: "@gobing-ai/ts-db"
|
|
16
|
+
- specifier: "@gobing-ai/ts-db/schema"
|
|
17
|
+
- specifier: "@gobing-ai/ts-db/bun-sqlite"
|
|
18
|
+
- specifier: "@gobing-ai/ts-db/d1"
|
|
19
|
+
scope:
|
|
20
|
+
include:
|
|
21
|
+
- "apps/**/src/**/*.ts"
|
|
22
|
+
- "packages/app/src/**/*.ts"
|
|
23
|
+
- "packages/config/src/**/*.ts"
|
|
24
|
+
- "packages/contracts/src/**/*.ts"
|
|
25
|
+
exclude:
|
|
26
|
+
- "**/node_modules/**"
|
|
27
|
+
- "**/tests/**"
|
|
28
|
+
|
|
29
|
+
- id: drizzle-only-in-domain-schema
|
|
30
|
+
description: >
|
|
31
|
+
drizzle-orm is an internal detail of the ts-db facade. Spur may import it
|
|
32
|
+
ONLY in packages/domain/src/schema/ (table authoring via defineTable column
|
|
33
|
+
builders). DAOs, analytics, apps, and other packages must use the ts-db
|
|
34
|
+
vocabulary (EntityDao/BaseDao + predicate spec), never drizzle. (ADR-011)
|
|
35
|
+
severity: error
|
|
36
|
+
evaluator:
|
|
37
|
+
type: forbidden-import
|
|
38
|
+
config:
|
|
39
|
+
forbidden:
|
|
40
|
+
- specifier: "drizzle-orm"
|
|
41
|
+
- specifier: "drizzle-orm/sqlite-core"
|
|
42
|
+
- specifier: "drizzle-orm/bun-sqlite"
|
|
43
|
+
- specifier: "drizzle-orm/d1"
|
|
44
|
+
- specifier: "drizzle-zod"
|
|
45
|
+
scope:
|
|
46
|
+
include:
|
|
47
|
+
- "apps/**/src/**/*.ts"
|
|
48
|
+
- "packages/**/src/**/*.ts"
|
|
49
|
+
exclude:
|
|
50
|
+
- "packages/domain/src/schema/**"
|
|
51
|
+
- "**/node_modules/**"
|
|
52
|
+
- "**/tests/**"
|
|
53
|
+
|
|
54
|
+
- id: tables-via-defineTable
|
|
55
|
+
description: >
|
|
56
|
+
Tables must be defined with defineTable() (from @gobing-ai/ts-db/schema),
|
|
57
|
+
not bare sqliteTable() — so DDL and zod derive from one source. Allowed only
|
|
58
|
+
under packages/domain/src/schema/. (ADR-011)
|
|
59
|
+
severity: error
|
|
60
|
+
evaluator:
|
|
61
|
+
type: rg
|
|
62
|
+
config:
|
|
63
|
+
pattern: "sqliteTable\\("
|
|
64
|
+
include:
|
|
65
|
+
- "apps/**/src/**/*.ts"
|
|
66
|
+
- "packages/**/src/**/*.ts"
|
|
67
|
+
exclude:
|
|
68
|
+
- "**/node_modules/**"
|
|
69
|
+
- "**/tests/**"
|
|
70
|
+
|
|
71
|
+
- id: no-hand-written-ddl-for-drizzle-tables
|
|
72
|
+
description: >
|
|
73
|
+
Domain tables derive their CREATE TABLE via createTableSql (single source of
|
|
74
|
+
truth) — do not hand-write DDL. Exempt: the CLI migration journal and
|
|
75
|
+
package-owned schema SQL re-exported from ts-libs. (ADR-011)
|
|
76
|
+
severity: error
|
|
77
|
+
evaluator:
|
|
78
|
+
type: rg
|
|
79
|
+
config:
|
|
80
|
+
# Match DDL statement form (CREATE/ALTER/DROP TABLE <name> ... '(' or ';'),
|
|
81
|
+
# not the bare words in prose/comments. Inline `(?i)` replaces the JS
|
|
82
|
+
# `flags: i` — the rg evaluator honors inline flags, not a `flags` field.
|
|
83
|
+
pattern: "(?i)(CREATE|ALTER|DROP)\\s+TABLE\\s+(IF\\s+(NOT\\s+)?EXISTS\\s+)?[\"'`]?[A-Za-z_][A-Za-z0-9_]*[\"'`]?\\s*[(;]"
|
|
84
|
+
include:
|
|
85
|
+
- "apps/**/src/**/*.ts"
|
|
86
|
+
- "packages/**/src/**/*.ts"
|
|
87
|
+
exclude:
|
|
88
|
+
- "packages/domain/src/migrations.ts"
|
|
89
|
+
- "**/node_modules/**"
|
|
90
|
+
- "**/tests/**"
|
|
91
|
+
|
|
92
|
+
- id: raw-sql-only-in-domain
|
|
93
|
+
description: >
|
|
94
|
+
Raw SQL string literals (SELECT/INSERT/UPDATE/DELETE) must stay inside
|
|
95
|
+
packages/domain (the DAO/migration layer). Apps and other packages query
|
|
96
|
+
through @gobing-ai/spur-domain DAOs. (ADR-011)
|
|
97
|
+
severity: error
|
|
98
|
+
evaluator:
|
|
99
|
+
type: rg
|
|
100
|
+
config:
|
|
101
|
+
pattern: "(SELECT |INSERT INTO|UPDATE |DELETE FROM)"
|
|
102
|
+
include:
|
|
103
|
+
- "apps/**/src/**/*.ts"
|
|
104
|
+
- "packages/app/src/**/*.ts"
|
|
105
|
+
- "packages/config/src/**/*.ts"
|
|
106
|
+
- "packages/contracts/src/**/*.ts"
|
|
107
|
+
exclude:
|
|
108
|
+
- "**/node_modules/**"
|
|
109
|
+
- "**/tests/**"
|
|
110
|
+
|
|
111
|
+
- id: no-sql-text-imports
|
|
112
|
+
description: >
|
|
113
|
+
.sql text-imports (import ... from './x.sql' with { type: 'text' }) are
|
|
114
|
+
non-portable through build/publish and are forbidden. Inline SQL in .ts or
|
|
115
|
+
derive DDL via createTableSql instead. (ADR-011)
|
|
116
|
+
severity: error
|
|
117
|
+
evaluator:
|
|
118
|
+
type: rg
|
|
119
|
+
config:
|
|
120
|
+
pattern: "from\\s+['\"][^'\"]*\\.sql['\"]"
|
|
121
|
+
include:
|
|
122
|
+
- "apps/**/src/**/*.ts"
|
|
123
|
+
- "packages/**/src/**/*.ts"
|
|
124
|
+
exclude:
|
|
125
|
+
- "**/node_modules/**"
|
|
126
|
+
- "**/tests/**"
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# One-off migration guard for the `regex` → `rg` (ripgrep) evaluator move.
|
|
2
|
+
#
|
|
3
|
+
# NOT part of recommended-pre-check — it is a transitional check, run on demand:
|
|
4
|
+
# spur rule run --preset rg-migration
|
|
5
|
+
#
|
|
6
|
+
# It flags `rg`-typed rules whose patterns use ripgrep-incompatible constructs
|
|
7
|
+
# (lookbehind, backreferences) so they stay on `type: regex`. Once a project's
|
|
8
|
+
# rule files are migrated and clean, this preset rarely needs to run again.
|
|
9
|
+
rules:
|
|
10
|
+
- id: rg-evaluator-patterns-are-ripgrep-dialect
|
|
11
|
+
description: "Patterns on the `rg` evaluator run under ripgrep's Rust regex engine, which has no lookbehind or backreferences. Such JS-only constructs belong on the `regex` (JS RegExp) evaluator. Keeps `rg` rules from failing to compile at scan time."
|
|
12
|
+
severity: error
|
|
13
|
+
evaluator:
|
|
14
|
+
type: exit-code
|
|
15
|
+
config:
|
|
16
|
+
command: sh
|
|
17
|
+
args:
|
|
18
|
+
- -c
|
|
19
|
+
- |
|
|
20
|
+
errors=0
|
|
21
|
+
for f in $(rg --files .spur/rules -g '*.yaml'); do
|
|
22
|
+
yq -e '.rules != null' "$f" >/dev/null 2>&1 || continue
|
|
23
|
+
count="$(yq '.rules | length' "$f")"
|
|
24
|
+
i=0
|
|
25
|
+
while [ "$i" -lt "$count" ]; do
|
|
26
|
+
rtype="$(yq ".rules[$i].evaluator.type // \"\"" "$f")"
|
|
27
|
+
if [ "$rtype" = "rg" ]; then
|
|
28
|
+
pat="$(yq ".rules[$i].evaluator.config.pattern // \"\"" "$f")"
|
|
29
|
+
# ripgrep's regex crate rejects lookbehind and backreferences.
|
|
30
|
+
if printf '%s' "$pat" | rg -q '\(\?<[=!]'; then
|
|
31
|
+
echo "INVALID: $f: rules[$i] rg pattern uses lookbehind (unsupported by ripgrep) — use type: regex"
|
|
32
|
+
errors=$((errors + 1))
|
|
33
|
+
fi
|
|
34
|
+
if printf '%s' "$pat" | rg -q '\\[1-9]'; then
|
|
35
|
+
echo "INVALID: $f: rules[$i] rg pattern uses a backreference (unsupported by ripgrep) — use type: regex"
|
|
36
|
+
errors=$((errors + 1))
|
|
37
|
+
fi
|
|
38
|
+
fi
|
|
39
|
+
i=$((i + 1))
|
|
40
|
+
done
|
|
41
|
+
done
|
|
42
|
+
[ "$errors" -eq 0 ] || exit 1
|
|
43
|
+
include:
|
|
44
|
+
- ".spur/rules/**/*.yaml"
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Coverage gate — per-file line coverage meets threshold from Bun's lcov output.
|
|
2
|
+
# Absorbed from ts-libs/.spur/rules/quality/coverage-gate.yaml, re-scoped to
|
|
3
|
+
# Spur's monorepo layout:
|
|
4
|
+
# - lcovPath kept at .coverage/lcov.info (Spur's `bun run test` writes
|
|
5
|
+
# coverage there via --coverage-dir=.coverage)
|
|
6
|
+
# - include expanded to apps/** + packages/** (Spur tests cover both;
|
|
7
|
+
# ts-libs only covers packages/**)
|
|
8
|
+
# - threshold kept at 90 matching bunfig.toml coverageThreshold
|
|
9
|
+
# - no drizzle exclude needed (Spur doesn't vendor generated SQL in src/)
|
|
10
|
+
#
|
|
11
|
+
# Scope tightened to production source only and aligned with the tsdoc-export
|
|
12
|
+
# gate's exclusions: tests carry no coverage obligation, stubs are
|
|
13
|
+
# declaration-only, and schema/migrations/db are implementation internals
|
|
14
|
+
# (DDL, journals, adapter wiring) whose per-file coverage is noise rather than
|
|
15
|
+
# a meaningful test-gap signal.
|
|
16
|
+
rules:
|
|
17
|
+
- id: coverage-gate
|
|
18
|
+
description: "Per-file line coverage meets 90% threshold (read from lcov)"
|
|
19
|
+
severity: error
|
|
20
|
+
evaluator:
|
|
21
|
+
type: coverage-gate
|
|
22
|
+
config:
|
|
23
|
+
lcovPath: .coverage/lcov.info
|
|
24
|
+
threshold: 90
|
|
25
|
+
include:
|
|
26
|
+
- "apps/**/src/**"
|
|
27
|
+
- "packages/**/src/**"
|
|
28
|
+
exclude:
|
|
29
|
+
- "**/node_modules/**"
|
|
30
|
+
- "**/vendors/**"
|
|
31
|
+
- "**/dist/**"
|
|
32
|
+
- "**/tests/**"
|
|
33
|
+
- "**/stubs/**"
|
|
34
|
+
- "**/schema/**"
|
|
35
|
+
- "**/migrations.ts"
|
|
36
|
+
- "**/db.ts"
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# TSDoc-on-exports — enforced by Spur's post-check gate.
|
|
2
|
+
# Absorbed from ts-libs/.spur/rules/quality/tsdoc-exports.yaml.
|
|
3
|
+
#
|
|
4
|
+
# Rationale: exported symbols in production source (apps/**/src, packages/**/src)
|
|
5
|
+
# are public integration points that warrant doc comments. The post-check gate
|
|
6
|
+
# keeps those boundaries documented.
|
|
7
|
+
#
|
|
8
|
+
# Scope tightened from the evaluator's default (**/*.ts) to production source only.
|
|
9
|
+
# Excluded: tests (no public API contract), stubs (declaration-only), schema/
|
|
10
|
+
# migrations/db (implementation internals, not public API), dist, node_modules.
|
|
11
|
+
include:
|
|
12
|
+
- "apps/**/src/**/*.ts"
|
|
13
|
+
- "packages/**/src/**/*.ts"
|
|
14
|
+
exclude:
|
|
15
|
+
- "**/node_modules/**"
|
|
16
|
+
- "**/dist/**"
|
|
17
|
+
- "**/tests/**"
|
|
18
|
+
- "**/stubs/**"
|
|
19
|
+
- "**/schema/**" # drizzle DDL definitions — not public API surface
|
|
20
|
+
- "**/migrations.ts"
|
|
21
|
+
- "**/db.ts"
|
|
22
|
+
rules:
|
|
23
|
+
- id: every-export-has-tsdoc
|
|
24
|
+
description: >
|
|
25
|
+
Exported declarations must have a preceding TSDoc comment.
|
|
26
|
+
severity: error
|
|
27
|
+
enabled: true
|
|
28
|
+
evaluator:
|
|
29
|
+
type: tsdoc-export
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Recommended post-check preset — coverage gate and exported-symbol docs.
|
|
2
|
+
# Use with: spur rule run --preset recommended-post-check --fail-on warning
|
|
3
|
+
#
|
|
4
|
+
# Runs AFTER tests (test-post-check). Enforces the coverage gate on
|
|
5
|
+
# fresh .coverage/lcov.info output from bun test --coverage, checks exported
|
|
6
|
+
# declarations for TSDoc comments. All other rules (typescript, structure,
|
|
7
|
+
# boundary, surface) run in pre-check.
|
|
8
|
+
name: recommended-post-check
|
|
9
|
+
extends:
|
|
10
|
+
- quality
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# Recommended pre-check preset — portable rule categories from global install.
|
|
2
|
+
# Use with: spur rule run --preset recommended-pre-check
|
|
3
|
+
#
|
|
4
|
+
# Runs BEFORE tests (test-pre-check). TypeScript quality, structural, DB
|
|
5
|
+
# boundary, and CLI surface consistency rules. TSDoc exports run in post-check
|
|
6
|
+
# alongside coverage-gate.
|
|
7
|
+
name: recommended-pre-check
|
|
8
|
+
extends:
|
|
9
|
+
- typescript
|
|
10
|
+
- structure
|
|
11
|
+
- boundary
|
|
12
|
+
- surface
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# rg-migration preset — on-demand guard for the regex → rg (ripgrep) evaluator move.
|
|
2
|
+
#
|
|
3
|
+
# Run explicitly when migrating rule files onto the `rg` evaluator:
|
|
4
|
+
# spur rule run --preset rg-migration --fail-on warning
|
|
5
|
+
#
|
|
6
|
+
# Deliberately NOT included in recommended-pre-check / recommended-post-check:
|
|
7
|
+
# it is a transitional check, not a standing quality gate. See the rule-engine
|
|
8
|
+
# README "Rules Migration" section.
|
|
9
|
+
name: rg-migration
|
|
10
|
+
description: >
|
|
11
|
+
Flags rg-typed rule patterns that use ripgrep-incompatible constructs
|
|
12
|
+
(lookbehind, backreferences). Run on demand during the regex → rg migration.
|
|
13
|
+
extends:
|
|
14
|
+
- migration
|