@gobing-ai/spur 0.4.31 → 0.4.33
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gobing-ai/spur",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.33",
|
|
4
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
5
|
"keywords": [
|
|
6
6
|
"spur",
|
package/plugins/sp/plugin.json
CHANGED
|
@@ -72,11 +72,16 @@ mode; `batch-create` surfaces per-child `warnings` rows (`[{"wbs", "warnings"}]`
|
|
|
72
72
|
when non-empty) in `--json` and prints `<wbs>: <warning>` lines to stderr in human mode;
|
|
73
73
|
`update --section` section writes carried this advisory already.
|
|
74
74
|
|
|
75
|
+
When an advisory fires, split the task instead of growing it: decompose into smaller tasks before
|
|
76
|
+
pipeline execution (execution-workflow.md, "Split oversized tasks before pipeline execution").
|
|
77
|
+
`create --requirements/--plan` and `batch-create` body fields exist to author the split tasks'
|
|
78
|
+
content up front — not to accumulate more into one oversized task.
|
|
79
|
+
|
|
75
80
|
## Verb map
|
|
76
81
|
|
|
77
82
|
| Verb | Purpose | Key flags |
|
|
78
83
|
| ---- | ------- | --------- |
|
|
79
|
-
| `create <title>` | Allocate a new task (race-safe WBS) | `--feature <id>` `--no-reopen` `--parent <wbs>` `--template <variant>` `--dedupe-within <s>` `--allow-duplicate-name` `--skip-ready` `--agent <selector>` `--folder` `--json` |
|
|
84
|
+
| `create <title>` | Allocate a new task (race-safe WBS) | `--feature <id>` `--no-reopen` `--parent <wbs>` `--template <variant>` `--requirements <text>` `--plan <text>` `--dedupe-within <s>` `--allow-duplicate-name` `--skip-ready` `--agent <selector>` `--folder` `--json` |
|
|
80
85
|
| `show <wbs>` | Print one task's frontmatter + body; section-filtered or summary mode (1325) | `--section <name>` `--sections <csv>` `--summary` `--folder` `--json` |
|
|
81
86
|
| `update <wbs> [status]` | Lifecycle transition, section replace, **or** frontmatter set | `--section <name> --from-file <path>` `--assignee <spec-id>` (exclusive with `--section`) `--feature <id>` `--no-reopen` `--priority <p>` `--ac-numbering task-local` `--ac-altitude <a>` `--estimate-hours <n>` `--no-lifecycle` `--force-done` `--reason <text>` `--provenance-bypass` `--verdict-dir <path>` `--folder` `--json` |
|
|
82
87
|
| `deps <wbs> <op> [values...]` | Mutate `dependencies[]` frontmatter array (ops: `set`, `add`, `remove`, `clear`) | `--folder` `--json` |
|
package/spur.js
CHANGED
|
@@ -44082,6 +44082,7 @@ async function messageRollup(db, sel, opts) {
|
|
|
44082
44082
|
return db.queryAll(`WITH filtered AS (
|
|
44083
44083
|
SELECT m.source, m.session_id, m.model, m.ts, m.input_tokens, m.output_tokens,
|
|
44084
44084
|
m.cache_read_tokens, m.cache_write_tokens, m.cost_usd, m.role, m.duration_ms,
|
|
44085
|
+
m.disposition,
|
|
44085
44086
|
ROW_NUMBER() OVER (PARTITION BY m.request_id ORDER BY m.rowid DESC) AS rn,
|
|
44086
44087
|
m.request_id
|
|
44087
44088
|
FROM history_message m
|
|
@@ -44097,7 +44098,7 @@ async function messageRollup(db, sel, opts) {
|
|
|
44097
44098
|
'unknown'
|
|
44098
44099
|
) AS model,
|
|
44099
44100
|
ts, input_tokens, output_tokens, cache_read_tokens, cache_write_tokens,
|
|
44100
|
-
cost_usd, role, duration_ms
|
|
44101
|
+
cost_usd, role, duration_ms, disposition
|
|
44101
44102
|
FROM filtered WHERE request_id IS NULL OR rn = 1
|
|
44102
44103
|
)
|
|
44103
44104
|
SELECT source, model, DATE(ts) AS day,
|
|
@@ -44108,9 +44109,12 @@ async function messageRollup(db, sel, opts) {
|
|
|
44108
44109
|
SUM(cache_write_tokens) AS cacheWriteTokens,
|
|
44109
44110
|
SUM(cost_usd) AS costUsd,
|
|
44110
44111
|
SUM(CASE WHEN input_tokens IS NOT NULL OR output_tokens IS NOT NULL THEN 1 ELSE 0 END) AS recordsWithUsage,
|
|
44111
|
-
|
|
44112
|
-
|
|
44113
|
-
|
|
44112
|
+
-- 1328: latency aggregates exclude collapsed poll rows \u2014 the duration
|
|
44113
|
+
-- backfill hands poll duplicates derived durations, so executor-latency
|
|
44114
|
+
-- means/samples stay unpolluted (1324 R3's rollup-chain residue).
|
|
44115
|
+
SUM(CASE WHEN role = 'assistant' AND disposition <> 'poll-duplicate' THEN duration_ms END) AS assistantDurationMs,
|
|
44116
|
+
SUM(CASE WHEN role = 'assistant' AND duration_ms IS NULL AND disposition <> 'poll-duplicate' THEN 1 ELSE 0 END) AS assistantDurationUnmeasured,
|
|
44117
|
+
SUM(CASE WHEN role = 'assistant' AND duration_ms > 0 AND disposition <> 'poll-duplicate' THEN 1 ELSE 0 END) AS assistantDurationSamples
|
|
44114
44118
|
FROM selected
|
|
44115
44119
|
GROUP BY source, model, DATE(ts)`, ...params, ...wm.params);
|
|
44116
44120
|
}
|
|
@@ -109457,6 +109461,7 @@ class AgentRunExecutor {
|
|
|
109457
109461
|
let result;
|
|
109458
109462
|
let invocation;
|
|
109459
109463
|
let dispatchStartedAt = Date.now();
|
|
109464
|
+
let lifecycleStarted = false;
|
|
109460
109465
|
const getDb = this.ctx.getDb;
|
|
109461
109466
|
let sessionObserver;
|
|
109462
109467
|
if (getDb !== undefined) {
|
|
@@ -109634,7 +109639,8 @@ class AgentRunExecutor {
|
|
|
109634
109639
|
...sessionId !== undefined ? { sessionId } : {},
|
|
109635
109640
|
...translated !== undefined && prompt !== undefined ? { translatedFrom: traceSafePrompt(prompt) } : {}
|
|
109636
109641
|
};
|
|
109637
|
-
if (
|
|
109642
|
+
if (!lifecycleStarted) {
|
|
109643
|
+
lifecycleStarted = true;
|
|
109638
109644
|
lifecycle.start({
|
|
109639
109645
|
agent,
|
|
109640
109646
|
...model !== undefined ? { model } : {},
|
|
@@ -128869,7 +128875,9 @@ ${templateBackground}`;
|
|
|
128869
128875
|
featureId: params.featureId,
|
|
128870
128876
|
parentWbs: params.parentWbs,
|
|
128871
128877
|
template: params.template,
|
|
128872
|
-
explicitStatus: params.status
|
|
128878
|
+
explicitStatus: params.status,
|
|
128879
|
+
requirements: params.requirements,
|
|
128880
|
+
plan: params.plan
|
|
128873
128881
|
});
|
|
128874
128882
|
this.validateCandidateOrThrow(params.title, shape);
|
|
128875
128883
|
let featureReopened;
|
|
@@ -146695,6 +146703,14 @@ function readWorkspaceGraph(cwd) {
|
|
|
146695
146703
|
} catch {
|
|
146696
146704
|
return { byName: new Map, dependents: new Map };
|
|
146697
146705
|
}
|
|
146706
|
+
const unsupported = globs.find((glob) => glob.includes("*") && (!glob.endsWith("/*") || glob === "/*"));
|
|
146707
|
+
if (unsupported !== undefined) {
|
|
146708
|
+
return {
|
|
146709
|
+
byName: new Map,
|
|
146710
|
+
dependents: new Map,
|
|
146711
|
+
unsupported: `workspaces glob ${JSON.stringify(unsupported)} is not a supported shape (only \`dir/*\` globs and literal dirs expand)`
|
|
146712
|
+
};
|
|
146713
|
+
}
|
|
146698
146714
|
const dirs = new Set;
|
|
146699
146715
|
for (const glob of globs) {
|
|
146700
146716
|
if (glob.endsWith("/*")) {
|
|
@@ -146779,7 +146795,10 @@ function lightScope(changedFiles, exists = existsSync23, graph) {
|
|
|
146779
146795
|
}
|
|
146780
146796
|
}
|
|
146781
146797
|
let fallback;
|
|
146782
|
-
if (graph !== undefined) {
|
|
146798
|
+
if (graph?.unsupported !== undefined) {
|
|
146799
|
+
fallback = `${graph.unsupported} \u2014 full suite required`;
|
|
146800
|
+
}
|
|
146801
|
+
if (fallback === undefined && graph !== undefined) {
|
|
146783
146802
|
for (const file of changedFiles) {
|
|
146784
146803
|
if (file.startsWith("plugins/sp/"))
|
|
146785
146804
|
continue;
|
|
@@ -159910,7 +159929,7 @@ ${result.wbs} (${result.status}): ${result.pass ? "PASS" : "FAIL"}`);
|
|
|
159910
159929
|
init_src4();
|
|
159911
159930
|
init_src2();
|
|
159912
159931
|
function registerTaskCreateCommand(task, context) {
|
|
159913
|
-
task.command("create").summary("Create a new task with race-safe WBS allocation.").argument("<title>", "Task title").option(...SHARED_OPTIONS.featureTrace).option("--parent <wbs>", "Parent WBS for sub-task grouping").option("--template <variant>", `Template variant (${TASK_VARIANTS.join("|")})`).option("--no-reopen", "Do not reopen a 'verifying' parent feature to 'active'").option(...SHARED_OPTIONS.folderTasks).option("--dedupe-within <seconds>", "Override the default dedup window (seconds). Guard is on (300s) by default when --feature is set.", Number).option("--allow-duplicate-name", "Disable the dedup guard entirely (creates anyway)").option("--skip-ready", "Skip ready preparation (backlog capture only, no model dispatch)").option("--agent <selector>", "Agent used for ready preparation (defaults to the configured agent)").option(...SHARED_OPTIONS.json).option(...SHARED_OPTIONS.jsonEnvelope).action(async (title, options) => {
|
|
159932
|
+
task.command("create").summary("Create a new task with race-safe WBS allocation.").argument("<title>", "Task title").option(...SHARED_OPTIONS.featureTrace).option("--parent <wbs>", "Parent WBS for sub-task grouping").option("--template <variant>", `Template variant (${TASK_VARIANTS.join("|")})`).option("--requirements <text>", "Pre-filled Requirements body (normalized like batch items)").option("--plan <text>", "Pre-filled Plan body (ordered checklist)").option("--no-reopen", "Do not reopen a 'verifying' parent feature to 'active'").option(...SHARED_OPTIONS.folderTasks).option("--dedupe-within <seconds>", "Override the default dedup window (seconds). Guard is on (300s) by default when --feature is set.", Number).option("--allow-duplicate-name", "Disable the dedup guard entirely (creates anyway)").option("--skip-ready", "Skip ready preparation (backlog capture only, no model dispatch)").option("--agent <selector>", "Agent used for ready preparation (defaults to the configured agent)").option(...SHARED_OPTIONS.json).option(...SHARED_OPTIONS.jsonEnvelope).action(async (title, options) => {
|
|
159914
159933
|
if (options.template !== undefined && !TASK_VARIANTS.includes(options.template)) {
|
|
159915
159934
|
writeCreateJsonError(context, options, "invalid-usage", `Unknown template variant "${options.template}". Valid: ${TASK_VARIANTS.join(", ")}`);
|
|
159916
159935
|
context.setExitCode(2);
|
|
@@ -159933,6 +159952,8 @@ function registerTaskCreateCommand(task, context) {
|
|
|
159933
159952
|
featureId: options.feature,
|
|
159934
159953
|
parentWbs: options.parent,
|
|
159935
159954
|
template: options.template,
|
|
159955
|
+
requirements: options.requirements,
|
|
159956
|
+
plan: options.plan,
|
|
159936
159957
|
noReopen: options.reopen === false,
|
|
159937
159958
|
dedupeWithinSec: options.allowDuplicateName ? null : options.dedupeWithin
|
|
159938
159959
|
});
|
|
@@ -160766,6 +160787,11 @@ function parseCsvSections(csv) {
|
|
|
160766
160787
|
function registerTaskShowCommand(task, context) {
|
|
160767
160788
|
task.command("show").alias("get").summary("Show a task by WBS.").argument("<wbs>", "Task WBS number").option(...SHARED_OPTIONS.folderTasks).option(...SHARED_OPTIONS.sectionShowFilter, collectSection, []).option("--sections <csv>", 'Comma-separated section names to show (e.g. "Background,Plan"); combined with --section').option("--summary", "Print frontmatter metadata plus a section index (name, heading, byte count) and total file size \u2014 no section bodies", false).option(...SHARED_OPTIONS.json).option(...SHARED_OPTIONS.jsonEnvelope).action(async (wbs, options) => {
|
|
160768
160789
|
const requested = [...options.section ?? [], ...parseCsvSections(options.sections)];
|
|
160790
|
+
if (options.sections !== undefined && parseCsvSections(options.sections).length === 0) {
|
|
160791
|
+
writeJsonError(context.output, options, `--sections "${options.sections}" carries no usable section names`, "VALIDATION_FAILED");
|
|
160792
|
+
context.setExitCode(2);
|
|
160793
|
+
return;
|
|
160794
|
+
}
|
|
160769
160795
|
if (options.summary === true && requested.length > 0) {
|
|
160770
160796
|
writeJsonError(context.output, options, "--summary cannot be combined with --section/--sections", "VALIDATION_FAILED");
|
|
160771
160797
|
context.setExitCode(2);
|
|
@@ -166039,7 +166065,7 @@ init_src2();
|
|
|
166039
166065
|
var CLI_CONFIG = {
|
|
166040
166066
|
binaryName: "spur",
|
|
166041
166067
|
binaryLabel: "spur",
|
|
166042
|
-
binaryVersion: "0.4.
|
|
166068
|
+
binaryVersion: "0.4.33",
|
|
166043
166069
|
configDir: ".spur",
|
|
166044
166070
|
configFile: ".spur/config.yaml",
|
|
166045
166071
|
databaseFile: ".spur/spur.db"
|
|
@@ -173778,7 +173804,7 @@ init_dist5();
|
|
|
173778
173804
|
import { homedir as homedir17 } from "os";
|
|
173779
173805
|
import { basename as basename23, join as join95, relative as relative19, resolve as resolve37 } from "path";
|
|
173780
173806
|
// ../server/package.json
|
|
173781
|
-
var version4 = "0.4.
|
|
173807
|
+
var version4 = "0.4.33";
|
|
173782
173808
|
|
|
173783
173809
|
// ../server/src/modules/health/index.ts
|
|
173784
173810
|
var startedAt = Date.now();
|