@gobing-ai/spur 0.3.2 → 0.3.3

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.3.2",
3
+ "version": "0.3.3",
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",
@@ -2,7 +2,7 @@
2
2
  "$schema": "http://json-schema.org/draft-07/schema#",
3
3
  "$id": "https://gobing.ai/spur/schemas/section-matrix.schema.json",
4
4
  "title": "Section-Status-Matrix Schema",
5
- "description": "Validates config/tasks/section-matrix.yaml — which sections are required/optional/forbidden per task status. Design §3.2. Authored for ts-runtime's loadStructuredConfig validator (supports properties/required/additionalProperties + $defs/$ref/enum; NOT patternProperties/uniqueItems).",
5
+ "description": "Validates the shipped section-matrix.yaml — which sections are required/optional/forbidden per task status. Design §3.2. Authored for ts-runtime's loadStructuredConfig validator (supports properties/required/additionalProperties + $defs/$ref/enum; NOT patternProperties/uniqueItems).",
6
6
  "type": "object",
7
7
  "required": ["variants"],
8
8
  "additionalProperties": false,
@@ -15,7 +15,7 @@ bootstrap:
15
15
  console: false
16
16
  json: false
17
17
  file: true
18
- filePath: .spur/spur.log # relative to project root
18
+ filePath: .spur/logs/spur.log # relative to project root
19
19
  telemetry:
20
20
  enabled: false # OFF by default for CLI (per-invocation latency)
21
21
  serviceName: spur
