@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.
Files changed (27) hide show
  1. package/README.md +78 -0
  2. package/package.json +67 -0
  3. package/schemas/spur-config.schema.json +140 -0
  4. package/spur-cli/config/config.example.yaml +44 -0
  5. package/spur-cli/config/plugins/.gitkeep +0 -0
  6. package/spur-cli/config/rules/README.md +40 -0
  7. package/spur-cli/config/rules/boundary/dao-boundary.yaml +126 -0
  8. package/spur-cli/config/rules/migration/rg-dialect.yaml +44 -0
  9. package/spur-cli/config/rules/quality/coverage-gate.yaml +36 -0
  10. package/spur-cli/config/rules/quality/tsdoc-exports.yaml +29 -0
  11. package/spur-cli/config/rules/recommended-post-check.yaml +10 -0
  12. package/spur-cli/config/rules/recommended-pre-check.yaml +12 -0
  13. package/spur-cli/config/rules/rg-migration.yaml +14 -0
  14. package/spur-cli/config/rules/strict/http-boundaries.yaml +70 -0
  15. package/spur-cli/config/rules/strict/rule-files-structural.yaml +55 -0
  16. package/spur-cli/config/rules/strict/runtime-boundaries.yaml +64 -0
  17. package/spur-cli/config/rules/strict-check.yaml +15 -0
  18. package/spur-cli/config/rules/structure/protected-files.yaml +62 -0
  19. package/spur-cli/config/rules/structure/test-focus-skip.yaml +27 -0
  20. package/spur-cli/config/rules/structure/test-location.yaml +44 -0
  21. package/spur-cli/config/rules/surface/check-cli-surface.yaml +35 -0
  22. package/spur-cli/config/rules/typescript/bun-tooling.yaml +61 -0
  23. package/spur-cli/config/rules/typescript/no-biome-suppressions.yaml +29 -0
  24. package/spur-cli/config/rules/typescript/no-debugger.yaml +27 -0
  25. package/spur-cli/config/rules/typescript/output-boundaries.yaml +28 -0
  26. package/spur-cli/config/workflows/basic.yaml +58 -0
  27. 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