@gobing-ai/spur 0.3.89 → 0.3.90
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/rules/boundary/sp-plugin-standalone.yaml +37 -0
- package/package.json +9 -9
- package/plugins/sp/lib/idea-handoff.generated.mjs +157 -150
- package/plugins/sp/plugin.json +1 -1
- package/plugins/sp/scripts/script-contract-check.ts +58 -0
- package/plugins/sp/skills/spur-cli/references/workflows.md +8 -3
- package/spur.js +535 -240
package/plugins/sp/plugin.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sp",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.90",
|
|
4
4
|
"description": "Spur — a local-first harness engineering toolkit that wraps mainstream coding agents with constraint checking, workflow orchestration, and history analytics.",
|
|
5
5
|
"extensions": {
|
|
6
6
|
"pi": ["./hooks/pi/guard-extension.ts"]
|
|
@@ -178,6 +178,47 @@ export function scanShippedSurfaces(pluginDir: string): Array<{ file: string; li
|
|
|
178
178
|
return matches;
|
|
179
179
|
}
|
|
180
180
|
|
|
181
|
+
// Bare-specifier value imports in bundled surfaces break `superskill install`, which
|
|
182
|
+
// bundles hooks/scripts on targets with no node_modules (task 0669; releases
|
|
183
|
+
// 0.3.81–0.3.88 failed with "Bundle failed" when scripts imported @gobing-ai/ts-utils).
|
|
184
|
+
// Type-only imports are erased before bundling, so they stay legal. Line-based
|
|
185
|
+
// statement walk (import/export statements are column 0 under biome) — lookahead
|
|
186
|
+
// regexes misbehave in Bun 1.3.x (JSC) when grouped with lazy quantifiers.
|
|
187
|
+
function findGobingAiValueImports(dir: string): { file: string; line: number }[] {
|
|
188
|
+
const hits: { file: string; line: number }[] = [];
|
|
189
|
+
let entries: string[];
|
|
190
|
+
try {
|
|
191
|
+
entries = readdirSync(dir);
|
|
192
|
+
} catch {
|
|
193
|
+
return hits;
|
|
194
|
+
}
|
|
195
|
+
for (const entry of entries) {
|
|
196
|
+
const full = join(dir, entry);
|
|
197
|
+
let st: ReturnType<typeof statSync>;
|
|
198
|
+
try {
|
|
199
|
+
st = statSync(full);
|
|
200
|
+
} catch {
|
|
201
|
+
continue;
|
|
202
|
+
}
|
|
203
|
+
if (st.isDirectory()) {
|
|
204
|
+
hits.push(...findGobingAiValueImports(full));
|
|
205
|
+
} else if (entry.endsWith('.ts')) {
|
|
206
|
+
const lines = readFileSync(full, 'utf8').split('\n');
|
|
207
|
+
let stmtStart = 0;
|
|
208
|
+
for (let i = 0; i < lines.length; i++) {
|
|
209
|
+
if (/^\s*(?:import|export)\b/.test(lines[i])) stmtStart = i;
|
|
210
|
+
if (/(?:from\s*|import\s*|import\s*\(\s*)['"]@gobing-ai\//.test(lines[i])) {
|
|
211
|
+
const opener = lines.slice(stmtStart, i + 1).join(' ');
|
|
212
|
+
if (!/^\s*(?:import|export)\s+type\b/.test(opener)) {
|
|
213
|
+
hits.push({ file: full, line: i + 1 });
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
return hits;
|
|
220
|
+
}
|
|
221
|
+
|
|
181
222
|
export function validateContract(manifest: ScriptManifest, scriptsDir: string, pluginDir: string): Violation[] {
|
|
182
223
|
const violations: Violation[] = [];
|
|
183
224
|
const { tsFiles, mjsFiles } = listDiskScripts(scriptsDir);
|
|
@@ -280,6 +321,23 @@ export function validateContract(manifest: ScriptManifest, scriptsDir: string, p
|
|
|
280
321
|
});
|
|
281
322
|
}
|
|
282
323
|
|
|
324
|
+
// Rule 5: bundled surfaces (scripts, hooks, lib) must not value-import @gobing-ai/*.
|
|
325
|
+
// superskill install bundles them where no node_modules exists; resolution then
|
|
326
|
+
// depends on the host superskill's private dep tree (0.3.28+ happens to carry
|
|
327
|
+
// ts-utils — an accident we do not depend on). Vendor into plugins/sp/lib/ instead.
|
|
328
|
+
for (const dir of [scriptsDir, join(pluginDir, 'hooks'), join(pluginDir, 'lib')]) {
|
|
329
|
+
for (const hit of findGobingAiValueImports(dir)) {
|
|
330
|
+
violations.push({
|
|
331
|
+
kind: 'gobing_ai_import',
|
|
332
|
+
target: `${hit.file}:${hit.line}`,
|
|
333
|
+
message:
|
|
334
|
+
`bundled surface ${hit.file}:${hit.line} value-imports @gobing-ai/* — ` +
|
|
335
|
+
'superskill install bundles it with no node_modules ("Bundle failed", task 0669). ' +
|
|
336
|
+
'Vendor into plugins/sp/lib/ or use a relative import; `import type` is exempt.',
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
283
341
|
return violations;
|
|
284
342
|
}
|
|
285
343
|
|
|
@@ -108,7 +108,7 @@ The skill's logic divides by **whether the LLM adds value**:
|
|
|
108
108
|
| --------- | --------- | ----- | ------------------ |
|
|
109
109
|
| `validate` | `spur workflow validate` (CLI) | `<file> [--no-schema]` | Schema + semantic verdict |
|
|
110
110
|
| `run` | `spur workflow run` (CLI) | `<file> [--run-id <id>] [--vars <json>] [--dry-run] [--async] [--no-plan] [--quiet/--silent/--verbose] [--detail <level>] [--trace-file] [--no-log] [--steer]` | Terminal state reached (sync) or run started (async); trace readable |
|
|
111
|
-
| `continue` | `spur workflow continue` (CLI) | `[run-id] [--yes] [--answer <yes\|no\|cancel>]` | Resume a paused
|
|
111
|
+
| `continue` | `spur workflow continue` (CLI) | `[run-id] [--yes] [--answer <yes\|no\|cancel>] [--async] [--no-log]` | Resume a paused or interrupted run (omit id -> most recent resumable); `--answer` injects a gate answer before guard re-evaluation and is required headless (0901 R3); `--async` detaches the resume (0901 R4) |
|
|
112
112
|
| `cancel` | `spur workflow cancel` (CLI) | `<run-id>` | Single non-terminal run marked failed (SIGTERM async worker when live) |
|
|
113
113
|
| `clean` | `spur workflow clean` (CLI) | `[--older-than <min>] [--force] [--logs] [--dry-run]` | Bulk-finalize stale `running`/`pending` runs as failed **and** reclaim retained run logs older than `workflow.logRetentionDays` (30d default) |
|
|
114
114
|
| `list` | `spur workflow list` (CLI) | — | Available workflow **YAML definition files** (not run records) |
|
|
@@ -258,7 +258,7 @@ the operator accepts it, and never hot-edit a running workflow's shell in place.
|
|
|
258
258
|
spur workflow validate <file> [--no-schema] [--json]
|
|
259
259
|
spur workflow show <file> [--format <mermaid|todo>] [--json]
|
|
260
260
|
spur workflow run <file> [--run-id <id>] [--vars <json>] [--dry-run] [--async] [--no-plan] [--quiet/--silent/--verbose] [--detail <level>] [--trace-file] [--no-log] [--steer] [--json]
|
|
261
|
-
spur workflow continue [run-id] [--yes] [--answer <yes|no|cancel>] [--json]
|
|
261
|
+
spur workflow continue [run-id] [--yes] [--answer <yes|no|cancel>] [--async] [--no-log] [--json]
|
|
262
262
|
spur workflow cancel <run-id> [--json]
|
|
263
263
|
spur workflow clean [--older-than <minutes>] [--force] [--logs] [--dry-run] [--json]
|
|
264
264
|
spur workflow list [--json]
|
|
@@ -318,7 +318,12 @@ HITL pause/resume: a run that hits a HITL action pauses; resume with `spur workf
|
|
|
318
318
|
(`--yes` skips confirmation). A headless `hitl.confirm` persists a default `no` before pausing -
|
|
319
319
|
use `--answer yes|no|cancel` to inject the operator's gate answer before guard re-evaluation (0433).
|
|
320
320
|
`--answer` is distinct from `--yes`: `--yes` skips the CLI resume prompt, `--answer` sets the HITL
|
|
321
|
-
gate answer.
|
|
321
|
+
gate answer. 0901: resumes accept interrupted runs too (rerun-enter re-executes the interrupted
|
|
322
|
+
node and needs `resumeRerun: true` on the target state); a headless (`--json`/non-TTY) continue
|
|
323
|
+
without `--answer` is refused (exit 2); `--async` detaches the resume and reports started/failed
|
|
324
|
+
after the worker claims the run; resumed runs write the consolidated run log and pass shell
|
|
325
|
+
streams through the secret redactor + 64 KiB tail unless `--no-log`. Cancel one live/paused run
|
|
326
|
+
with `cancel <run-id>`; bulk-finalize orphans stuck in
|
|
322
327
|
`running`/`pending` with `clean` (`--older-than` default 30 minutes, or `--force`).
|
|
323
328
|
|
|
324
329
|
**Schema resolution parity (0431):** `validate` and `run` both load the workflow through
|