@gobing-ai/spur 0.3.85 → 0.3.87
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/.claude-plugin/marketplace.json +1 -1
- package/config/pipeline-budgets.json +0 -25
- package/config/plugin-scripts.json +4 -5
- package/config/rules/boundary/env-var-hygiene.yaml +41 -0
- package/config/templates/feature/default.md +2 -0
- package/config/templates/task/brainstorm.md +2 -2
- package/config/templates/task/feature-impl.md +2 -2
- package/config/templates/task/issue.md +2 -2
- package/config/templates/task/meta.md +2 -2
- package/config/templates/task/review.md +2 -2
- package/config/templates/task/standard.md +2 -2
- package/config/transition-shims.json +1 -1
- package/config/workflow-candidates.json +19 -0
- package/config/workflows/feature-lifecycle.yaml +10 -2
- package/config/workflows/feature-verification.yaml +71 -0
- package/config/workflows/idea-pipeline.yaml +87 -39
- package/config/workflows/task-pipeline.yaml +43 -12
- package/config/workflows/wrapup-pipeline.yaml +70 -7
- package/package.json +9 -9
- package/plugins/sp/README.md +7 -7
- package/plugins/sp/commands/dev-idea.md +9 -2
- package/plugins/sp/commands/dev-refactor.md +33 -0
- package/plugins/sp/hooks/agent-hint.ts +5 -4
- package/plugins/sp/hooks/careful-guard.ts +3 -1
- package/plugins/sp/hooks/context-post-tool.ts +2 -1
- package/plugins/sp/hooks/context-session-start.ts +4 -3
- package/plugins/sp/hooks/context-session-stop.ts +2 -1
- package/plugins/sp/hooks/pi/guard-extension.ts +4 -3
- package/plugins/sp/hooks/task-write-guard.ts +4 -3
- package/plugins/sp/lib/idea-handoff.generated.mjs +260 -260
- package/plugins/sp/plugin.json +1 -1
- package/plugins/sp/references/roles.md +1 -1
- package/plugins/sp/scripts/daily-summary/daily-summary.mjs +13 -4
- package/plugins/sp/scripts/daily-summary/daily-summary.ts +6 -4
- package/plugins/sp/scripts/feature-sync-bounded.mjs +10 -2
- package/plugins/sp/scripts/feature-sync-bounded.ts +2 -1
- package/plugins/sp/scripts/idea-coverage-check.ts +168 -0
- package/plugins/sp/scripts/idea-handoff.mjs +6 -1
- package/plugins/sp/scripts/idea-handoff.ts +4 -1
- package/plugins/sp/scripts/inline-pipeline-parity-check.ts +115 -4
- package/plugins/sp/scripts/inline-run-setup.ts +195 -2
- package/plugins/sp/scripts/pr-reviewing.mjs +8 -1
- package/plugins/sp/scripts/pr-reviewing.ts +2 -1
- package/plugins/sp/scripts/quality-gate.mjs +8 -1
- package/plugins/sp/scripts/quality-gate.ts +2 -1
- package/plugins/sp/scripts/surface-drift-inventory.ts +1 -4
- package/plugins/sp/scripts/task-evidence-precheck.ts +2 -1
- package/plugins/sp/scripts/task-size-precheck.ts +6 -4
- package/plugins/sp/scripts/verify-answer-lint.ts +2 -1
- package/plugins/sp/scripts/workflow-step-profile.mjs +10 -2
- package/plugins/sp/scripts/workflow-step-profile.ts +2 -1
- package/plugins/sp/scripts/wrapup-steps.mjs +8 -1
- package/plugins/sp/scripts/wrapup-steps.ts +2 -1
- package/plugins/sp/skills/brainstorm/SKILL.md +4 -0
- package/plugins/sp/skills/code-refactoring/SKILL.md +155 -0
- package/plugins/sp/skills/code-refactoring/references/finding-schema.md +74 -0
- package/plugins/sp/skills/code-refactoring/references/fix-ladder.md +52 -0
- package/plugins/sp/skills/code-refactoring/references/focus-detection.md +44 -0
- package/plugins/sp/skills/code-refactoring/references/refactor-finding.schema.json +95 -0
- package/plugins/sp/skills/spec-decomposition/references/decomposition.md +23 -16
- package/plugins/sp/skills/spur-cli/references/features/acceptance-criteria.md +4 -2
- package/plugins/sp/skills/spur-cli/references/features.md +6 -1
- package/plugins/sp/skills/spur-cli/references/workflows/authoring-workflows.md +2 -2
- package/plugins/sp/skills/spur-cli/references/workflows/operations.md +3 -3
- package/plugins/sp/skills/spur-cli/references/workflows/workflow-fit-and-tuning.md +1 -1
- package/plugins/sp/skills/spur-cli/references/workflows.md +8 -7
- package/plugins/sp/skills/spur-dev/references/ac-style-guide.md +24 -0
- package/plugins/sp/skills/spur-dev/references/cross-cutting.md +4 -5
- package/plugins/sp/skills/spur-dev/references/dev-operations.md +18 -2
- package/plugins/sp/skills/spur-dev/references/done-housekeeping.md +1 -1
- package/plugins/sp/skills/spur-dev/references/flag-glossary.md +22 -3
- package/plugins/sp/skills/spur-dev/references/gate-checklists.md +2 -2
- package/plugins/sp/skills/spur-dev/references/idea-evaluation.md +11 -1
- package/plugins/sp/skills/spur-dev/references/inline-pipeline-driver.md +91 -1
- package/plugins/sp/skills/taste-refactoring-api/SKILL.md +44 -1
- package/plugins/sp/skills/taste-refactoring-api/references/protocol-modes.md +31 -0
- package/plugins/sp/skills/taste-refactoring-architect/SKILL.md +43 -0
- package/plugins/sp/skills/taste-refactoring-tests/SKILL.md +42 -0
- package/plugins/sp/skills/taste-refactoring-ui/SKILL.md +43 -0
- package/schemas/state-machine-workflow.schema.json +5 -0
- package/schemas/task-batch.schema.json +2 -2
- package/schemas/transition-flow-workflow.schema.json +5 -0
- package/spur.js +21106 -20669
- package/web/_astro/BoardApp.CJiqp5pS.js +1 -0
- package/web/_astro/{BoardApp.yW425dRZ.js → BoardApp.yBBcFXWP.js} +4 -4
- package/web/_astro/{TaskDetail.CGwJAinW.js → TaskDetail.DqFJbRFc.js} +1 -1
- package/web/_astro/{arc.B-qNXzSO.js → arc.DL-BpHoi.js} +1 -1
- package/web/_astro/{architectureDiagram-3BPJPVTR.Bdg-xiji.js → architectureDiagram-3BPJPVTR.9IdQYyDq.js} +1 -1
- package/web/_astro/{blockDiagram-GPEHLZMM.DFArg3Kp.js → blockDiagram-GPEHLZMM.BKsFCqTl.js} +1 -1
- package/web/_astro/{c4Diagram-AAUBKEIU.BkOLcjyx.js → c4Diagram-AAUBKEIU.DhwI0dh1.js} +1 -1
- package/web/_astro/channel.CX5453qQ.js +1 -0
- package/web/_astro/{chunk-2J33WTMH.DN3c20V4.js → chunk-2J33WTMH.B3QVmQ9S.js} +1 -1
- package/web/_astro/{chunk-4BX2VUAB.B64K0Ttd.js → chunk-4BX2VUAB.DBSuqs9F.js} +1 -1
- package/web/_astro/{chunk-55IACEB6.C-AJvNwa.js → chunk-55IACEB6.BSYTWAYD.js} +1 -1
- package/web/_astro/{chunk-727SXJPM.DMkr46uS.js → chunk-727SXJPM.cWVuxXfS.js} +1 -1
- package/web/_astro/{chunk-AQP2D5EJ.4_WGbI64.js → chunk-AQP2D5EJ.DpU_Ob3d.js} +1 -1
- package/web/_astro/{chunk-FMBD7UC4.cbFW_lVE.js → chunk-FMBD7UC4.BykFkyji.js} +1 -1
- package/web/_astro/{chunk-ND2GUHAM.CDW_-2O1.js → chunk-ND2GUHAM.DwgHlMdY.js} +1 -1
- package/web/_astro/{chunk-QZHKN3VN.BoYOt_yg.js → chunk-QZHKN3VN.CusXUGWM.js} +1 -1
- package/web/_astro/{classDiagram-4FO5ZUOK.BNT6XpHQ.js → classDiagram-4FO5ZUOK.fx0ObzkN.js} +1 -1
- package/web/_astro/{classDiagram-v2-Q7XG4LA2.BNT6XpHQ.js → classDiagram-v2-Q7XG4LA2.fx0ObzkN.js} +1 -1
- package/web/_astro/{cose-bilkent-S5V4N54A.CI1DQxR3.js → cose-bilkent-S5V4N54A.Z4HgOlsd.js} +1 -1
- package/web/_astro/{cynefin-OW5HDTMX.A8ARH61p.js → cynefin-OW5HDTMX.B5dIZHJu.js} +1 -1
- package/web/_astro/{dagre-BM42HDAG.u28ZmqwR.js → dagre-BM42HDAG.DT70Q_Yw.js} +1 -1
- package/web/_astro/{diagram-2AECGRRQ.Dx8JcrGc.js → diagram-2AECGRRQ.DqHA3XBF.js} +1 -1
- package/web/_astro/{diagram-5GNKFQAL.BXJUG9GY.js → diagram-5GNKFQAL.BmCem957.js} +1 -1
- package/web/_astro/{diagram-KO2AKTUF.BtlMuWqW.js → diagram-KO2AKTUF.sn0-hrE0.js} +1 -1
- package/web/_astro/{diagram-LMA3HP47.C4T7qaAy.js → diagram-LMA3HP47.BSHe9tVc.js} +1 -1
- package/web/_astro/{diagram-OG6HWLK6.D5HECE10.js → diagram-OG6HWLK6.DHIc-86k.js} +1 -1
- package/web/_astro/{erDiagram-TEJ5UH35.B_hMR3yw.js → erDiagram-TEJ5UH35.Bxayrs7v.js} +1 -1
- package/web/_astro/{flowDiagram-I6XJVG4X.BAmpcYl3.js → flowDiagram-I6XJVG4X.BkzoE_5I.js} +1 -1
- package/web/_astro/{ganttDiagram-6RSMTGT7.DV1bSWK-.js → ganttDiagram-6RSMTGT7.okT6CvTo.js} +1 -1
- package/web/_astro/{gitGraphDiagram-PVQCEYII.DxYKkKrJ.js → gitGraphDiagram-PVQCEYII.CJuYbhC7.js} +1 -1
- package/web/_astro/{infoDiagram-5YYISTIA.BAWY2xMb.js → infoDiagram-5YYISTIA.RqLy7nBo.js} +1 -1
- package/web/_astro/{ishikawaDiagram-YF4QCWOH.CZssRn6V.js → ishikawaDiagram-YF4QCWOH.BwIcoagw.js} +1 -1
- package/web/_astro/{journeyDiagram-JHISSGLW.C--muARd.js → journeyDiagram-JHISSGLW.UB1VbWtH.js} +1 -1
- package/web/_astro/{kanban-definition-UN3LZRKU.D_QCK4et.js → kanban-definition-UN3LZRKU.AaxMKpTk.js} +1 -1
- package/web/_astro/{linear.DzrmTtZ0.js → linear.Nv_xOUjP.js} +1 -1
- package/web/_astro/{mermaid.core.Da03W3iu.js → mermaid.core.Bc4LqQgX.js} +4 -4
- package/web/_astro/{mindmap-definition-RKZ34NQL.6cy-8hR_.js → mindmap-definition-RKZ34NQL.oKUvU_qi.js} +1 -1
- package/web/_astro/{pieDiagram-4H26LBE5.C5rS1pdU.js → pieDiagram-4H26LBE5.DQk0oo03.js} +1 -1
- package/web/_astro/{quadrantDiagram-W4KKPZXB.w56GZZ6Q.js → quadrantDiagram-W4KKPZXB.BdDjESDa.js} +1 -1
- package/web/_astro/{requirementDiagram-4Y6WPE33.CipX3Pwu.js → requirementDiagram-4Y6WPE33.C2u9hUeH.js} +1 -1
- package/web/_astro/{sankeyDiagram-5OEKKPKP.C0VVzgJm.js → sankeyDiagram-5OEKKPKP.CDEoiJST.js} +1 -1
- package/web/_astro/{sequenceDiagram-3UESZ5HK.BX2dUUbF.js → sequenceDiagram-3UESZ5HK.D_hT_GAT.js} +1 -1
- package/web/_astro/{stateDiagram-AJRCARHV.ypCdgODQ.js → stateDiagram-AJRCARHV.DI8RYG0b.js} +1 -1
- package/web/_astro/{stateDiagram-v2-BHNVJYJU.In0baEtg.js → stateDiagram-v2-BHNVJYJU.Bkxz4DnP.js} +1 -1
- package/web/_astro/{timeline-definition-PNZ67QCA.CJN4Vkvl.js → timeline-definition-PNZ67QCA.DSY-kH3-.js} +1 -1
- package/web/_astro/{vennDiagram-CIIHVFJN.Cf8KkIPY.js → vennDiagram-CIIHVFJN.CpaDtuGr.js} +1 -1
- package/web/_astro/{wardleyDiagram-YWT4CUSO.DCZBo9xw.js → wardleyDiagram-YWT4CUSO.DujQWvo8.js} +1 -1
- package/web/_astro/{xychartDiagram-2RQKCTM6.Cm4v_MiJ.js → xychartDiagram-2RQKCTM6.DcM5Y4b9.js} +1 -1
- package/web/index.html +1 -1
- package/config/workflows/basic.yaml +0 -146
- package/config/workflows/docs-pipeline.yaml +0 -350
- package/config/workflows/feature-dev.yaml +0 -288
- package/plugins/sp/scripts/feature-dev-precheck.mjs +0 -146
- package/plugins/sp/scripts/feature-dev-precheck.ts +0 -238
- package/web/_astro/BoardApp.CHenHFia.js +0 -1
- package/web/_astro/channel.CbDHK5UQ.js +0 -1
package/plugins/sp/README.md
CHANGED
|
@@ -134,6 +134,7 @@ list this README is checked against.
|
|
|
134
134
|
| `dev-find-next` | Prompt-first feature frontier prioritizer — ranks the open feature frontier by derived importance/urgency with per-candidate evidence; gates unactionable features; emits tree defects as proposals only |
|
|
135
135
|
| `dev-fixall` | Fix all lint, type, and test errors systematically across the working tree |
|
|
136
136
|
| `dev-simplify` | Simplify recently-changed code for clarity without changing behavior — incremental, test-after-each, revert on regression |
|
|
137
|
+
| `dev-refactor` | Lens-routed refactoring with a preservation contract — taste lenses (api/architect/tests/ui) classify findings on the shared schema; cutting/breaking changes pause for operator approval; forwards to sp:code-refactoring |
|
|
137
138
|
| `dev-arch` | Survey a codebase (or module tree) for shallow modules and deepening opportunities — emit a ranked MARKDOWN candidate report that feeds the planning half; never auto-refactors |
|
|
138
139
|
| `dev-reverse` | Reverse-engineer a codebase — analyze unfamiliar repos, generate HLD/architecture docs, audit quality/security, and produce onboarding documentation |
|
|
139
140
|
| `dev-gitmsg` | Generate conventional commit message(s) from the current change set via one bounded diff capture, optionally commit |
|
|
@@ -199,6 +200,7 @@ plugins/sp/
|
|
|
199
200
|
│ ├── code-review/ # Pre-commit self-review + SECUA review lenses
|
|
200
201
|
│ │ └── references/{review-lenses, self-review-checklist}.md
|
|
201
202
|
│ ├── code-simplification/ # Behavior-preserving simplification
|
|
203
|
+
│ ├── code-refactoring/ # Lens-routed refactoring coordinator (shared finding schema, P1–P4 severity map, fix ladder, focus detection)
|
|
202
204
|
│ ├── code-testing/ # Testing / coverage competency
|
|
203
205
|
│ │ └── references/{unit-testing.md, stacks/{bun-ts, go, python}.md}
|
|
204
206
|
│ ├── code-verification/ # Verify + SECUA review
|
|
@@ -316,6 +318,7 @@ surface or run one workflow. All skills target the same five core platforms: `cl
|
|
|
316
318
|
| `code-review` | 1.0 | Pre-commit self-review checklist (6 categories, catches 60-80% of issues) + SECUA review lenses + findings processing |
|
|
317
319
|
| `code-simplification` | 1.0 | Behavior-preserving simplification — Chesterton's Fence, signal tables, incremental change + test-after-each, scope-to-changed |
|
|
318
320
|
| `code-improvement` | 1.0 | Architectural deepening — surface shallow/tightly-coupled modules and propose refactors that make them deep, testable, AI-navigable; backs `/sp:dev-arch` |
|
|
321
|
+
| `code-refactoring` | 1.0 | Lens-routed refactoring coordinator with a preservation contract — focus auto-detection, taste-lens dispatch, shared finding schema, P1–P4 severity map, objective/taste gates, fix ladder with revert-on-regression; backs `/sp:dev-refactor` |
|
|
319
322
|
| `functional-review` | 1.0 | Requirements-traceability assessment — per-requirement verdicts with file:line evidence that the implementation satisfies ALL task requirements; pipeline Phase 8b gate |
|
|
320
323
|
| `doubt-driven-development` | 1.0 | In-flight adversarial review of a non-trivial decision before committing it — hand artifact + contract to a fresh-context skeptic, reconcile, stop at 3 cycles |
|
|
321
324
|
| `source-driven-development` | 1.0 | Source-first verification — verify framework/API/library facts against primary sources before generating code; separates "the API exists" from "used correctly under its contract" |
|
|
@@ -340,10 +343,10 @@ surface or run one workflow. All skills target the same five core platforms: `cl
|
|
|
340
343
|
| `spur-composer` | 1.0 | Cross-noun composition — workflow catalog selection, the ephemeral→project→shared ladder, ADR-115 budgets, trace-driven rule tuning; applies accepted `spur-doctor` proposals through `spur` verbs; never judges its own output and never runs a recurring loop |
|
|
341
344
|
| `spur-doctor` | 1.0 | Cross-noun evaluation — read-only CLI evidence per noun (task/feature/rule/workflow/agent spec), reflection over `history-anatomy` findings through a closed action-class map, and a proposal table; writes nothing; diagnoses artifacts, not runtime environments (`spur agent doctor`'s job) |
|
|
342
345
|
| `redesign-web-ui` | 1.0 | Existing-UI visual upgrade — audit generic AI fingerprints, apply in-stack polish against `DESIGN.md` / live tokens, verify behavior and viewports; does not migrate frameworks |
|
|
343
|
-
| `taste-refactoring-api` |
|
|
344
|
-
| `taste-refactoring-ui` |
|
|
345
|
-
| `taste-refactoring-architect` |
|
|
346
|
-
| `taste-refactoring-tests` |
|
|
346
|
+
| `taste-refactoring-api` | 1.0 | API design and refactoring for REST/HTTP, RPC/gRPC, GraphQL, event contracts, and CLI surfaces; compatibility, security, and migration review |
|
|
347
|
+
| `taste-refactoring-ui` | 1.0 | UI design and refactoring with visual hierarchy, typography, spacing, color, and interaction review |
|
|
348
|
+
| `taste-refactoring-architect` | 1.0 | Architecture review, simplification, and refactoring; boundary modeling, dependency reduction, and migration planning |
|
|
349
|
+
| `taste-refactoring-tests` | 1.0 | Test suite refactoring for failure sensitivity, regression detection, and assertion strength; eliminates brittle mocks |
|
|
347
350
|
|
|
348
351
|
#### Bounded coexistence and retirement gate — `sp:issue-finding` (HA-S1 0661)
|
|
349
352
|
|
|
@@ -620,14 +623,11 @@ pipeline owns one lifecycle phase:
|
|
|
620
623
|
|
|
621
624
|
| Workflow | Phase | Entry command |
|
|
622
625
|
| --------------------------- | --------------------------------- | --------------------------------- |
|
|
623
|
-
| `basic.yaml` | Generic implement/check/fix | direct `spur workflow run` |
|
|
624
626
|
| `feature-lifecycle.yaml` | Feature status FSM | `spur feature update` |
|
|
625
627
|
| `task-lifecycle.yaml` | Task status FSM | `spur task update` |
|
|
626
628
|
| `task-pipeline.yaml` | Single-task execution | `/sp:dev-run` |
|
|
627
629
|
| `idea-pipeline.yaml` | Idea/planning → feature + tasks | `/sp:dev-idea`, `/sp:dev-plan` |
|
|
628
|
-
| `feature-dev.yaml` | Feature umbrella execution | `/sp:dev-runall --feature` |
|
|
629
630
|
| `wrapup-pipeline.yaml` | Post-execution wrap-up | `/sp:dev-wrap`, `/sp:dev-wrapall` |
|
|
630
|
-
| `docs-pipeline.yaml` | Docs-only task execution | `/sp:dev-run --mode implement` |
|
|
631
631
|
| `wayfinder-resolution.yaml` | Wayfinder ticket resolution loop | `spur workflow run` (free-form) |
|
|
632
632
|
|
|
633
633
|
### Lifecycle operations
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
description: Turn a vague idea into a feature with AC and a decomposed task batch — discovery, idea-eval, feature-create, AC, feature-check, system-design, decompose, batch-create (Design by default), handoff
|
|
3
3
|
role: planner
|
|
4
|
-
argument-hint: "\"<idea>\" [--auto] [--skip-design] [--approve-taste] [--agent <inline|auto|name>]"
|
|
4
|
+
argument-hint: "\"<idea>\" [--from-file <path>] [--auto] [--skip-design] [--approve-taste] [--agent <inline|auto|name>]"
|
|
5
5
|
allowed-tools: ["Bash", "Read", "Skill", "AskUserQuestion"]
|
|
6
6
|
---
|
|
7
7
|
|
|
@@ -14,7 +14,8 @@ contract below maps to that workflow's transitions.
|
|
|
14
14
|
|
|
15
15
|
| Flag | Description | Default |
|
|
16
16
|
| --- | --- | --- |
|
|
17
|
-
| `"<idea>"` | Vague idea to turn into a feature with AC and tasks. | required |
|
|
17
|
+
| `"<idea>"` | Vague idea to turn into a feature with AC and tasks. | required (or `--from-file`) |
|
|
18
|
+
| `--from-file` `<path>` | Read the idea from a file instead of the positional argument. Mutually exclusive with `"<idea>"` — exactly one must be present. The file's contents become the verbatim idea text (trimmed of surrounding whitespace only). Useful for long or multiline asks that are awkward to quote. | off |
|
|
18
19
|
| `--auto` | Skip objective HITL gates only (taste gates still pause). | off |
|
|
19
20
|
| `--skip-design` | Omit system-design and per-task Design. | off |
|
|
20
21
|
| `--approve-taste` | With `--auto`: set idea_approved + design_approved so idea-eval / design-approval do not pause. | off |
|
|
@@ -45,5 +46,11 @@ vars as subsets of `--approve-taste` (`idea_approved` / `design_approved`). Pref
|
|
|
45
46
|
- Omitted/`inline`: drive `idea-pipeline.yaml` through the [inline pipeline driver](../skills/spur-dev/references/inline-pipeline-driver.md). Do not launch `spur workflow run`, `spur agent run`, or a native subagent unless the operator explicitly requests delegation.
|
|
46
47
|
- `auto`/name: launch `spur workflow run idea-pipeline.yaml --async`, observe with one `workflow trace --follow`, and only report cancellation as stopped when `workflow cancel --json` returns `killed: true`.
|
|
47
48
|
- `Skill(skill="sp:spur-dev", args="idea $ARGUMENTS")`
|
|
49
|
+
- Pass the idea text through every hop **verbatim** — never paraphrase or shorten it in the nested
|
|
50
|
+
`Skill` call or stage prompts; long ideas lose their trailing asks when summarized at the hop.
|
|
51
|
+
- Before executing the pipeline's `start` state, persist the operator's idea argument (or the
|
|
52
|
+
`--from-file` contents) **unmodified** to `.spur/run/<run-id>-idea-input.md` (0887 R1); every
|
|
53
|
+
model-bearing stage prompt treats that file as the authoritative ask, and the precheck fails
|
|
54
|
+
the run when it is empty or missing.
|
|
48
55
|
- Stage contract (discovery → idea-eval → feature-create → AC → feature-check → system-design →
|
|
49
56
|
decompose → batch-create → ready-prepare → handoff): `plugins/sp/skills/spur-dev/references/dev-operations.md` § idea.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Lens-routed refactoring with a preservation contract — taste lenses classify findings against the shared schema; cutting/breaking changes pause for operator approval
|
|
3
|
+
role: reviewer
|
|
4
|
+
argument-hint: "[<description>] [--scope <path>] [--focus <api|architect|tests|ui|auto>] [--fix <none|blockers-first|all>] [--check <cmd>] [--agent <inline|auto|name>] [--auto]"
|
|
5
|
+
allowed-tools: ["Bash", "Read", "Edit", "Skill"]
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Dev Refactor
|
|
9
|
+
|
|
10
|
+
Wraps the **sp:code-refactoring** skill.
|
|
11
|
+
|
|
12
|
+
## Argument Flags
|
|
13
|
+
|
|
14
|
+
| Flag | Description | Default |
|
|
15
|
+
| --- | --- | --- |
|
|
16
|
+
| `[<description>]` | Free-text steering for the lenses (e.g. "pagination consistency"). | — |
|
|
17
|
+
| `--scope` `<path>` | Path bound; no edit may land outside it. | working tree |
|
|
18
|
+
| `--focus` `<api\|architect\|tests\|ui\|auto>` | Lens set; comma list allowed (`api,tests`). | auto |
|
|
19
|
+
| `--fix` `<none\|blockers-first\|all>` | Apply policy; `blockers-first` = P1/P2. | none |
|
|
20
|
+
| `--check` `<cmd>` | Verification command for baseline and per-fix checks. | project gate |
|
|
21
|
+
| `--agent` `<inline\|auto\|name>` | Who runs the model-bearing analysis. | inline |
|
|
22
|
+
| `--auto` | Skip objective gates only; cutting/breaking taste gates still pause. | off |
|
|
23
|
+
|
|
24
|
+
For shared semantics, see the [flag glossary](../skills/spur-dev/references/flag-glossary.md).
|
|
25
|
+
|
|
26
|
+
## Usage
|
|
27
|
+
|
|
28
|
+
/sp:dev-refactor [<description>] [--scope <path>] [--focus <api|architect|tests|ui|auto>] [--fix <none|blockers-first|all>] [--check <cmd>] [--agent <inline|auto|name>] [--auto]
|
|
29
|
+
|
|
30
|
+
## Implementation
|
|
31
|
+
|
|
32
|
+
- Apply the [inline-default execution-surface contract](../skills/spur-dev/references/cross-cutting.md#inline-default-execution-surface).
|
|
33
|
+
- `Skill(skill="sp:code-refactoring", args="$ARGUMENTS")`
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { getEnvVars } from '@gobing-ai/ts-utils';
|
|
1
2
|
/**
|
|
2
3
|
* Shared host-agent identification helpers — the **only** host-agent detection path
|
|
3
4
|
* in the sp plugin hooks.
|
|
@@ -22,11 +23,11 @@
|
|
|
22
23
|
* 3. `TERM_PROGRAM` — terminal identifier (e.g. `claude`, `ghostty`)
|
|
23
24
|
* 4. `SPUR_DEFAULT_AGENT` — configured default agent
|
|
24
25
|
*
|
|
25
|
-
* @param env - environment record (defaults to `
|
|
26
|
+
* @param env - environment record (defaults to `getEnvVars()`)
|
|
26
27
|
* @param fallback - value returned when no candidate matches (defaults to `undefined`)
|
|
27
28
|
*/
|
|
28
29
|
export function resolveAgentHint(
|
|
29
|
-
env: NodeJS.ProcessEnv =
|
|
30
|
+
env: NodeJS.ProcessEnv = getEnvVars(),
|
|
30
31
|
fallback: string | undefined = undefined,
|
|
31
32
|
): string | undefined {
|
|
32
33
|
const candidates = [env.SPUR_AGENT, env.CLAUDE_CODE_ENTRYPOINT, env.TERM_PROGRAM, env.SPUR_DEFAULT_AGENT];
|
|
@@ -45,11 +46,11 @@ export function resolveAgentHint(
|
|
|
45
46
|
* 3. `OPENAI_MODEL` — OpenAI API model
|
|
46
47
|
* 4. `CLAUDE_MODEL` — Claude Code model setting
|
|
47
48
|
*
|
|
48
|
-
* @param env - environment record (defaults to `
|
|
49
|
+
* @param env - environment record (defaults to `getEnvVars()`)
|
|
49
50
|
* @param fallback - value returned when no candidate matches (defaults to `undefined`)
|
|
50
51
|
*/
|
|
51
52
|
export function resolveModelHint(
|
|
52
|
-
env: NodeJS.ProcessEnv =
|
|
53
|
+
env: NodeJS.ProcessEnv = getEnvVars(),
|
|
53
54
|
fallback: string | undefined = undefined,
|
|
54
55
|
): string | undefined {
|
|
55
56
|
const candidates = [env.SPUR_MODEL, env.ANTHROPIC_MODEL, env.OPENAI_MODEL, env.CLAUDE_MODEL];
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
|
+
|
|
2
3
|
/**
|
|
3
4
|
* careful-guard — PreToolUse guard for destructive shell commands (task 0215, R3).
|
|
4
5
|
*
|
|
@@ -21,6 +22,7 @@
|
|
|
21
22
|
* adapter. This file owns the Claude Code payload/decision shape only.
|
|
22
23
|
*/
|
|
23
24
|
|
|
25
|
+
import { getEnvVar } from '@gobing-ai/ts-utils';
|
|
24
26
|
import { classifyCommand } from './destructive-policy';
|
|
25
27
|
|
|
26
28
|
interface ToolPayload {
|
|
@@ -43,7 +45,7 @@ function preToolUseDecision(decision: Decision, reason?: string): never {
|
|
|
43
45
|
}
|
|
44
46
|
|
|
45
47
|
async function main(): Promise<void> {
|
|
46
|
-
if (
|
|
48
|
+
if (getEnvVar('SPUR_CAREFUL') === 'off') preToolUseDecision('allow');
|
|
47
49
|
|
|
48
50
|
const stdinText = await Bun.stdin.text();
|
|
49
51
|
let payload: ToolPayload;
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
import { execSync } from 'node:child_process';
|
|
24
24
|
import { appendFileSync, existsSync, readFileSync, statSync, writeFileSync } from 'node:fs';
|
|
25
25
|
import { join, resolve, sep } from 'node:path';
|
|
26
|
+
import { getEnvVar } from '@gobing-ai/ts-utils';
|
|
26
27
|
|
|
27
28
|
/** Tools recorded by this hook (must match hooks.json PostToolUse matcher). */
|
|
28
29
|
export const ALLOWED_TOOLS = new Set(['Bash', 'Grep', 'Glob', 'Read', 'Write', 'Edit']);
|
|
@@ -411,7 +412,7 @@ export function readContextFreshness(contextDir: string): string | null {
|
|
|
411
412
|
// Entrypoint — thin wrapper; logic lives in {@link recordToolUseEvent} for unit coverage.
|
|
412
413
|
if (import.meta.main) {
|
|
413
414
|
void (async () => {
|
|
414
|
-
const dir = join(
|
|
415
|
+
const dir = join(getEnvVar('CLAUDE_PROJECT_DIR') ?? process.cwd(), '.spur', 'context');
|
|
415
416
|
try {
|
|
416
417
|
const stdinText = await Bun.stdin.text();
|
|
417
418
|
const payload = JSON.parse(stdinText) as ToolPayload;
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
import { execSync } from 'node:child_process';
|
|
16
16
|
import { appendFileSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
17
17
|
import { join } from 'node:path';
|
|
18
|
+
import { getEnvVar, getEnvVars } from '@gobing-ai/ts-utils';
|
|
18
19
|
import { resolveAgentHint, resolveModelHint } from './agent-hint';
|
|
19
20
|
import { checkContextFreshness } from './context-post-tool';
|
|
20
21
|
|
|
@@ -82,7 +83,7 @@ interface SessionFileBody {
|
|
|
82
83
|
* a stale file is only reachable from inside a live agent run, where reusing it is the correct
|
|
83
84
|
* answer anyway.
|
|
84
85
|
*/
|
|
85
|
-
export function resolveActiveSession(dir: string, now: Date, env: NodeJS.ProcessEnv =
|
|
86
|
+
export function resolveActiveSession(dir: string, now: Date, env: NodeJS.ProcessEnv = getEnvVars()): string | null {
|
|
86
87
|
let raw: string;
|
|
87
88
|
try {
|
|
88
89
|
raw = readFileSync(join(dir, '.session.json'), 'utf-8');
|
|
@@ -123,7 +124,7 @@ export function resolveActiveSession(dir: string, now: Date, env: NodeJS.Process
|
|
|
123
124
|
*/
|
|
124
125
|
export function recordSessionStart(
|
|
125
126
|
dir: string,
|
|
126
|
-
env: NodeJS.ProcessEnv =
|
|
127
|
+
env: NodeJS.ProcessEnv = getEnvVars(),
|
|
127
128
|
now: () => Date = () => new Date(),
|
|
128
129
|
): string | null {
|
|
129
130
|
try {
|
|
@@ -195,7 +196,7 @@ export function recordSessionStart(
|
|
|
195
196
|
// Entrypoint — kept minimal so unit coverage focuses on pure helpers above.
|
|
196
197
|
if (import.meta.main) {
|
|
197
198
|
try {
|
|
198
|
-
recordSessionStart(join(
|
|
199
|
+
recordSessionStart(join(getEnvVar('CLAUDE_PROJECT_DIR') ?? process.cwd(), '.spur', 'context'));
|
|
199
200
|
} catch {
|
|
200
201
|
/* fail-open */
|
|
201
202
|
}
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
|
|
18
18
|
import { appendFileSync, existsSync, readFileSync, rmSync } from 'node:fs';
|
|
19
19
|
import { join } from 'node:path';
|
|
20
|
+
import { getEnvVar } from '@gobing-ai/ts-utils';
|
|
20
21
|
|
|
21
22
|
interface LedgerEvent {
|
|
22
23
|
session: string;
|
|
@@ -53,7 +54,7 @@ function exitOk(): never {
|
|
|
53
54
|
}
|
|
54
55
|
|
|
55
56
|
async function main(): Promise<void> {
|
|
56
|
-
const dir = join(
|
|
57
|
+
const dir = join(getEnvVar('CLAUDE_PROJECT_DIR') ?? process.cwd(), '.spur', 'context');
|
|
57
58
|
|
|
58
59
|
const sessionFile = join(dir, '.session.json');
|
|
59
60
|
if (!existsSync(sessionFile)) exitOk();
|
|
@@ -23,6 +23,7 @@ import { appendFileSync, existsSync, mkdirSync, readFileSync, realpathSync, rmSy
|
|
|
23
23
|
import { homedir } from 'node:os';
|
|
24
24
|
import { isAbsolute, join, resolve } from 'node:path';
|
|
25
25
|
import type { ExtensionAPI } from '@earendil-works/pi-coding-agent';
|
|
26
|
+
import { getEnvVar, getEnvVars } from '@gobing-ai/ts-utils';
|
|
26
27
|
import { resolveAgentHint as resolveAgentHintShared, resolveModelHint as resolveModelHintShared } from '../agent-hint';
|
|
27
28
|
import { classifyCommand } from '../destructive-policy';
|
|
28
29
|
import { couldBeTaskFile } from '../task-file-policy';
|
|
@@ -81,7 +82,7 @@ function resolveSpurTaskOwnership(filePath: string): TaskOwnership {
|
|
|
81
82
|
spawnSync(cmd, args, { cwd: process.cwd(), encoding: 'utf-8', timeout: 8000 });
|
|
82
83
|
|
|
83
84
|
// 1. SPUR_BIN env override (may include args) or `spur` on PATH
|
|
84
|
-
const envBin =
|
|
85
|
+
const envBin = getEnvVar('SPUR_BIN') || 'spur';
|
|
85
86
|
const envParts = envBin.split(' ');
|
|
86
87
|
let res = run(envParts[0] ?? 'spur', [...envParts.slice(1), 'task', 'resolve', filePath, '--strict', '--json']);
|
|
87
88
|
// Only 0 (owned) / 1 (unowned) are valid spur exit codes; 127 (interpreter
|
|
@@ -203,8 +204,8 @@ function initSession(): void {
|
|
|
203
204
|
const sessionId = generateSessionId();
|
|
204
205
|
const session = {
|
|
205
206
|
session_id: sessionId,
|
|
206
|
-
agent: resolveAgentHintShared(
|
|
207
|
-
model: resolveModelHintShared(
|
|
207
|
+
agent: resolveAgentHintShared(getEnvVars(), 'pi'),
|
|
208
|
+
model: resolveModelHintShared(getEnvVars()),
|
|
208
209
|
started_at: new Date().toISOString(),
|
|
209
210
|
};
|
|
210
211
|
writeFileSync(sessionFilePath(), `${JSON.stringify(session, null, 2)}\n`);
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
22
|
import { spawnSync } from 'node:child_process';
|
|
23
|
+
import { getEnvVar } from '@gobing-ai/ts-utils';
|
|
23
24
|
import { couldBeTaskFile } from './task-file-policy';
|
|
24
25
|
|
|
25
26
|
interface ToolPayload {
|
|
@@ -40,7 +41,7 @@ function preToolUseDecision(decision: 'allow' | 'deny', reason?: string): never
|
|
|
40
41
|
|
|
41
42
|
/** Resolve whether a path is owned by a Spur task via `spur task resolve --strict --json`. */
|
|
42
43
|
function resolveSpurTaskOwnership(filePath: string, cwd: string): TaskOwnership {
|
|
43
|
-
const spurBin =
|
|
44
|
+
const spurBin = getEnvVar('SPUR_BIN') || 'spur';
|
|
44
45
|
const parts = spurBin.split(' ');
|
|
45
46
|
const cmd = parts[0] ?? 'spur';
|
|
46
47
|
const args = [...parts.slice(1), 'task', 'resolve', filePath, '--strict', '--json'];
|
|
@@ -54,7 +55,7 @@ function resolveSpurTaskOwnership(filePath: string, cwd: string): TaskOwnership
|
|
|
54
55
|
}
|
|
55
56
|
|
|
56
57
|
async function main(): Promise<void> {
|
|
57
|
-
if (
|
|
58
|
+
if (getEnvVar('SPUR_WRITE_GUARD') === 'off') preToolUseDecision('allow');
|
|
58
59
|
|
|
59
60
|
const stdinText = await Bun.stdin.text();
|
|
60
61
|
let payload: ToolPayload;
|
|
@@ -73,7 +74,7 @@ async function main(): Promise<void> {
|
|
|
73
74
|
// cannot name a task file — that is every ordinary source edit.
|
|
74
75
|
if (!couldBeTaskFile(filePath)) preToolUseDecision('allow');
|
|
75
76
|
|
|
76
|
-
const ownership = resolveSpurTaskOwnership(filePath,
|
|
77
|
+
const ownership = resolveSpurTaskOwnership(filePath, getEnvVar('CLAUDE_PROJECT_DIR') ?? process.cwd());
|
|
77
78
|
if (ownership === 'owned') {
|
|
78
79
|
preToolUseDecision(
|
|
79
80
|
'deny',
|