@@ -0,0 +1,32 @@
1
+ $schema: "@gobing-ai/spur/schemas/rule-file.schema.json"
2
+ # Runtime-path boundary rule (task 0217, R6) — zero `config/(plugins|rules|tasks|templates|workflows)`
3
+ # references in agent-facing instructions and runtime source code. `config/` is the build-time
4
+ # bundled-asset source-of-truth (ADR-015); `.spur/` is the runtime configuration directory that
5
+ # agents and runtime code MUST reference. A `config/...` literal in scope teaches the wrong
6
+ # convention and propagates confusion into every project created via `/sp:spur-init`.
7
+ #
8
+ # Blanket scope (all file types across apps/packages/plugins/sp) chosen deliberately:
9
+ # even build-time JSDoc and test-fixture `config/` literals are caught, forcing rephrase rather
10
+ # than false-positive triage. See task 0217 Design "Standing enforcement (R6)" for rationale.
11
+ #
12
+ # This is a STANDING gate (not transitional like rg-migration.yaml) — it runs on every pre-check.
13
+ include:
14
+ - "apps/**"
15
+ - "packages/**"
16
+ - "plugins/sp/**"
17
+ exclude:
18
+ - "**/node_modules/**"
19
+ - "**/dist/**"
20
+ rules:
21
+ - id: sp-runtime-path
22
+ description: >
23
+ Use `.spur/` paths for runtime configuration references, not `config/`. `config/` is the
24
+ build-time bundled-asset source-of-truth (ADR-015); `.spur/` is the runtime directory.
25
+ Agent-facing instructions (`plugins/sp/`) and runtime code (`apps/`, `packages/`) MUST NOT
26
+ contain literal `config/plugins`, `config/rules`, `config/tasks`, `config/templates`, or
27
+ `config/workflows` path references.
28
+ severity: error
29
+ evaluator:
30
+ type: rg
31
+ config:
32
+ pattern: "config/(plugins|rules|tasks|templates|workflows)"
package/spur.js CHANGED
@@ -59693,7 +59693,7 @@ function gitDiffU0(cwd) {
59693
59693
  var init_task_record = () => {};
59694
59694
 
59695
59695
  // ../../packages/app/src/services/task-service.ts
59696
- import { dirname as dirname8, isAbsolute, relative as relative2, resolve as resolve2 } from "path";
59696
+ import { isAbsolute, relative as relative2, resolve as resolve2 } from "path";
59697
59697
  function patchFrontmatterField(rendered, key, value) {
59698
59698
  const existingRe = new RegExp(`^(?=\\s*${escapeRegex2(key)}:)`, "m");
59699
59699
  if (existingRe.test(rendered)) {
@@ -60276,8 +60276,8 @@ ${block}` : block);
60276
60276
  resolveListDir(folder) {
60277
60277
  if (folder === undefined)
60278
60278
  return this.ctx.tasksDir;
60279
- const root = resolve2(dirname8(this.ctx.tasksDir));
60280
- const candidate = resolve2(root, folder);
60279
+ const root = this.ctx.fs.resolve(".");
60280
+ const candidate = this.ctx.fs.resolve(folder);
60281
60281
  const rel = relative2(root, candidate);
60282
60282
  if (rel.startsWith("..") || isAbsolute(rel)) {
60283
60283
  throw new Error(`Invalid folder: ${folder} escapes the planning workspace`);
@@ -60687,7 +60687,7 @@ var init_team_service = __esm(() => {
60687
60687
  import { execFile } from "child_process";
60688
60688
  import { existsSync as existsSync4 } from "fs";
60689
60689
  import { mkdir, writeFile } from "fs/promises";
60690
- import { dirname as dirname9, isAbsolute as isAbsolute2, join as join10 } from "path";
60690
+ import { dirname as dirname8, isAbsolute as isAbsolute2, join as join10 } from "path";
60691
60691
  import { promisify as promisify3 } from "util";
60692
60692
 
60693
60693
  class AgentRunActionRunner {
@@ -60742,7 +60742,7 @@ class AgentRunActionRunner {
60742
60742
  const ok2 = exitCode2 === 0;
60743
60743
  if (answerFile !== undefined) {
60744
60744
  const target = isAbsolute2(answerFile) ? answerFile : join10(cwd, answerFile);
60745
- await mkdir(dirname9(target), { recursive: true });
60745
+ await mkdir(dirname8(target), { recursive: true });
60746
60746
  await writeFile(target, answer, "utf8");
60747
60747
  }
60748
60748
  if (ok2 && expectFile !== undefined) {
@@ -60844,7 +60844,7 @@ async function writePartialWorkArtifact(context3, agentLabel, captured, cwd) {
60844
60844
  ].join(`
60845
60845
  `);
60846
60846
  const target = join10(cwd, ".spur", "run", `${context3.runId}-${context3.stateOrNodeId}-partial.md`);
60847
- await mkdir(dirname9(target), { recursive: true });
60847
+ await mkdir(dirname8(target), { recursive: true });
60848
60848
  await writeFile(target, body, "utf8");
60849
60849
  } catch {}
60850
60850
  }
@@ -69925,7 +69925,7 @@ import { join as join13, resolve as resolve5 } from "path";
69925
69925
  var CLI_CONFIG = {
69926
69926
  binaryName: "spur",
69927
69927
  binaryLabel: "spur",
69928
- binaryVersion: "0.3.2",
69928
+ binaryVersion: "0.3.3",
69929
69929
  configDir: ".spur",
69930
69930
  configFile: ".spur/config.yaml",
69931
69931
  databaseFile: ".spur/spur.db"
@@ -70059,7 +70059,7 @@ function registerInitCommand(program2, context3) {
70059
70059
  " logging:",
70060
70060
  " enabled: true",
70061
70061
  " level: info",
70062
- " console: true",
70062
+ " console: false",
70063
70063
  " json: true",
70064
70064
  " file: true",
70065
70065
  ` filePath: ${CLI_CONFIG.configDir}/logs/spur.log`,
@@ -70526,8 +70526,9 @@ init_src();
70526
70526
 
70527
70527
  // ../server/src/serve.ts
70528
70528
  init_src3();
70529
+ init_loader();
70529
70530
  init_src2();
70530
- import { dirname as dirname10, isAbsolute as isAbsolute3, join as join16 } from "path";
70531
+ import { dirname as dirname9, isAbsolute as isAbsolute3, join as join16 } from "path";
70531
70532
  init_dist3();
70532
70533
 
70533
70534
  // ../server/src/bootstrap.ts
@@ -78682,7 +78683,7 @@ function serverBootstrapConfig(env) {
78682
78683
  const raw2 = env.SPUR_TEAM_AUTOSTART;
78683
78684
  const teamAutostart = raw2 ? raw2.split(",").map((s) => s.trim()).filter((s) => s.length > 0) : [];
78684
78685
  return {
78685
- logging: { enabled: !isTest, level: env.SPUR_LOG_LEVEL ?? "info" },
78686
+ logging: { enabled: !isTest, level: env.SPUR_LOG_LEVEL ?? "info", console: false },
78686
78687
  telemetry: { enabled: false },
78687
78688
  events: { enabled: true },
78688
78689
  jobqueue: { enabled: !isTest },
@@ -78964,7 +78965,8 @@ var defaultDeps = {
78964
78965
  const { NodeSchedulerAdapter: NodeSchedulerAdapter2 } = await Promise.resolve().then(() => (init_scheduler_node(), exports_scheduler_node));
78965
78966
  return new NodeSchedulerAdapter2;
78966
78967
  },
78967
- openUrl
78968
+ openUrl,
78969
+ resolveConfigFile
78968
78970
  };
78969
78971
  function registerSchedulerEntries(scheduler3, ctx) {
78970
78972
  scheduler3.register(SYSTEM_EVENTS_PRUNE_CRON, async () => {
@@ -79021,7 +79023,7 @@ async function runTaskActionJob(ctx, env, payload, createAgentService = createTa
79021
79023
  async function resolveWebDistPath(configuredPath) {
79022
79024
  const candidates = configuredPath && configuredPath.trim() !== "" ? [isAbsolute3(configuredPath) ? configuredPath : join16(process.cwd(), configuredPath)] : [
79023
79025
  join16(process.cwd(), "dist/web"),
79024
- join16(dirname10(process.execPath), "../web"),
79026
+ join16(dirname9(process.execPath), "../web"),
79025
79027
  join16(import.meta.dir, "../../../dist/web")
79026
79028
  ];
79027
79029
  for (const candidate of candidates) {
@@ -79034,8 +79036,10 @@ async function resolveWebDistPath(configuredPath) {
79034
79036
  async function startServer(options, deps = defaultDeps) {
79035
79037
  const env = process.env;
79036
79038
  const bootConfig = deps.serverBootstrapConfig(env);
79039
+ const configFile = deps.resolveConfigFile();
79037
79040
  await deps.runNodeApplication({
79038
79041
  config: bootConfig,
79042
+ configLoader: configFile ? { configFile, bootstrapSection: "bootstrap" } : undefined,
79039
79043
  async start(appRt) {
79040
79044
  const fs3 = deps.createNodeFileSystem(process.cwd());
79041
79045
  let scheduler3;
@@ -79287,7 +79291,7 @@ var section_matrix_schema_default = {
79287
79291
  $schema: "http://json-schema.org/draft-07/schema#",
79288
79292
  $id: "https://gobing.ai/spur/schemas/section-matrix.schema.json",
79289
79293
  title: "Section-Status-Matrix Schema",
79290
- description: "Validates config/tasks/section-matrix.yaml \u2014 which sections are required/optional/forbidden per task status. Design \xA73.2. Authored for ts-runtime's loadStructuredConfig validator (supports properties/required/additionalProperties + $defs/$ref/enum; NOT patternProperties/uniqueItems).",
79294
+ description: "Validates the shipped section-matrix.yaml \u2014 which sections are required/optional/forbidden per task status. Design \xA73.2. Authored for ts-runtime's loadStructuredConfig validator (supports properties/required/additionalProperties + $defs/$ref/enum; NOT patternProperties/uniqueItems).",
79291
79295
  type: "object",
79292
79296
  required: ["variants"],
79293
79297
  additionalProperties: false,
@@ -80671,7 +80675,7 @@ init_src3();
80671
80675
  init_src();
80672
80676
  init_src2();
80673
80677
  init_dist3();
80674
- import { dirname as dirname11, join as join19, resolve as resolve7 } from "path";
80678
+ import { dirname as dirname10, join as join19, resolve as resolve7 } from "path";
80675
80679
  import { isatty as isatty3 } from "tty";
80676
80680
 
80677
80681
  // ../../node_modules/.bun/@clack+core@1.4.1/node_modules/@clack/core/dist/index.mjs
@@ -82083,7 +82087,7 @@ async function createMigratedDbAdapter(cwd = process.cwd(), env = process.env, d
82083
82087
  const configuredUrl = env.DATABASE_URL === undefined ? join19(cwd, CLI_CONFIG.databaseFile) : config3.database.url;
82084
82088
  const url2 = dbUrl ?? configuredUrl;
82085
82089
  if (url2 !== ":memory:") {
82086
- await createNodeFileSystem().ensureDir(dirname11(url2));
82090
+ await createNodeFileSystem().ensureDir(dirname10(url2));
82087
82091
  }
82088
82092
  return createMigratedDb({ url: url2 });
82089
82093
  }
@@ -82103,7 +82107,7 @@ async function main(argv = process.argv.slice(2), options = {}) {
82103
82107
  bootstrapSection: "bootstrap",
82104
82108
  appConfig: { safeParse: (raw2) => spurConfigSchema.safeParse(raw2) }
82105
82109
  },
82106
- config: undefined,
82110
+ config: { logging: { console: false } },
82107
82111
  services: { db: db2 },
82108
82112
  async start(appRt) {
82109
82113
  const context3 = createCliContext({