@gobing-ai/spur 0.3.85 → 0.3.86
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 +0 -5
- package/config/rules/boundary/env-var-hygiene.yaml +41 -0
- package/config/transition-shims.json +1 -1
- package/config/workflow-candidates.json +41 -0
- package/config/workflows/feature-lifecycle.yaml +4 -2
- package/config/workflows/feature-verification.yaml +70 -0
- package/config/workflows/idea-pipeline.yaml +24 -12
- 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 +0 -3
- 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/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-handoff.mjs +6 -1
- package/plugins/sp/scripts/idea-handoff.ts +4 -1
- package/plugins/sp/scripts/inline-pipeline-parity-check.ts +1 -1
- package/plugins/sp/scripts/inline-run-setup.ts +185 -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/spur-cli/references/workflows.md +8 -7
- package/plugins/sp/skills/spur-dev/references/cross-cutting.md +4 -5
- package/plugins/sp/skills/spur-dev/references/done-housekeeping.md +1 -1
- package/plugins/sp/skills/spur-dev/references/gate-checklists.md +2 -2
- package/plugins/sp/skills/spur-dev/references/inline-pipeline-driver.md +59 -1
- package/schemas/state-machine-workflow.schema.json +5 -0
- package/schemas/transition-flow-workflow.schema.json +5 -0
- package/spur.js +20988 -20652
- 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
|
@@ -620,14 +620,11 @@ pipeline owns one lifecycle phase:
|
|
|
620
620
|
|
|
621
621
|
| Workflow | Phase | Entry command |
|
|
622
622
|
| --------------------------- | --------------------------------- | --------------------------------- |
|
|
623
|
-
| `basic.yaml` | Generic implement/check/fix | direct `spur workflow run` |
|
|
624
623
|
| `feature-lifecycle.yaml` | Feature status FSM | `spur feature update` |
|
|
625
624
|
| `task-lifecycle.yaml` | Task status FSM | `spur task update` |
|
|
626
625
|
| `task-pipeline.yaml` | Single-task execution | `/sp:dev-run` |
|
|
627
626
|
| `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
627
|
| `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
628
|
| `wayfinder-resolution.yaml` | Wayfinder ticket resolution loop | `spur workflow run` (free-form) |
|
|
632
629
|
|
|
633
630
|
### Lifecycle operations
|
|
@@ -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',
|