@gobing-ai/spur 0.3.83 → 0.3.84

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.
Files changed (65) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/config/rules/strict/runtime-boundaries.yaml +1 -0
  3. package/package.json +1 -1
  4. package/plugins/sp/lib/idea-handoff.generated.mjs +1 -1
  5. package/plugins/sp/plugin.json +1 -1
  6. package/plugins/sp/skills/parallel-execution/references/dispatch-surface.md +37 -0
  7. package/plugins/sp/skills/parallel-execution/references/fan-out-patterns.md +55 -1
  8. package/plugins/sp/skills/spec-decomposition/references/decomposition.md +12 -0
  9. package/plugins/sp/skills/spur-dev/references/cross-cutting.md +4 -1
  10. package/plugins/sp/skills/spur-dev/references/inline-pipeline-driver.md +60 -4
  11. package/schemas/task-batch.schema.json +5 -0
  12. package/spur.js +780 -325
  13. package/web/_astro/{BoardApp.D8bM9pKL.js → BoardApp.D4mBUGLT.js} +64 -64
  14. package/web/_astro/BoardApp.DFPYpI5O.js +1 -0
  15. package/web/_astro/{TaskDetail.BPRqgVUE.js → TaskDetail.DhCWaOPR.js} +1 -1
  16. package/web/_astro/{arc.BPrPES3z.js → arc.D3X0nfq-.js} +1 -1
  17. package/web/_astro/{architectureDiagram-3BPJPVTR.qX_7q02P.js → architectureDiagram-3BPJPVTR.BQDoiGme.js} +1 -1
  18. package/web/_astro/{blockDiagram-GPEHLZMM.CUZfj5V7.js → blockDiagram-GPEHLZMM.BjHekBbM.js} +1 -1
  19. package/web/_astro/{c4Diagram-AAUBKEIU.CTaOr8hH.js → c4Diagram-AAUBKEIU.BvHt171l.js} +1 -1
  20. package/web/_astro/channel.BlQwxyoI.js +1 -0
  21. package/web/_astro/{chunk-2J33WTMH.Dt-9wf3h.js → chunk-2J33WTMH.CwxGXlDR.js} +1 -1
  22. package/web/_astro/{chunk-4BX2VUAB.CTC2sdoN.js → chunk-4BX2VUAB.Dia1YtwU.js} +1 -1
  23. package/web/_astro/{chunk-55IACEB6.DQcxt2_g.js → chunk-55IACEB6.Oz9epCXa.js} +1 -1
  24. package/web/_astro/{chunk-727SXJPM.DXFPSn-a.js → chunk-727SXJPM.DKFYJjYJ.js} +1 -1
  25. package/web/_astro/{chunk-AQP2D5EJ.BCx3U4bT.js → chunk-AQP2D5EJ.AD7w5oVz.js} +1 -1
  26. package/web/_astro/{chunk-FMBD7UC4.DL2tJkdO.js → chunk-FMBD7UC4.D0OqTj52.js} +1 -1
  27. package/web/_astro/{chunk-ND2GUHAM.DZyflMro.js → chunk-ND2GUHAM.CU5ppR7j.js} +1 -1
  28. package/web/_astro/{chunk-QZHKN3VN.CUI2mT09.js → chunk-QZHKN3VN.Bu1rFztw.js} +1 -1
  29. package/web/_astro/{classDiagram-4FO5ZUOK.g4rX4Fr1.js → classDiagram-4FO5ZUOK.C0Pgm5yE.js} +1 -1
  30. package/web/_astro/{classDiagram-v2-Q7XG4LA2.g4rX4Fr1.js → classDiagram-v2-Q7XG4LA2.C0Pgm5yE.js} +1 -1
  31. package/web/_astro/{cose-bilkent-S5V4N54A.CzWJLqp0.js → cose-bilkent-S5V4N54A.C0ecLb1e.js} +1 -1
  32. package/web/_astro/{cynefin-OW5HDTMX.WgsvQeCR.js → cynefin-OW5HDTMX.CpStVmhO.js} +1 -1
  33. package/web/_astro/{dagre-BM42HDAG.Dzv6ngql.js → dagre-BM42HDAG.BPWN3W9f.js} +1 -1
  34. package/web/_astro/{diagram-2AECGRRQ.CpJ4a9rU.js → diagram-2AECGRRQ.DnXbEot4.js} +1 -1
  35. package/web/_astro/{diagram-5GNKFQAL.CzPlF_dq.js → diagram-5GNKFQAL.BYJsgUiI.js} +1 -1
  36. package/web/_astro/{diagram-KO2AKTUF.TAkZNTcQ.js → diagram-KO2AKTUF.CU4Bqprx.js} +1 -1
  37. package/web/_astro/{diagram-LMA3HP47.uCjoKSag.js → diagram-LMA3HP47.BQLOANIu.js} +1 -1
  38. package/web/_astro/{diagram-OG6HWLK6.eMplIjoK.js → diagram-OG6HWLK6.Cn1UVhqj.js} +1 -1
  39. package/web/_astro/{erDiagram-TEJ5UH35.Bf7zoXGz.js → erDiagram-TEJ5UH35.C8FdZyvA.js} +1 -1
  40. package/web/_astro/{flowDiagram-I6XJVG4X.B_bHj3gN.js → flowDiagram-I6XJVG4X.QSZCR8Uo.js} +1 -1
  41. package/web/_astro/{ganttDiagram-6RSMTGT7.BasrHRMj.js → ganttDiagram-6RSMTGT7.O1Py31MY.js} +1 -1
  42. package/web/_astro/{gitGraphDiagram-PVQCEYII.C6iphq1x.js → gitGraphDiagram-PVQCEYII.DoeJRBfY.js} +1 -1
  43. package/web/_astro/index.TPF1FerP.css +1 -0
  44. package/web/_astro/{infoDiagram-5YYISTIA.HXmDMhW4.js → infoDiagram-5YYISTIA.9npLJecW.js} +1 -1
  45. package/web/_astro/{ishikawaDiagram-YF4QCWOH.BSmW8NiU.js → ishikawaDiagram-YF4QCWOH.DXanvOr3.js} +1 -1
  46. package/web/_astro/{journeyDiagram-JHISSGLW.DEQow5fo.js → journeyDiagram-JHISSGLW.DxbVjxAv.js} +1 -1
  47. package/web/_astro/{kanban-definition-UN3LZRKU.IVm9cTdc.js → kanban-definition-UN3LZRKU.BDk6_iq0.js} +1 -1
  48. package/web/_astro/{linear.CrsM73_9.js → linear.C9cCDjT3.js} +1 -1
  49. package/web/_astro/{mermaid.core.CfBeDJls.js → mermaid.core.CpHRe5nH.js} +4 -4
  50. package/web/_astro/{mindmap-definition-RKZ34NQL.C3j60Y-0.js → mindmap-definition-RKZ34NQL.D-6C85bn.js} +1 -1
  51. package/web/_astro/{pieDiagram-4H26LBE5.B-aCMeEA.js → pieDiagram-4H26LBE5.B3Oxodty.js} +1 -1
  52. package/web/_astro/{quadrantDiagram-W4KKPZXB.Cib965yq.js → quadrantDiagram-W4KKPZXB.QZ_9Hshu.js} +1 -1
  53. package/web/_astro/{requirementDiagram-4Y6WPE33.D61cS4O-.js → requirementDiagram-4Y6WPE33.BimvuK53.js} +1 -1
  54. package/web/_astro/{sankeyDiagram-5OEKKPKP.GKF2qVPy.js → sankeyDiagram-5OEKKPKP.D5Kkpx2C.js} +1 -1
  55. package/web/_astro/{sequenceDiagram-3UESZ5HK.DZnq8F2h.js → sequenceDiagram-3UESZ5HK.B4YR6fAE.js} +1 -1
  56. package/web/_astro/{stateDiagram-AJRCARHV.DXUFmdgM.js → stateDiagram-AJRCARHV.Bt2wkZok.js} +1 -1
  57. package/web/_astro/{stateDiagram-v2-BHNVJYJU.BtHmhLEz.js → stateDiagram-v2-BHNVJYJU.YZ4X7dfQ.js} +1 -1
  58. package/web/_astro/{timeline-definition-PNZ67QCA.Cy-WW2ln.js → timeline-definition-PNZ67QCA.DmiTBL8w.js} +1 -1
  59. package/web/_astro/{vennDiagram-CIIHVFJN.SLp5b9KI.js → vennDiagram-CIIHVFJN.KNJV40mf.js} +1 -1
  60. package/web/_astro/{wardleyDiagram-YWT4CUSO.Bww45mWV.js → wardleyDiagram-YWT4CUSO.BVAaKgWH.js} +1 -1
  61. package/web/_astro/{xychartDiagram-2RQKCTM6.DR4swI6a.js → xychartDiagram-2RQKCTM6.D5Jx7zB2.js} +1 -1
  62. package/web/index.html +2 -2
  63. package/web/_astro/BoardApp.D-WlxiN2.js +0 -1
  64. package/web/_astro/channel.DGZaFHZx.js +0 -1
  65. package/web/_astro/index.DayyIngm.css +0 -1
package/spur.js CHANGED
@@ -39503,6 +39503,34 @@ var init_projects = __esm(() => {
39503
39503
  });
39504
39504
  });
39505
39505
 
39506
+ // ../../packages/config/src/slash-commands.ts
39507
+ import { homedir as homedir2 } from "os";
39508
+ import { join as join2 } from "path";
39509
+ function getSlashCommandsFilePath() {
39510
+ if (process.env.SPUR_SLASH_COMMANDS_FILE) {
39511
+ return process.env.SPUR_SLASH_COMMANDS_FILE;
39512
+ }
39513
+ return join2(homedir2(), ".config", "spur", "slash_commands.json");
39514
+ }
39515
+ var slashCommandCategorySchema, slashCommandItemSchema, slashCommandsFileSchema;
39516
+ var init_slash_commands = __esm(() => {
39517
+ init_zod();
39518
+ slashCommandCategorySchema = exports_external.enum(["git", "dev", "sys", "harness"]);
39519
+ slashCommandItemSchema = exports_external.object({
39520
+ name: exports_external.string().min(1),
39521
+ description: exports_external.string().min(1),
39522
+ category: slashCommandCategorySchema.default("dev"),
39523
+ argumentHint: exports_external.string().optional(),
39524
+ role: exports_external.string().optional(),
39525
+ source: exports_external.string().optional()
39526
+ });
39527
+ slashCommandsFileSchema = exports_external.object({
39528
+ version: exports_external.number().int().default(1),
39529
+ updatedAt: exports_external.string().optional(),
39530
+ commands: exports_external.array(slashCommandItemSchema).default([])
39531
+ });
39532
+ });
39533
+
39506
39534
  // ../../packages/config/src/index.ts
39507
39535
  function folderPathWithDefault(defaultPath) {
39508
39536
  return exports_external.preprocess((v) => v == null ? undefined : v, exports_external.string().default(defaultPath));
@@ -39608,6 +39636,7 @@ var init_src = __esm(() => {
39608
39636
  init_zod();
39609
39637
  init_finding_codes();
39610
39638
  init_projects();
39639
+ init_slash_commands();
39611
39640
  SPUR_ENV_VARS = {
39612
39641
  nodeEnv: "NODE_ENV",
39613
39642
  port: "PORT",
@@ -39835,14 +39864,14 @@ var init_src = __esm(() => {
39835
39864
 
39836
39865
  // ../../packages/config/src/bundled-config.ts
39837
39866
  import { existsSync as existsSync3, readdirSync as readdirSync3, statSync as statSync4 } from "fs";
39838
- import { dirname as dirname3, join as join2 } from "path";
39867
+ import { dirname as dirname3, join as join3 } from "path";
39839
39868
  function bundledConfigRoot() {
39840
39869
  if (cachedRoot !== undefined)
39841
39870
  return cachedRoot;
39842
39871
  let dir = import.meta.dirname;
39843
39872
  while (true) {
39844
39873
  for (const name of BUNDLED_CONFIG_DIRS) {
39845
- const candidate = join2(dir, name);
39874
+ const candidate = join3(dir, name);
39846
39875
  if (isBundledConfigDir(candidate)) {
39847
39876
  cachedRoot = candidate;
39848
39877
  return cachedRoot;
@@ -39857,7 +39886,7 @@ function bundledConfigRoot() {
39857
39886
  return cachedRoot;
39858
39887
  }
39859
39888
  function isBundledConfigDir(candidate) {
39860
- return existsSync3(candidate) && statSync4(candidate).isDirectory() && existsSync3(join2(candidate, "rules")) && existsSync3(join2(candidate, "workflows"));
39889
+ return existsSync3(candidate) && statSync4(candidate).isDirectory() && existsSync3(join3(candidate, "rules")) && existsSync3(join3(candidate, "workflows"));
39861
39890
  }
39862
39891
  function listBundledConfigFiles() {
39863
39892
  const root = bundledConfigRoot();
@@ -39868,7 +39897,7 @@ function listBundledConfigFiles() {
39868
39897
  function walk(dir, relPrefix, filter = /\.(ya?ml|json)$/i) {
39869
39898
  const acc = [];
39870
39899
  for (const entry of readdirSync3(dir)) {
39871
- const abs = join2(dir, entry);
39900
+ const abs = join3(dir, entry);
39872
39901
  const rel = relPrefix.length > 0 ? `${relPrefix}/${entry}` : entry;
39873
39902
  if (statSync4(abs).isDirectory()) {
39874
39903
  acc.push(...walk(abs, rel, filter));
@@ -39906,7 +39935,7 @@ var init_template_renderer = () => {};
39906
39935
 
39907
39936
  // ../../packages/config/src/executor-update.ts
39908
39937
  import { chmod, lstat, open, readFile, rename, stat, unlink } from "fs/promises";
39909
- import { basename, dirname as dirname4, join as join3 } from "path";
39938
+ import { basename, dirname as dirname4, join as join4 } from "path";
39910
39939
  async function setProjectExecutorDisabled(projectRoot, executorName, disabled) {
39911
39940
  if (executorName.length === 0) {
39912
39941
  throw new ExecutorUpdateError("INVALID_CONFIG", "executor name must be a non-empty string");
@@ -39914,7 +39943,7 @@ async function setProjectExecutorDisabled(projectRoot, executorName, disabled) {
39914
39943
  if (typeof disabled !== "boolean") {
39915
39944
  throw new ExecutorUpdateError("INVALID_CONFIG", `disabled must be a boolean, received ${typeof disabled}`);
39916
39945
  }
39917
- const configPath = join3(projectRoot, ".spur", "config.yaml");
39946
+ const configPath = join4(projectRoot, ".spur", "config.yaml");
39918
39947
  let original;
39919
39948
  try {
39920
39949
  original = await stat(configPath);
@@ -39969,7 +39998,7 @@ async function setProjectExecutorDisabled(projectRoot, executorName, disabled) {
39969
39998
  }
39970
39999
  target.set("disabled", disabled);
39971
40000
  const serialized = String(doc2);
39972
- const tmpPath = join3(dirname4(configPath), `.${basename(configPath)}.tmp-${process.pid}`);
40001
+ const tmpPath = join4(dirname4(configPath), `.${basename(configPath)}.tmp-${process.pid}`);
39973
40002
  try {
39974
40003
  const latest = await stat(configPath);
39975
40004
  if (latest.mtimeMs !== baseline.mtimeMs || latest.size !== baseline.size || latest.ino !== baseline.ino) {
@@ -40057,8 +40086,8 @@ var init_executor_update = __esm(() => {
40057
40086
 
40058
40087
  // ../../packages/config/src/loader.ts
40059
40088
  import { existsSync as existsSync4, statSync as statSync5 } from "fs";
40060
- import { homedir as homedir2 } from "os";
40061
- import { dirname as dirname5, join as join4, resolve } from "path";
40089
+ import { homedir as homedir3 } from "os";
40090
+ import { dirname as dirname5, join as join5, resolve } from "path";
40062
40091
  import { fileURLToPath as fileURLToPath3 } from "url";
40063
40092
  function embeddedSchemasId(embeddedSchemas) {
40064
40093
  if (embeddedSchemas === undefined)
@@ -40081,7 +40110,7 @@ function cacheKey(configPath, opts, validateJsonSchema2) {
40081
40110
  }
40082
40111
  function resolveSchemaSpecifier(specifier, manifestSpecifier) {
40083
40112
  if (specifier === manifestSpecifier) {
40084
- const workspaceManifest = join4(LOADER_DIR, "..", "..", "..", "apps", "cli", "package.json");
40113
+ const workspaceManifest = join5(LOADER_DIR, "..", "..", "..", "apps", "cli", "package.json");
40085
40114
  if (existsSync4(workspaceManifest))
40086
40115
  return workspaceManifest;
40087
40116
  }
@@ -40096,7 +40125,7 @@ function resolveConfigLayers(cwd) {
40096
40125
  const layers = {};
40097
40126
  const skipProject = cwd === undefined && process.env.SPUR_SKIP_PROJECT_CONFIG === "true";
40098
40127
  if (!skipProject) {
40099
- const projectConfig = join4(cwd ?? process.cwd(), SPUR_CONFIG_DIR, SPUR_CONFIG_FILE);
40128
+ const projectConfig = join5(cwd ?? process.cwd(), SPUR_CONFIG_DIR, SPUR_CONFIG_FILE);
40100
40129
  if (existsSync4(projectConfig))
40101
40130
  layers.project = projectConfig;
40102
40131
  }
@@ -40169,9 +40198,9 @@ function assertNoGlobalFleetSection(globalRaw, layerPath, projectFile) {
40169
40198
  throw new Error(`agent.fleet is not supported in the global config (${layerPath ?? SPUR_CONFIG_FILE}). ` + `Declare the project fleet under agent.fleet in ${projectFile} \u2014 the flock belongs to a project, not to the machine.`);
40170
40199
  }
40171
40200
  function assertNoLegacyFleetFile(projectRoot, projectConfigPath) {
40172
- const candidates = new Set([join4(projectRoot, SPUR_CONFIG_DIR, "fleet.json")]);
40201
+ const candidates = new Set([join5(projectRoot, SPUR_CONFIG_DIR, "fleet.json")]);
40173
40202
  if (projectConfigPath !== undefined)
40174
- candidates.add(join4(dirname5(projectConfigPath), "fleet.json"));
40203
+ candidates.add(join5(dirname5(projectConfigPath), "fleet.json"));
40175
40204
  for (const legacyFile of candidates) {
40176
40205
  if (!existsSync4(legacyFile))
40177
40206
  continue;
@@ -40179,7 +40208,7 @@ function assertNoLegacyFleetFile(projectRoot, projectConfigPath) {
40179
40208
  }
40180
40209
  }
40181
40210
  function projectConfigReplacement(layers) {
40182
- return layers.project ?? join4(SPUR_CONFIG_DIR, SPUR_CONFIG_FILE);
40211
+ return layers.project ?? join5(SPUR_CONFIG_DIR, SPUR_CONFIG_FILE);
40183
40212
  }
40184
40213
  function schemaValidationContext(opts) {
40185
40214
  const embeddedSchemas = opts?.embeddedSchemas;
@@ -40434,7 +40463,7 @@ async function resolvePlanningFolders(fs2) {
40434
40463
  return promise2;
40435
40464
  }
40436
40465
  async function resolvePlanningFoldersUncached(fs2) {
40437
- const configPath = fs2.resolve(join4(SPUR_CONFIG_DIR, SPUR_CONFIG_FILE));
40466
+ const configPath = fs2.resolve(join5(SPUR_CONFIG_DIR, SPUR_CONFIG_FILE));
40438
40467
  if (!await fs2.exists(configPath))
40439
40468
  return defaultPlanningFolders();
40440
40469
  try {
@@ -40473,7 +40502,7 @@ var init_loader = __esm(() => {
40473
40502
  init_template_renderer();
40474
40503
  init_executor_update();
40475
40504
  init_projects();
40476
- GLOBAL_CONFIG_FILE = join4(homedir2(), ".config", "spur", "config.yaml");
40505
+ GLOBAL_CONFIG_FILE = join5(homedir3(), ".config", "spur", "config.yaml");
40477
40506
  LOADER_DIR = dirname5(fileURLToPath3(import.meta.url));
40478
40507
  embeddedSchemasIds = new WeakMap;
40479
40508
  spurConfigCache = new Map;
@@ -68003,7 +68032,7 @@ var init_schema3 = __esm(() => {
68003
68032
  });
68004
68033
 
68005
68034
  // ../../packages/domain/src/migrations.ts
68006
- import { join as join6 } from "path";
68035
+ import { join as join7 } from "path";
68007
68036
  async function allMigrationsJournaled(adapter, migrations) {
68008
68037
  if (migrations.length === 0)
68009
68038
  return true;
@@ -68116,7 +68145,7 @@ async function loadSqlMigrations(folder) {
68116
68145
  for (const entry of entries) {
68117
68146
  migrations.push({
68118
68147
  id: entry.replace(/\.sql$/, ""),
68119
- sql: await fs3.readFile(join6(folder, entry))
68148
+ sql: await fs3.readFile(join7(folder, entry))
68120
68149
  });
68121
68150
  }
68122
68151
  return migrations.length > 0 ? migrations : CLI_MIGRATIONS;
@@ -70803,7 +70832,7 @@ var init_envelope = __esm(() => {
70803
70832
 
70804
70833
  // ../../packages/domain/src/retention.ts
70805
70834
  import { readdirSync as readdirSync5, rmSync as rmSync3, statfsSync, statSync as statSync6 } from "fs";
70806
- import { join as join7 } from "path";
70835
+ import { join as join8 } from "path";
70807
70836
  async function estimateReclaimableBytes(db2) {
70808
70837
  try {
70809
70838
  const rows = await db2.queryAll("SELECT pageno, pagetype, ncell, payload, unused FROM dbstat ORDER BY pageno");
@@ -70871,7 +70900,7 @@ async function runRetention(db2, cwd, now = new Date) {
70871
70900
  result.queueJobs = await purgeQueueJobs(db2, now);
70872
70901
  result.ledgerRows = await purgeLedger(db2, now);
70873
70902
  result.backupFiles = pruneBackups(cwd, now);
70874
- result.compaction = await compactDatabase(db2, { dbPath: join7(cwd, ".spur", "spur.db"), now });
70903
+ result.compaction = await compactDatabase(db2, { dbPath: join8(cwd, ".spur", "spur.db"), now });
70875
70904
  return result;
70876
70905
  }
70877
70906
  async function purgeRuleEvalRuns(db2, now) {
@@ -70884,7 +70913,7 @@ async function purgeLedger(db2, now) {
70884
70913
  return purgeRows(db2, `DELETE FROM history_import_ledger WHERE imported_at < ?`, new Date(now.getTime() - LEDGER_RETENTION_DAYS * DAY_MS).toISOString());
70885
70914
  }
70886
70915
  function pruneBackups(cwd, now) {
70887
- const dir = join7(cwd, ".spur", "backups");
70916
+ const dir = join8(cwd, ".spur", "backups");
70888
70917
  let entries;
70889
70918
  try {
70890
70919
  entries = readdirSync5(dir);
@@ -70894,7 +70923,7 @@ function pruneBackups(cwd, now) {
70894
70923
  const cutoffMs = now.getTime() - BACKUP_RETENTION_DAYS * DAY_MS;
70895
70924
  let reclaimed = 0;
70896
70925
  for (const name of entries) {
70897
- const path9 = join7(dir, name);
70926
+ const path9 = join8(dir, name);
70898
70927
  try {
70899
70928
  const stat2 = statSync6(path9);
70900
70929
  if (!stat2.isFile() || stat2.mtimeMs >= cutoffMs)
@@ -70979,12 +71008,12 @@ var init_maintenance = __esm(() => {
70979
71008
 
70980
71009
  // ../../packages/domain/src/planning/locks.ts
70981
71010
  import { closeSync, fsyncSync, mkdirSync as mkdirSync4, openSync, readFileSync as readFileSync7, renameSync as renameSync3, unlinkSync, writeSync } from "fs";
70982
- import { dirname as dirname8, join as join8 } from "path";
71011
+ import { dirname as dirname8, join as join9 } from "path";
70983
71012
  function lockPathForEntity(folder, entityId) {
70984
- return join8(folder, `.${entityId}.lock`);
71013
+ return join9(folder, `.${entityId}.lock`);
70985
71014
  }
70986
71015
  function createLockPath(folder) {
70987
- return join8(folder, ".create.lock");
71016
+ return join9(folder, ".create.lock");
70988
71017
  }
70989
71018
  function parseLockContent(raw) {
70990
71019
  const str = typeof raw === "string" ? raw : raw.toString();
@@ -71089,7 +71118,7 @@ function fsyncPath(path9, swallowErrors = false) {
71089
71118
  function atomicWrite(dest, content, entityId, fs3, projectName = "spur") {
71090
71119
  const dir = dirname8(dest);
71091
71120
  const rand = Math.random().toString(36).slice(2, 10);
71092
- const tempPath = join8(dir, `.${projectName}.${entityId}.${rand}.tmp`);
71121
+ const tempPath = join9(dir, `.${projectName}.${entityId}.${rand}.tmp`);
71093
71122
  fs3.writeFile(tempPath, content);
71094
71123
  fsyncPath(tempPath);
71095
71124
  renameSync3(tempPath, dest);
@@ -71098,7 +71127,7 @@ function atomicWrite(dest, content, entityId, fs3, projectName = "spur") {
71098
71127
  async function atomicWriteAsync(dest, content, entityId, fs3, projectName = "spur") {
71099
71128
  const dir = dirname8(dest);
71100
71129
  const rand = Math.random().toString(36).slice(2, 10);
71101
- const tempPath = join8(dir, `.${projectName}.${entityId}.${rand}.tmp`);
71130
+ const tempPath = join9(dir, `.${projectName}.${entityId}.${rand}.tmp`);
71102
71131
  await fs3.writeFile(tempPath, content);
71103
71132
  fsyncPath(tempPath);
71104
71133
  renameSync3(tempPath, dest);
@@ -71113,7 +71142,7 @@ function cleanupTempFiles(folder, entityId, fs3, projectName = "spur") {
71113
71142
  let count3 = 0;
71114
71143
  for (const entry of entries) {
71115
71144
  if (entry.startsWith(prefix) && entry.endsWith(suffix)) {
71116
- fs3.deleteFile(join8(folder, entry));
71145
+ fs3.deleteFile(join9(folder, entry));
71117
71146
  count3++;
71118
71147
  }
71119
71148
  }
@@ -71694,6 +71723,7 @@ var init_schema6 = __esm(() => {
71694
71723
  done_forced: exports_external.preprocess((v) => typeof v === "string" ? v === "true" : v, exports_external.boolean().optional()),
71695
71724
  done_reason: exports_external.string().optional(),
71696
71725
  feature_link_declined: exports_external.preprocess((v) => typeof v === "string" ? v === "true" : v, exports_external.boolean().optional()),
71726
+ estimate_hours: exports_external.preprocess((v) => typeof v === "string" && v.trim() !== "" ? Number(v) : v, exports_external.number().positive().optional()),
71697
71727
  created_at: isoDateString,
71698
71728
  updated_at: isoDateString
71699
71729
  });
@@ -71721,7 +71751,8 @@ var init_schema6 = __esm(() => {
71721
71751
  parent_wbs: wbsString,
71722
71752
  priority: exports_external.enum(PRIORITIES).optional(),
71723
71753
  tags: exports_external.array(exports_external.string()).optional(),
71724
- template: exports_external.enum(TASK_VARIANTS).optional()
71754
+ template: exports_external.enum(TASK_VARIANTS).optional(),
71755
+ estimate_hours: exports_external.number().positive().optional()
71725
71756
  }).strict();
71726
71757
  taskBatchSchema = exports_external.array(taskBatchItemSchema).min(1, "batch must contain at least one task");
71727
71758
  });
@@ -73046,7 +73077,7 @@ var init_escalation_packet = __esm(() => {
73046
73077
 
73047
73078
  // ../../packages/app/src/observability/escalation-packet-sink.ts
73048
73079
  import { randomUUID } from "crypto";
73049
- import { join as join9 } from "path";
73080
+ import { join as join10 } from "path";
73050
73081
  function parseDryRunProbeMetadata(metadataJson) {
73051
73082
  if (metadataJson === "")
73052
73083
  return false;
@@ -73093,7 +73124,7 @@ class EscalationPacketSink {
73093
73124
  }
73094
73125
  }
73095
73126
  async readPacket(runId) {
73096
- const path9 = join9(this.options.cwd, ".spur", "run", `${runId}-escalation.json`);
73127
+ const path9 = join10(this.options.cwd, ".spur", "run", `${runId}-escalation.json`);
73097
73128
  if (!await this.options.fs.exists(path9))
73098
73129
  return;
73099
73130
  return JSON.parse(await this.options.fs.readFile(path9));
@@ -73161,7 +73192,7 @@ class EscalationPacketSink {
73161
73192
  const identity6 = await this.resolveIdentity(wbs);
73162
73193
  const now2 = (this.options.now ?? (() => new Date().toISOString()))();
73163
73194
  const packet = buildEscalationPacket({ ...packetInput, identity: identity6, now: now2 });
73164
- const path9 = join9(this.options.cwd, ".spur", "run", `${input.runId}-escalation.json`);
73195
+ const path9 = join10(this.options.cwd, ".spur", "run", `${input.runId}-escalation.json`);
73165
73196
  if (!await this.options.fs.exists(path9)) {
73166
73197
  await this.options.fs.writeFile(path9, `${JSON.stringify(packet, null, 2)}
73167
73198
  `);
@@ -73452,7 +73483,7 @@ var init_step_reporter = () => {};
73452
73483
 
73453
73484
  // ../../packages/app/src/observability/workflow-run-log-sink.ts
73454
73485
  import { closeSync as closeSync2, mkdirSync as mkdirSync5, openSync as openSync2, writeSync as writeSync2 } from "fs";
73455
- import { join as join10 } from "path";
73486
+ import { join as join11 } from "path";
73456
73487
 
73457
73488
  class WorkflowRunLogSink {
73458
73489
  filePath;
@@ -73468,7 +73499,7 @@ class WorkflowRunLogSink {
73468
73499
  bus;
73469
73500
  handlers;
73470
73501
  constructor(options) {
73471
- this.filePath = join10(options.dir, `${options.runId}.log`);
73502
+ this.filePath = join11(options.dir, `${options.runId}.log`);
73472
73503
  this.maxBytes = options.maxBytes ?? DEFAULT_RUN_LOG_MAX_BYTES;
73473
73504
  this.maxLines = options.maxLines;
73474
73505
  this.planPreview = options.planPreview;
@@ -73923,7 +73954,7 @@ var init_failure_classification = __esm(() => {
73923
73954
  });
73924
73955
 
73925
73956
  // ../../packages/app/src/services/run-session-observer.ts
73926
- import { homedir as homedir3 } from "os";
73957
+ import { homedir as homedir4 } from "os";
73927
73958
  import { basename as basename2, isAbsolute as isAbsolute2, resolve as resolve3 } from "path";
73928
73959
 
73929
73960
  class RunSessionObserver {
@@ -73935,7 +73966,7 @@ class RunSessionObserver {
73935
73966
  now;
73936
73967
  constructor(options) {
73937
73968
  this.options = options;
73938
- this.home = options.home ?? homedir3();
73969
+ this.home = options.home ?? homedir4();
73939
73970
  this.cwd = options.cwd ?? process.cwd();
73940
73971
  this.now = options.now ?? Date.now;
73941
73972
  }
@@ -74147,7 +74178,7 @@ var init_run_session_observer = __esm(() => {
74147
74178
 
74148
74179
  // ../../packages/app/src/services/agent-service.ts
74149
74180
  import { createHash as createHash8 } from "crypto";
74150
- import { homedir as homedir4 } from "os";
74181
+ import { homedir as homedir5 } from "os";
74151
74182
  import { isatty as isatty3 } from "tty";
74152
74183
 
74153
74184
  class AgentService {
@@ -74565,7 +74596,7 @@ class AgentService {
74565
74596
  getDb,
74566
74597
  output: this.ctx.output,
74567
74598
  registry: this.sessionRootRegistry,
74568
- home: homedir4(),
74599
+ home: homedir5(),
74569
74600
  cwd: cwd || this.ctx.cwd,
74570
74601
  json: jsonOutput
74571
74602
  }));
@@ -75669,15 +75700,15 @@ var init_agent_service = __esm(() => {
75669
75700
  // ../../packages/app/src/services/project-registry.ts
75670
75701
  import { existsSync as existsSync5, mkdirSync as mkdirSync6, readFileSync as readFileSync8, realpathSync as realpathSync3, renameSync as renameSync4, rmSync as rmSync4, writeFileSync as writeFileSync4 } from "fs";
75671
75702
  import { connect, createServer } from "net";
75672
- import { homedir as homedir5 } from "os";
75673
- import { dirname as dirname9, join as join11, resolve as resolve4 } from "path";
75703
+ import { homedir as homedir6 } from "os";
75704
+ import { dirname as dirname9, join as join12, resolve as resolve4 } from "path";
75674
75705
  function normalizeProjectPath(pathInput) {
75675
75706
  const trimmed = pathInput.trim();
75676
75707
  let expanded = trimmed;
75677
75708
  if (trimmed === "~") {
75678
- expanded = homedir5();
75709
+ expanded = homedir6();
75679
75710
  } else if (trimmed.startsWith("~/")) {
75680
- expanded = join11(homedir5(), trimmed.slice(2));
75711
+ expanded = join12(homedir6(), trimmed.slice(2));
75681
75712
  } else {
75682
75713
  expanded = resolve4(trimmed);
75683
75714
  }
@@ -75978,7 +76009,7 @@ var init_project_registry = __esm(() => {
75978
76009
  });
75979
76010
 
75980
76011
  // ../../packages/app/src/services/fleet-service.ts
75981
- import { basename as basename3, dirname as dirname10, join as join12 } from "path";
76012
+ import { basename as basename3, dirname as dirname10, join as join13 } from "path";
75982
76013
  function resolveMemberExecutor(params) {
75983
76014
  const { member, index: index2, label, agentConfig, roles, roster } = params;
75984
76015
  if (member.executor !== undefined) {
@@ -76188,7 +76219,7 @@ class FleetService {
76188
76219
  }
76189
76220
  const slug = await this.projectSlug(normalized);
76190
76221
  const config4 = await this.effectiveConfig();
76191
- const configDir = join12(normalized, ".spur", "agents");
76222
+ const configDir = join13(normalized, ".spur", "agents");
76192
76223
  const specs = await loadAgentSpecs(configDir);
76193
76224
  const projection = materializeRoster({
76194
76225
  slug,
@@ -76242,7 +76273,7 @@ class FleetService {
76242
76273
  }
76243
76274
  async assertLaunchGroundTruth(projectPath) {
76244
76275
  const expected = normalizeProjectPath(projectPath);
76245
- const expectedStorageRoot = join12(expected, ".spur");
76276
+ const expectedStorageRoot = join13(expected, ".spur");
76246
76277
  const cwd = normalizeProjectPath(process.cwd());
76247
76278
  const storageRoot = normalizeProjectPath(this.fs.resolve(".spur"));
76248
76279
  const databasePath = this.ctx.openDb ? await new ProjectClaimDao(await this.ctx.openDb(expected)).databasePath() : "";
@@ -76350,7 +76381,7 @@ var init_task_locator = __esm(() => {
76350
76381
  });
76351
76382
 
76352
76383
  // ../../packages/app/src/services/agent-coordination-service.ts
76353
- import { join as join13 } from "path";
76384
+ import { join as join14 } from "path";
76354
76385
 
76355
76386
  class AgentCoordinationService {
76356
76387
  ctx;
@@ -76358,7 +76389,7 @@ class AgentCoordinationService {
76358
76389
  orchestratorPromise;
76359
76390
  constructor(ctx) {
76360
76391
  this.ctx = ctx;
76361
- this.configDir = join13(ctx.cwd, ".spur", "agents");
76392
+ this.configDir = join14(ctx.cwd, ".spur", "agents");
76362
76393
  }
76363
76394
  async sendMessage(fromId, toId, body, replyTo, requestKey) {
76364
76395
  validateAgentId(toId);
@@ -76624,7 +76655,7 @@ class AgentCoordinationService {
76624
76655
  async resolveTaskFile(taskId) {
76625
76656
  const fs3 = this.ctx.fs;
76626
76657
  const { foldersConfig } = await resolvePlanningFolders(fs3);
76627
- const dirs = [...new Set([foldersConfig.active_folder, ...Object.keys(foldersConfig.folders)])].map((dir) => join13(this.ctx.cwd, dir));
76658
+ const dirs = [...new Set([foldersConfig.active_folder, ...Object.keys(foldersConfig.folders)])].map((dir) => join14(this.ctx.cwd, dir));
76628
76659
  return await TaskLocator.forDirs(fs3, dirs).findPathByWbs(taskId);
76629
76660
  }
76630
76661
  }
@@ -76976,7 +77007,7 @@ var init_agent_quota_updates = __esm(() => {
76976
77007
  });
76977
77008
 
76978
77009
  // ../../packages/app/src/services/anchor-qualifier.ts
76979
- import { basename as basename4, join as join14 } from "path";
77010
+ import { basename as basename4, join as join15 } from "path";
76980
77011
  async function resolveRepoRoot(projectRoot, hintDir) {
76981
77012
  if (projectRoot)
76982
77013
  return projectRoot;
@@ -77105,7 +77136,7 @@ async function qualifyAnchors(fs3, opts) {
77105
77136
  } catch {
77106
77137
  continue;
77107
77138
  }
77108
- const mdFiles = entries.filter((name) => name.endsWith(".md") && name !== "kanban.md").map((name) => join14(dir, name)).sort();
77139
+ const mdFiles = entries.filter((name) => name.endsWith(".md") && name !== "kanban.md").map((name) => join15(dir, name)).sort();
77109
77140
  for (const filePath of mdFiles) {
77110
77141
  let raw;
77111
77142
  try {
@@ -78327,7 +78358,7 @@ __export(exports_feature_check, {
78327
78358
  FeatureCheckService: () => FeatureCheckService,
78328
78359
  DEFAULT_FEATURE_MATRIX: () => DEFAULT_FEATURE_MATRIX
78329
78360
  });
78330
- import { dirname as dirname11, join as join15 } from "path";
78361
+ import { dirname as dirname11, join as join16 } from "path";
78331
78362
  function isGroupFeature(fm) {
78332
78363
  const tags = fm.tags;
78333
78364
  return Array.isArray(tags) && tags.includes("group") ? "group" : "standard";
@@ -78425,9 +78456,9 @@ function decodeVerdictRows(source, sectionName, required2) {
78425
78456
  function defaultVerdictRunDir(tasksDir) {
78426
78457
  const norm = tasksDir.replace(/\\/g, "/");
78427
78458
  if (/\/docs\/tasks\d*$/.test(norm) || /\/docs\/tasks$/.test(norm)) {
78428
- return join15(dirname11(dirname11(tasksDir)), ".spur", "run");
78459
+ return join16(dirname11(dirname11(tasksDir)), ".spur", "run");
78429
78460
  }
78430
- return join15(dirname11(tasksDir), ".spur", "run");
78461
+ return join16(dirname11(tasksDir), ".spur", "run");
78431
78462
  }
78432
78463
  function rowMatchesScenario(id, sc) {
78433
78464
  const stripped = id.replace(/^\[[^\]]*\]\s*/, "").replace(/^Scenario:\s*/i, "").replace(/^\[[^\]]*\]\s*/, "").trim();
@@ -78557,7 +78588,7 @@ var init_feature_check = __esm(() => {
78557
78588
  await this.checkOneActiveGoal(fm, featureId2, options.featuresDir, findings, options.asStatus);
78558
78589
  await this.checkChildrenLimit(featureId2, options.featuresDir, findings);
78559
78590
  }
78560
- const dogfoodDir = options?.dogfoodDir ?? (options?.featuresDir ? join15(dirname11(options.featuresDir), "dogfood") : undefined);
78591
+ const dogfoodDir = options?.dogfoodDir ?? (options?.featuresDir ? join16(dirname11(options.featuresDir), "dogfood") : undefined);
78561
78592
  const primaryTasksDir = options?.tasksDir ?? options?.tasksDirs?.[0];
78562
78593
  const runDir = options?.runDir ?? (primaryTasksDir ? defaultVerdictRunDir(primaryTasksDir) : undefined);
78563
78594
  const taskScanDirs = options?.tasksDirs && options.tasksDirs.length > 0 ? options.tasksDirs : options?.tasksDir ? [options.tasksDir] : [];
@@ -78988,7 +79019,7 @@ var init_feature_check = __esm(() => {
78988
79019
  });
78989
79020
 
78990
79021
  // ../../packages/app/src/services/task-check.ts
78991
- import { basename as basename5, dirname as dirname12, join as join16 } from "path";
79022
+ import { basename as basename5, dirname as dirname12, join as join17 } from "path";
78992
79023
  function isPlaceholderBody(body) {
78993
79024
  const stripped = body.replace(/<!--[\s\S]*?-->/g, "").replace(/^\s*>\s*TBD\s*$/gim, "").trim();
78994
79025
  return stripped.length === 0;
@@ -79248,7 +79279,7 @@ var init_task_check = __esm(() => {
79248
79279
  this.runL2(doc2, entry, findings, raw);
79249
79280
  this.runL3(doc2, entry, effectiveStatus, findings, isTransitionTarget);
79250
79281
  const tasksDir = dirname12(filePath);
79251
- const featuresDir = join16(dirname12(tasksDir), "features");
79282
+ const featuresDir = join17(dirname12(tasksDir), "features");
79252
79283
  await this.runL4(doc2, fm, effectiveStatus, findings, featuresDir, tasksDir, wbs);
79253
79284
  await this.runL4Rollup(doc2, wbs, effectiveStatus, findings, tasksDir);
79254
79285
  if (effectiveStatus !== "done" && effectiveStatus !== "cancelled") {
@@ -79815,7 +79846,7 @@ var init_task_check = __esm(() => {
79815
79846
  for (const cite of citations) {
79816
79847
  if (reported >= 5)
79817
79848
  break;
79818
- const abs = join16(projectRoot, cite.path);
79849
+ const abs = join17(projectRoot, cite.path);
79819
79850
  let exists2 = false;
79820
79851
  try {
79821
79852
  exists2 = await this.fs.exists(abs);
@@ -79899,7 +79930,7 @@ var init_task_check = __esm(() => {
79899
79930
  continue;
79900
79931
  }
79901
79932
  try {
79902
- const abs = join16(dir, name);
79933
+ const abs = join17(dir, name);
79903
79934
  const stat2 = await this.fs.stat(abs);
79904
79935
  if (stat2 !== null && stat2 !== undefined && stat2.isDirectory?.())
79905
79936
  stack.push(abs);
@@ -79994,7 +80025,7 @@ var init_task_check = __esm(() => {
79994
80025
  }
79995
80026
  async checkVerdictArtifact(wbs, tasksDir, findings) {
79996
80027
  const projectRoot = resolveProjectRootFromTasksDir(tasksDir);
79997
- const runDir = join16(projectRoot, ".spur", "run");
80028
+ const runDir = join17(projectRoot, ".spur", "run");
79998
80029
  const verdictPath = `${runDir}/${wbs}-verdict.json`;
79999
80030
  const outcome = await readVerifyVerdict(this.fs, verdictPath, wbs);
80000
80031
  if (outcome.kind === "missing")
@@ -80039,13 +80070,13 @@ var init_task_check = __esm(() => {
80039
80070
  });
80040
80071
 
80041
80072
  // ../../packages/app/src/services/corpus-check.ts
80042
- import { basename as basename6, dirname as dirname13, join as join17, relative, resolve as resolve5 } from "path";
80073
+ import { basename as basename6, dirname as dirname13, join as join18, relative, resolve as resolve5 } from "path";
80043
80074
  async function loadTaskMatrix(projectRoot) {
80044
80075
  const fs3 = createNodeFileSystem3(projectRoot);
80045
- const candidates = [join17(projectRoot, ".spur", "tasks", "section-matrix.yaml")];
80076
+ const candidates = [join18(projectRoot, ".spur", "tasks", "section-matrix.yaml")];
80046
80077
  const bundledRoot = bundledConfigRoot();
80047
80078
  if (bundledRoot !== null)
80048
- candidates.push(join17(bundledRoot, "tasks", "section-matrix.yaml"));
80079
+ candidates.push(join18(bundledRoot, "tasks", "section-matrix.yaml"));
80049
80080
  let matrixPath;
80050
80081
  for (const candidate of candidates) {
80051
80082
  if (await fs3.exists(candidate)) {
@@ -80088,7 +80119,7 @@ async function structuralSweep(projectRoot) {
80088
80119
  const wbs = fileName.match(/^(\d{4})_.+\.md$/)?.[1];
80089
80120
  if (wbs === undefined)
80090
80121
  continue;
80091
- const result = await taskService.check(join17(tasksDir, fileName), wbs);
80122
+ const result = await taskService.check(join18(tasksDir, fileName), wbs);
80092
80123
  for (const finding of result.findings) {
80093
80124
  findings.push({
80094
80125
  kind: "task",
@@ -80106,7 +80137,7 @@ async function structuralSweep(projectRoot) {
80106
80137
  const id = fileName.match(/^([A-Z][0-9]*)_.+\.md$/)?.[1];
80107
80138
  if (id === undefined)
80108
80139
  continue;
80109
- const result = await featureService.check(join17(featuresDir, fileName), id, {
80140
+ const result = await featureService.check(join18(featuresDir, fileName), id, {
80110
80141
  featuresDir,
80111
80142
  tasksDir: activeTasksDir,
80112
80143
  tasksDirs: taskDirs,
@@ -80135,7 +80166,7 @@ async function duplicateIds(cwd, taskDirs, featuresDir) {
80135
80166
  return [];
80136
80167
  }
80137
80168
  const pattern = kind === "task" ? /^(\d{4})_/ : /^([A-Z][0-9]*)_/;
80138
- return names.map((n2) => ({ m: n2.match(pattern), n: n2 })).filter((x) => x.m !== null).map((x) => ({ id: x.m[1], file: relative(cwd, join17(dir, x.n)), kind }));
80169
+ return names.map((n2) => ({ m: n2.match(pattern), n: n2 })).filter((x) => x.m !== null).map((x) => ({ id: x.m[1], file: relative(cwd, join18(dir, x.n)), kind }));
80139
80170
  };
80140
80171
  const all = [
80141
80172
  ...(await Promise.all(taskDirs.map((dir) => scan(dir, "task")))).flat(),
@@ -80189,7 +80220,7 @@ function resolveProjectRoot(cwd) {
80189
80220
  const fs3 = createNodeFileSystem3(cwd);
80190
80221
  let current = resolve5(cwd);
80191
80222
  while (true) {
80192
- if (fs3.exists(join17(current, ".spur", "config.yaml"))) {
80223
+ if (fs3.exists(join18(current, ".spur", "config.yaml"))) {
80193
80224
  return current;
80194
80225
  }
80195
80226
  const parent = dirname13(current);
@@ -80211,14 +80242,14 @@ function diskReader(cwd) {
80211
80242
  return {
80212
80243
  list: async (dir) => {
80213
80244
  try {
80214
- return (await fs3.readDir(join17(cwd, dir))).map((n2) => `${dir}/${n2}`);
80245
+ return (await fs3.readDir(join18(cwd, dir))).map((n2) => `${dir}/${n2}`);
80215
80246
  } catch {
80216
80247
  return [];
80217
80248
  }
80218
80249
  },
80219
80250
  read: async (path9) => {
80220
80251
  try {
80221
- return await fs3.readFile(join17(cwd, path9));
80252
+ return await fs3.readFile(join18(cwd, path9));
80222
80253
  } catch {
80223
80254
  return null;
80224
80255
  }
@@ -80378,7 +80409,7 @@ var init_corpus_check = __esm(() => {
80378
80409
  });
80379
80410
 
80380
80411
  // ../../packages/app/src/services/corpus-migrator.ts
80381
- import { join as join18, relative as relative2 } from "path";
80412
+ import { join as join19, relative as relative2 } from "path";
80382
80413
  function applyM1(data, flags) {
80383
80414
  const raw = data.status;
80384
80415
  if (typeof raw !== "string")
@@ -80678,7 +80709,7 @@ class CorpusMigrator {
80678
80709
  }
80679
80710
  async discoverFiles() {
80680
80711
  const entries = await this.fs.readDir(this.corpusDir);
80681
- return entries.filter((name) => name.endsWith(".md")).filter((name) => name !== "kanban.md").map((name) => join18(this.corpusDir, name)).sort();
80712
+ return entries.filter((name) => name.endsWith(".md")).filter((name) => name !== "kanban.md").map((name) => join19(this.corpusDir, name)).sort();
80682
80713
  }
80683
80714
  async migrateFile(filePath, dryRun, gitDates = new Map) {
80684
80715
  const flags = [];
@@ -86897,8 +86928,8 @@ import {
86897
86928
  unlinkSync as unlinkSync2,
86898
86929
  writeFileSync as writeFileSync5
86899
86930
  } from "fs";
86900
- import { homedir as homedir6 } from "os";
86901
- import { dirname as dirname14, isAbsolute as isAbsolute3, join as join19, resolve as resolve6, sep } from "path";
86931
+ import { homedir as homedir7 } from "os";
86932
+ import { dirname as dirname14, isAbsolute as isAbsolute3, join as join20, resolve as resolve6, sep } from "path";
86902
86933
  function parseImporterVersion(version3) {
86903
86934
  if (version3 === undefined) {
86904
86935
  return null;
@@ -86953,7 +86984,7 @@ async function buildRefreshCoverage(db2, selector, fanOut) {
86953
86984
  async function runSessionAugmentedRoots(source, home, cwd, dao2) {
86954
86985
  const roots = getSourceDefinition(source).defaultRoots.map((root) => resolve6(home, root));
86955
86986
  const runRoots = [];
86956
- const runRoot = join19(cwd, ".spur", "run");
86987
+ const runRoot = join20(cwd, ".spur", "run");
86957
86988
  if (!existsSync6(runRoot))
86958
86989
  return { roots, runRoots };
86959
86990
  const sourcesByRun = new Map;
@@ -86963,7 +86994,7 @@ async function runSessionAugmentedRoots(source, home, cwd, dao2) {
86963
86994
  sourcesByRun.set(row.run_id, sources);
86964
86995
  }
86965
86996
  for (const runId of readdirSync6(runRoot)) {
86966
- const sessionsRoot = join19(runRoot, runId, "agent-sessions");
86997
+ const sessionsRoot = join20(runRoot, runId, "agent-sessions");
86967
86998
  if (!existsSync6(sessionsRoot))
86968
86999
  continue;
86969
87000
  const mappedSources = sourcesByRun.get(runId);
@@ -86972,7 +87003,7 @@ async function runSessionAugmentedRoots(source, home, cwd, dao2) {
86972
87003
  const soleMappedSource = mappedSources?.size === 1 && mappedSources.has(source);
86973
87004
  if (!directMatch && !soleMappedSource)
86974
87005
  continue;
86975
- const root = realpathSync4(join19(sessionsRoot, agent));
87006
+ const root = realpathSync4(join20(sessionsRoot, agent));
86976
87007
  roots.push(root);
86977
87008
  runRoots.push({ runId, root });
86978
87009
  }
@@ -86993,7 +87024,7 @@ class HistoryService {
86993
87024
  const startedAt = new Date().toISOString();
86994
87025
  const db2 = await this.ctx.getDb();
86995
87026
  const dao2 = new RunSessionDao(db2);
86996
- const discovery = parsedSource !== "opencode" && opts.file === undefined && opts.root === undefined ? await runSessionAugmentedRoots(parsedSource, this.ctx.historyHome ?? homedir6(), this.ctx.cwd ?? process.cwd(), dao2) : undefined;
87027
+ const discovery = parsedSource !== "opencode" && opts.file === undefined && opts.root === undefined ? await runSessionAugmentedRoots(parsedSource, this.ctx.historyHome ?? homedir7(), this.ctx.cwd ?? process.cwd(), dao2) : undefined;
86997
87028
  const result = parsedSource === "opencode" && opts.file === undefined && opts.root === undefined ? await runOpenCodeImport({
86998
87029
  db: db2,
86999
87030
  sourceDatabase: this.ctx.openCodeSourceDatabase,
@@ -87060,7 +87091,7 @@ class HistoryService {
87060
87091
  }
87061
87092
  async maintain(opts = {}) {
87062
87093
  const db2 = await this.ctx.getDb();
87063
- const dbPath = this.ctx.cwd ? join19(this.ctx.cwd, ".spur", "spur.db") : undefined;
87094
+ const dbPath = this.ctx.cwd ? join20(this.ctx.cwd, ".spur", "spur.db") : undefined;
87064
87095
  return maintainDatabase(db2, {
87065
87096
  ...opts,
87066
87097
  ...dbPath && opts.dbPath === undefined ? { dbPath } : {}
@@ -87568,9 +87599,9 @@ function resolveArtifactPaths(artifact, opts) {
87568
87599
  return { artifactPath: out, sidecarPath: `${out.replace(/\.json$/, "")}.errors.jsonl` };
87569
87600
  }
87570
87601
  const base2 = resolve6(opts.cwd, ".spur", "reports", "history");
87571
- const dateDir = join19(base2, artifact.generatedAt.slice(0, 10));
87602
+ const dateDir = join20(base2, artifact.generatedAt.slice(0, 10));
87572
87603
  const name = `analyze-${selectorDigest(artifact.selector)}`;
87573
- return { artifactPath: join19(dateDir, `${name}.json`), sidecarPath: join19(dateDir, `${name}.errors.jsonl`) };
87604
+ return { artifactPath: join20(dateDir, `${name}.json`), sidecarPath: join20(dateDir, `${name}.errors.jsonl`) };
87574
87605
  }
87575
87606
  function boundCoverage(coverage) {
87576
87607
  const overflow = [];
@@ -87593,7 +87624,7 @@ function boundCoverage(coverage) {
87593
87624
  }
87594
87625
  function updateLatestPointer(opts, artifactPath) {
87595
87626
  const base2 = resolve6(opts.cwd, ".spur", "reports", "history");
87596
- const latest = join19(base2, "latest.json");
87627
+ const latest = join20(base2, "latest.json");
87597
87628
  mkdirSync7(base2, { recursive: true });
87598
87629
  if (existsSync6(latest))
87599
87630
  unlinkSync2(latest);
@@ -87659,7 +87690,7 @@ function formatIssue(issue2) {
87659
87690
  return `${issue2.sourceFile}:${issue2.sourceLine}: ${issue2.reason}`;
87660
87691
  }
87661
87692
  function pruneReports(cwd, retentionDays = REPORT_RETENTION_DAYS, now2 = new Date) {
87662
- const dir = join19(cwd, ".spur", "reports", "history");
87693
+ const dir = join20(cwd, ".spur", "reports", "history");
87663
87694
  let entries;
87664
87695
  try {
87665
87696
  entries = readdirSync6(dir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
@@ -87677,7 +87708,7 @@ function pruneReports(cwd, retentionDays = REPORT_RETENTION_DAYS, now2 = new Dat
87677
87708
  if (entryDate >= cutoff)
87678
87709
  continue;
87679
87710
  try {
87680
- rmSync5(join19(dir, name), { recursive: true, force: true });
87711
+ rmSync5(join20(dir, name), { recursive: true, force: true });
87681
87712
  pruned.push(name);
87682
87713
  } catch {}
87683
87714
  }
@@ -87787,7 +87818,7 @@ function extractResolvedWorkflowFacts(workflow) {
87787
87818
  var init_composition_baseline = () => {};
87788
87819
 
87789
87820
  // ../../packages/app/src/workflow/workflow-resolver.ts
87790
- import { basename as basename8, isAbsolute as isAbsolute4, join as join20, resolve as resolve7 } from "path";
87821
+ import { basename as basename8, isAbsolute as isAbsolute4, join as join21, resolve as resolve7 } from "path";
87791
87822
  function registeredWorkflowPaths(config4) {
87792
87823
  const paths = config4?.workflows?.paths ?? [".spur/workflows/"];
87793
87824
  const bundledRoot = bundledConfigRoot();
@@ -87795,7 +87826,7 @@ function registeredWorkflowPaths(config4) {
87795
87826
  for (const path9 of paths) {
87796
87827
  if (path9.startsWith(BUNDLED_PATH_PREFIX)) {
87797
87828
  if (bundledRoot !== null)
87798
- expanded.push(join20(bundledRoot, path9.slice(BUNDLED_PATH_PREFIX.length)));
87829
+ expanded.push(join21(bundledRoot, path9.slice(BUNDLED_PATH_PREFIX.length)));
87799
87830
  } else {
87800
87831
  expanded.push(path9);
87801
87832
  }
@@ -87807,7 +87838,7 @@ function normalizeLayerPath(cwd, path9) {
87807
87838
  }
87808
87839
  function workflowLayers(opts) {
87809
87840
  const sharedRoot = opts.sharedRoot !== undefined ? opts.sharedRoot : bundledConfigRoot();
87810
- const sharedPath = sharedRoot !== null ? normalizeLayerPath(opts.cwd, join20(sharedRoot, "workflows")) : null;
87841
+ const sharedPath = sharedRoot !== null ? normalizeLayerPath(opts.cwd, join21(sharedRoot, "workflows")) : null;
87811
87842
  const layers = [];
87812
87843
  const seen = new Set;
87813
87844
  const add = (id, path9) => {
@@ -87816,7 +87847,7 @@ function workflowLayers(opts) {
87816
87847
  seen.add(path9);
87817
87848
  layers.push({ id, path: path9 });
87818
87849
  };
87819
- add("project", normalizeLayerPath(opts.cwd, join20(opts.cwd, ".spur", "workflows")));
87850
+ add("project", normalizeLayerPath(opts.cwd, join21(opts.cwd, ".spur", "workflows")));
87820
87851
  for (const entry of opts.registered) {
87821
87852
  if (sharedPath !== null && normalizeLayerPath(opts.cwd, entry) === sharedPath)
87822
87853
  continue;
@@ -87860,7 +87891,7 @@ async function scanWorkflowByName(cwd, name, registered) {
87860
87891
  try {
87861
87892
  const files = (await fs3.readDir(layer.path)).filter((f) => f.endsWith(".yaml") || f.endsWith(".yml"));
87862
87893
  for (const f of files) {
87863
- const abs = join20(layer.path, f);
87894
+ const abs = join21(layer.path, f);
87864
87895
  const wfName = await readWorkflowNameFast(fs3, abs);
87865
87896
  if (wfName === name) {
87866
87897
  return { path: abs, source: layer.id };
@@ -87902,16 +87933,16 @@ function resolveWorkflowFile(cwd, file2) {
87902
87933
  const bundledRoot = bundledConfigRoot();
87903
87934
  if (bundledRoot !== null) {
87904
87935
  const sharedName = isYaml ? base2 : `${base2}.yaml`;
87905
- const sharedPath = join20(bundledRoot, "workflows", sharedName);
87936
+ const sharedPath = join21(bundledRoot, "workflows", sharedName);
87906
87937
  if (fs3.exists(sharedPath)) {
87907
87938
  return { path: sharedPath, source: "shared" };
87908
87939
  }
87909
87940
  if (!isYaml) {
87910
- const sharedPipeline = join20(bundledRoot, "workflows", `${base2}-pipeline.yaml`);
87941
+ const sharedPipeline = join21(bundledRoot, "workflows", `${base2}-pipeline.yaml`);
87911
87942
  if (fs3.exists(sharedPipeline)) {
87912
87943
  return { path: sharedPipeline, source: "shared" };
87913
87944
  }
87914
- const sharedLiteral = join20(bundledRoot, "workflows", base2);
87945
+ const sharedLiteral = join21(bundledRoot, "workflows", base2);
87915
87946
  if (fs3.exists(sharedLiteral)) {
87916
87947
  return { path: sharedLiteral, source: "shared" };
87917
87948
  }
@@ -88315,7 +88346,7 @@ var init_tripwire = __esm(() => {
88315
88346
 
88316
88347
  // ../../packages/app/src/workflow/actions/agent-run.ts
88317
88348
  import { tmpdir } from "os";
88318
- import { dirname as dirname15, isAbsolute as isAbsolute5, join as join21 } from "path";
88349
+ import { dirname as dirname15, isAbsolute as isAbsolute5, join as join22 } from "path";
88319
88350
 
88320
88351
  class AgentRunActionRunner {
88321
88352
  observabilityBus;
@@ -88349,15 +88380,15 @@ class AgentRunActionRunner {
88349
88380
  let sessionDir = freshSession ? undefined : asOptionalString(context4.vars.__agentSessionDir);
88350
88381
  if (affinityOn) {
88351
88382
  if (!sessionDir || prevAgent && prevAgent !== targetAgentDir) {
88352
- sessionDir = join21(cwd, ".spur", "run", context4.runId, "agent-sessions", targetAgentDir);
88383
+ sessionDir = join22(cwd, ".spur", "run", context4.runId, "agent-sessions", targetAgentDir);
88353
88384
  }
88354
88385
  } else {
88355
88386
  if (!sessionDir) {
88356
- sessionDir = join21(cwd, ".spur", "run", context4.runId, "agent-sessions", targetAgentDir);
88387
+ sessionDir = join22(cwd, ".spur", "run", context4.runId, "agent-sessions", targetAgentDir);
88357
88388
  }
88358
88389
  }
88359
88390
  if (freshSession) {
88360
- sessionDir = join21(cwd, ".spur", "run", context4.runId, "agent-sessions", targetAgentDir, `fresh-${context4.stateOrNodeId}`);
88391
+ sessionDir = join22(cwd, ".spur", "run", context4.runId, "agent-sessions", targetAgentDir, `fresh-${context4.stateOrNodeId}`);
88361
88392
  }
88362
88393
  const storedSessionId = freshSession ? undefined : asOptionalString(context4.vars.__agentSessionId);
88363
88394
  let continueFlag = asOptionalBoolean(options.continue);
@@ -88449,7 +88480,7 @@ class AgentRunActionRunner {
88449
88480
  flags.requiresCapabilities = JSON.stringify(requiresCapabilities.requires);
88450
88481
  }
88451
88482
  if (expectFile !== undefined) {
88452
- const target = isAbsolute5(expectFile) ? expectFile : join21(cwd, expectFile);
88483
+ const target = isAbsolute5(expectFile) ? expectFile : join22(cwd, expectFile);
88453
88484
  const fs3 = createNodeFileSystem3(cwd);
88454
88485
  if (await fs3.exists(target)) {
88455
88486
  try {
@@ -88468,7 +88499,7 @@ class AgentRunActionRunner {
88468
88499
  return;
88469
88500
  return `
88470
88501
 
88471
- Write the required artifact to this absolute path: ${join21(cwd, rel)}`;
88502
+ Write the required artifact to this absolute path: ${join22(cwd, rel)}`;
88472
88503
  })();
88473
88504
  const dispatchInput = input === undefined || absoluteArtifactHint === undefined ? input : `${input}${absoluteArtifactHint}`;
88474
88505
  const observer = this.observabilityBus === undefined ? undefined : (event) => {
@@ -88622,13 +88653,13 @@ Write the required artifact to this absolute path: ${join21(cwd, rel)}`;
88622
88653
  }
88623
88654
  }
88624
88655
  if (capture && answerFile !== undefined) {
88625
- const target = isAbsolute5(answerFile) ? answerFile : join21(cwd, answerFile);
88656
+ const target = isAbsolute5(answerFile) ? answerFile : join22(cwd, answerFile);
88626
88657
  const fs3 = createNodeFileSystem3(cwd);
88627
88658
  await fs3.ensureDir(dirname15(target));
88628
88659
  await fs3.writeFile(target, answer);
88629
88660
  }
88630
88661
  if (ok && expectFile !== undefined) {
88631
- const target = isAbsolute5(expectFile) ? expectFile : join21(cwd, expectFile);
88662
+ const target = isAbsolute5(expectFile) ? expectFile : join22(cwd, expectFile);
88632
88663
  const fs3 = createNodeFileSystem3(cwd);
88633
88664
  if (!await fs3.exists(target)) {
88634
88665
  await writePartialWorkArtifact(context4, agentLabel, model, traced, cwd, sessionDir, this.agentConfig.secretValues);
@@ -88673,7 +88704,7 @@ ${traced.stdout ?? ""}`);
88673
88704
  const resolvedAgent = invocation?.agent ?? targetAgentDir;
88674
88705
  let resolvedSessionDir = sessionDir;
88675
88706
  if (ok && affinityOn && resolvedAgent !== targetAgentDir && !context4.vars.__agentSessionDir) {
88676
- resolvedSessionDir = join21(cwd, ".spur", "run", context4.runId, "agent-sessions", resolvedAgent);
88707
+ resolvedSessionDir = join22(cwd, ".spur", "run", context4.runId, "agent-sessions", resolvedAgent);
88677
88708
  }
88678
88709
  let discoveredSessionId = storedSessionId;
88679
88710
  if (ok && affinityOn && resolvedSessionDir && !discoveredSessionId) {
@@ -88681,7 +88712,7 @@ ${traced.stdout ?? ""}`);
88681
88712
  }
88682
88713
  if (ok && affinityOn && resolvedSessionDir) {
88683
88714
  try {
88684
- const sidecarPath = join21(cwd, ".spur", "run", `${context4.runId}-agent-session.json`);
88715
+ const sidecarPath = join22(cwd, ".spur", "run", `${context4.runId}-agent-session.json`);
88685
88716
  const fs3 = createNodeFileSystem3(cwd);
88686
88717
  await fs3.ensureDir(dirname15(sidecarPath));
88687
88718
  await fs3.writeFile(sidecarPath, JSON.stringify({
@@ -88730,7 +88761,7 @@ async function discoverSessionId(sessionDir) {
88730
88761
  let newestFile;
88731
88762
  let newestMtime = 0;
88732
88763
  for (const entry of jsonEntries) {
88733
- const fullPath = join21(sessionDir, entry);
88764
+ const fullPath = join22(sessionDir, entry);
88734
88765
  const st = await fs3.stat(fullPath);
88735
88766
  if (st?.isFile() && st.mtimeMs > newestMtime) {
88736
88767
  newestMtime = st.mtimeMs;
@@ -88826,7 +88857,7 @@ async function writePartialWorkArtifact(context4, agentLabel, model, traced, cwd
88826
88857
  const headerLine = model !== undefined ? `${agentLabel} (model: ${model})` : agentLabel;
88827
88858
  const inv = traced.invocation;
88828
88859
  const argvLine = redactAndBound(inv ? `${inv.command} ${inv.argv.join(" ")}` : "(invocation not captured)", secretValues, PARTIAL_ARTIFACT_TAIL_CHARS);
88829
- const latchedSessionPath = join21(cwd, ".spur", "run", `${context4.runId}-agent-session.json`);
88860
+ const latchedSessionPath = join22(cwd, ".spur", "run", `${context4.runId}-agent-session.json`);
88830
88861
  const resumeContext = [
88831
88862
  "",
88832
88863
  "## resume context",
@@ -88842,9 +88873,9 @@ async function writePartialWorkArtifact(context4, agentLabel, model, traced, cwd
88842
88873
  try {
88843
88874
  const fs4 = createNodeFileSystem3(cwd);
88844
88875
  const locator = TaskLocator.forDirs(fs4, [
88845
- join21(cwd, "docs", "tasks3"),
88846
- join21(cwd, "docs", "tasks2"),
88847
- join21(cwd, "docs", "tasks")
88876
+ join22(cwd, "docs", "tasks3"),
88877
+ join22(cwd, "docs", "tasks2"),
88878
+ join22(cwd, "docs", "tasks")
88848
88879
  ]);
88849
88880
  const hit = await locator.findByWbs(wbs);
88850
88881
  if (hit) {
@@ -88900,7 +88931,7 @@ async function writePartialWorkArtifact(context4, agentLabel, model, traced, cwd
88900
88931
  completedSection
88901
88932
  ].join(`
88902
88933
  `);
88903
- const target = join21(cwd, ".spur", "run", `${context4.runId}-${context4.stateOrNodeId}-partial.md`);
88934
+ const target = join22(cwd, ".spur", "run", `${context4.runId}-${context4.stateOrNodeId}-partial.md`);
88904
88935
  const fs3 = createNodeFileSystem3(cwd);
88905
88936
  await fs3.ensureDir(dirname15(target));
88906
88937
  await fs3.writeFile(target, body);
@@ -88922,7 +88953,7 @@ async function gitDiffStat(cwd) {
88922
88953
  }
88923
88954
  }
88924
88955
  async function createGitWorkingTreeSnapshot(cwd, excludeGlobs = ["docs/tasks3/*", "docs/features/*"]) {
88925
- const indexFile = join21(tmpdir(), `spur-implement-scope-${crypto.randomUUID()}.index`);
88956
+ const indexFile = join22(tmpdir(), `spur-implement-scope-${crypto.randomUUID()}.index`);
88926
88957
  const fs3 = createNodeFileSystem3(cwd);
88927
88958
  let keepIndex = false;
88928
88959
  try {
@@ -89053,9 +89084,9 @@ async function findOutOfScopeChanges(cwd, wbs, changed) {
89053
89084
  try {
89054
89085
  const fs3 = createNodeFileSystem3(cwd);
89055
89086
  const locator = TaskLocator.forDirs(fs3, [
89056
- join21(cwd, "docs", "tasks3"),
89057
- join21(cwd, "docs", "tasks2"),
89058
- join21(cwd, "docs", "tasks")
89087
+ join22(cwd, "docs", "tasks3"),
89088
+ join22(cwd, "docs", "tasks2"),
89089
+ join22(cwd, "docs", "tasks")
89059
89090
  ]);
89060
89091
  const hit = await locator.findByWbs(wbs);
89061
89092
  if (!hit)
@@ -89105,7 +89136,7 @@ var init_child_env = __esm(() => {
89105
89136
  });
89106
89137
 
89107
89138
  // ../../packages/app/src/workflow/actions/run-path.ts
89108
- import { dirname as dirname16, join as join22, normalize, relative as relative3, resolve as resolve8, sep as sep2 } from "path";
89139
+ import { dirname as dirname16, join as join23, normalize, relative as relative3, resolve as resolve8, sep as sep2 } from "path";
89109
89140
  function within(child, ancestor) {
89110
89141
  return child === ancestor || child.startsWith(`${ancestor}${sep2}`);
89111
89142
  }
@@ -89114,7 +89145,7 @@ async function resolveRunArtifactPath(fileSystem, workdir, pathRaw) {
89114
89145
  throw new RunArtifactPathError("physical path confinement requires a FileSystem with realPath support \u2014 refusing to skip confinement (0785 R2)");
89115
89146
  }
89116
89147
  const lexicalTarget = normalize(resolve8(workdir, pathRaw));
89117
- const lexicalRunRoot = normalize(join22(resolve8(workdir), ".spur", "run"));
89148
+ const lexicalRunRoot = normalize(join23(resolve8(workdir), ".spur", "run"));
89118
89149
  if (!lexicalTarget.startsWith(`${lexicalRunRoot}${sep2}`)) {
89119
89150
  throw new RunArtifactPathError(`must resolve beneath .spur/run/ (got ${pathRaw})`);
89120
89151
  }
@@ -89125,7 +89156,7 @@ async function resolveRunArtifactPath(fileSystem, workdir, pathRaw) {
89125
89156
  } catch (error51) {
89126
89157
  throw new RunArtifactPathError(`project workdir could not be canonicalized: ${error51.message}`);
89127
89158
  }
89128
- const canonicalRunRootCandidate = join22(canonicalWorkdir, ".spur", "run");
89159
+ const canonicalRunRootCandidate = join23(canonicalWorkdir, ".spur", "run");
89129
89160
  let canonicalRunRoot = canonicalRunRootCandidate;
89130
89161
  const rootStat = await fileSystem.stat(canonicalRunRootCandidate);
89131
89162
  if (rootStat !== null) {
@@ -89173,7 +89204,7 @@ async function resolveRunArtifactPath(fileSystem, workdir, pathRaw) {
89173
89204
  if (!within(anchor, canonicalWorkdir)) {
89174
89205
  throw new RunArtifactPathError(`ancestor ${probe} escapes the project workdir through a symlink`);
89175
89206
  }
89176
- const reconstructed = normalize(join22(anchor, relative3(probe, lexicalTarget)));
89207
+ const reconstructed = normalize(join23(anchor, relative3(probe, lexicalTarget)));
89177
89208
  if (!reconstructed.startsWith(`${canonicalRunRoot}${sep2}`)) {
89178
89209
  throw new RunArtifactPathError(`path escapes .spur/run/ through a symlink (got ${pathRaw})`);
89179
89210
  }
@@ -89190,7 +89221,7 @@ var init_run_path = __esm(() => {
89190
89221
  });
89191
89222
 
89192
89223
  // ../../packages/app/src/workflow/actions/command-gate.ts
89193
- import { join as join23, normalize as normalize2 } from "path";
89224
+ import { join as join24, normalize as normalize2 } from "path";
89194
89225
  function sleep2(ms) {
89195
89226
  return new Promise((resolve9) => setTimeout(resolve9, ms));
89196
89227
  }
@@ -89262,7 +89293,7 @@ class CommandGateActionRunner {
89262
89293
  const retryOn = Array.isArray(retry.on) ? retry.on : [];
89263
89294
  const timeoutMs = typeof options.timeoutMs === "number" ? options.timeoutMs : undefined;
89264
89295
  const env = childProcessEnv(context4.vars);
89265
- await this.fileSystem.ensureDir(normalize2(join23(normalized, "..")));
89296
+ await this.fileSystem.ensureDir(normalize2(join24(normalized, "..")));
89266
89297
  let lastStdout = "";
89267
89298
  let lastStderr = "";
89268
89299
  let lastExitCode = -1;
@@ -89919,7 +89950,7 @@ var init_http_request = __esm(() => {
89919
89950
  // ../../packages/app/src/workflow/proof-input-fingerprint.ts
89920
89951
  import crypto4 from "crypto";
89921
89952
  import { tmpdir as tmpdir2 } from "os";
89922
- import { dirname as dirname17, join as join24, resolve as resolve10, sep as sep4 } from "path";
89953
+ import { dirname as dirname17, join as join25, resolve as resolve10, sep as sep4 } from "path";
89923
89954
  function taskDocumentShapeError(content) {
89924
89955
  const doc2 = MarkdownDocument.parse(content, "task");
89925
89956
  const heading = CANONICAL_TASK_HEADING_RE.exec(doc2.bodyWithoutFrontmatter);
@@ -89994,7 +90025,7 @@ async function readProofInputContents(fileSystem = createNodeFileSystem3(), work
89994
90025
  };
89995
90026
  }
89996
90027
  async function createGitAlternateTree(cwd, excludeGlobs = DEFAULT_EXCLUDE_GLOBS, executor = new NodeProcessExecutor3, fs3 = createNodeFileSystem3()) {
89997
- const indexFile = join24(tmpdir2(), `spur-proof-fingerprint-${crypto4.randomUUID()}.index`);
90028
+ const indexFile = join25(tmpdir2(), `spur-proof-fingerprint-${crypto4.randomUUID()}.index`);
89998
90029
  try {
89999
90030
  await fs3.ensureDir(dirname17(indexFile));
90000
90031
  const env = Object.fromEntries(Object.entries(process.env).filter((entry) => entry[1] !== undefined));
@@ -90289,7 +90320,7 @@ var init_rule_check = __esm(() => {
90289
90320
  });
90290
90321
 
90291
90322
  // ../../packages/app/src/workflow/actions/run-artifact.ts
90292
- import { join as join25, resolve as resolve11 } from "path";
90323
+ import { join as join26, resolve as resolve11 } from "path";
90293
90324
 
90294
90325
  class RunArtifactActionRunner {
90295
90326
  getDb;
@@ -90567,7 +90598,7 @@ class RunArtifactActionRunner {
90567
90598
  error: `${KIND14}: proof.stages.review.status is "${String(review.status)}" \u2014 a skipped or stale review is not completed evidence (0785 R4)`
90568
90599
  };
90569
90600
  }
90570
- const markerPath = join25(resolve11(workdir), ".spur", "run", `${context4.runId}-review-proof.digest`);
90601
+ const markerPath = join26(resolve11(workdir), ".spur", "run", `${context4.runId}-review-proof.digest`);
90571
90602
  let marker = null;
90572
90603
  try {
90573
90604
  marker = await this.fileSystem.readFile(markerPath);
@@ -90911,7 +90942,7 @@ var init_checkpoint_contract = __esm(() => {
90911
90942
 
90912
90943
  // ../../packages/app/src/services/workflow-service.ts
90913
90944
  import { realpathSync as realpathSync5 } from "fs";
90914
- import { basename as basename9, dirname as dirname18, isAbsolute as isAbsolute6, join as join26, resolve as resolve12, sep as sep5 } from "path";
90945
+ import { basename as basename9, dirname as dirname18, isAbsolute as isAbsolute6, join as join27, resolve as resolve12, sep as sep5 } from "path";
90915
90946
  function signalSubprocess(pid) {
90916
90947
  if (!Number.isInteger(pid) || pid <= 1)
90917
90948
  return false;
@@ -91176,7 +91207,7 @@ class WorkflowAppService {
91176
91207
  };
91177
91208
  }
91178
91209
  async cleanRunLogs(retentionDays = 30, dryRun = false) {
91179
- const runDir = join26(this.ctx.cwd, ".spur", "run");
91210
+ const runDir = join27(this.ctx.cwd, ".spur", "run");
91180
91211
  const fs3 = createNodeFileSystem3();
91181
91212
  const cutoffMs = Date.now() - retentionDays * 24 * 60 * 60 * 1000;
91182
91213
  const reclaimed = [];
@@ -91188,7 +91219,7 @@ class WorkflowAppService {
91188
91219
  return { retentionDays, dryRun, reclaimed, failures };
91189
91220
  }
91190
91221
  for (const name of entries) {
91191
- const path9 = join26(runDir, name);
91222
+ const path9 = join27(runDir, name);
91192
91223
  const stat2 = await fs3.stat(path9);
91193
91224
  if (stat2 === null || !stat2.isFile() || stat2.mtimeMs >= cutoffMs)
91194
91225
  continue;
@@ -91207,7 +91238,7 @@ class WorkflowAppService {
91207
91238
  return { retentionDays, dryRun, reclaimed, failures };
91208
91239
  }
91209
91240
  async cleanCheckpoints(retentionDays = 30, dryRun = false) {
91210
- const sessionsDir = join26(this.ctx.cwd, ".spur", "memory", "sessions");
91241
+ const sessionsDir = join27(this.ctx.cwd, ".spur", "memory", "sessions");
91211
91242
  const fs3 = createNodeFileSystem3();
91212
91243
  let sessionsReal;
91213
91244
  try {
@@ -91227,7 +91258,7 @@ class WorkflowAppService {
91227
91258
  }
91228
91259
  const activeRunIds = new Set((await new RunDao(await this.ctx.getDb()).listActiveRuns()).map((r) => r.id));
91229
91260
  for (const name of entries) {
91230
- const path9 = join26(sessionsDir, name);
91261
+ const path9 = join27(sessionsDir, name);
91231
91262
  let resolved;
91232
91263
  try {
91233
91264
  resolved = realpathSync5(path9);
@@ -91427,7 +91458,7 @@ class WorkflowAppService {
91427
91458
  await new RunDao(db2).stampFailureReason(runId, result.reason);
91428
91459
  }
91429
91460
  async validateResumeCheckpointFreshness(runId, row, workdir) {
91430
- const sessionsDir = join26(workdir, ".spur", "memory", "sessions");
91461
+ const sessionsDir = join27(workdir, ".spur", "memory", "sessions");
91431
91462
  const fs3 = createNodeFileSystem3();
91432
91463
  let entries;
91433
91464
  try {
@@ -91461,7 +91492,7 @@ class WorkflowAppService {
91461
91492
  return head;
91462
91493
  };
91463
91494
  for (const name of entries) {
91464
- const filePath = join26(sessionsDir, name);
91495
+ const filePath = join27(sessionsDir, name);
91465
91496
  let raw;
91466
91497
  try {
91467
91498
  raw = await fs3.readFile(filePath);
@@ -91492,7 +91523,7 @@ class WorkflowAppService {
91492
91523
  const staleness = checkpointStaleness(meta3, {
91493
91524
  ...wbs !== undefined ? { taskWbs: wbs } : {},
91494
91525
  ...meta3.sourceCommit === "" ? {} : { sourceCommit: await resolveHead() },
91495
- artifactExists: (p) => fs3.exists(isAbsolute6(p) ? p : join26(workdir, p))
91526
+ artifactExists: (p) => fs3.exists(isAbsolute6(p) ? p : join27(workdir, p))
91496
91527
  });
91497
91528
  if (staleness.stale) {
91498
91529
  throw new Error(`Cannot resume run "${runId}": checkpoint is stale (${staleness.reason}).`);
@@ -92037,8 +92068,8 @@ function resolveOutputLogConfig(config4) {
92037
92068
  };
92038
92069
  }
92039
92070
  async function outputArtifactForRun(cwd, runId) {
92040
- const relative4 = join26(".spur", "run", `${runId}.log`);
92041
- return await fileExists(join26(cwd, relative4)) ? relative4 : undefined;
92071
+ const relative4 = join27(".spur", "run", `${runId}.log`);
92072
+ return await fileExists(join27(cwd, relative4)) ? relative4 : undefined;
92042
92073
  }
92043
92074
  async function scanWorkflowFiles(rootPath, source, loadEntry) {
92044
92075
  const entries = [];
@@ -92236,7 +92267,7 @@ function projectActionTraceResult(resultJson, secretValues = []) {
92236
92267
  async function partialArtifactForAction(cwd, runId, node, ok) {
92237
92268
  if (ok !== false || !TRACE_IDENTIFIER.test(runId) || !TRACE_IDENTIFIER.test(node))
92238
92269
  return;
92239
- const relativePath2 = join26(".spur", "run", `${runId}-${node}-partial.md`);
92270
+ const relativePath2 = join27(".spur", "run", `${runId}-${node}-partial.md`);
92240
92271
  return await fileExists(resolve12(cwd, relativePath2)) ? relativePath2 : undefined;
92241
92272
  }
92242
92273
  var TASK_PIPELINE_WORKFLOW = "task-pipeline", PIPELINE_LINK_KIND = "pipeline", COMPOSITION_CAPS, STRUCTURE_TOKENS, TRACE_IDENTIFIER, TRACE_RESULT_FIELDS, TRACE_INVOCATION_FIELDS;
@@ -92281,7 +92312,7 @@ var init_workflow_service = __esm(() => {
92281
92312
  });
92282
92313
 
92283
92314
  // ../../packages/app/src/services/inline-run-setup.ts
92284
- import { join as join27, resolve as resolve13 } from "path";
92315
+ import { join as join28, resolve as resolve13 } from "path";
92285
92316
  function parseIdentityMetadata(raw) {
92286
92317
  if (raw.trim() === "")
92287
92318
  return {};
@@ -92295,8 +92326,8 @@ function parseIdentityMetadata(raw) {
92295
92326
  }
92296
92327
  }
92297
92328
  async function openInlineRunProjectDb(workdir) {
92298
- const url2 = join27(resolve13(workdir), ".spur", "spur.db");
92299
- mkdirSync8(join27(url2, ".."), { recursive: true });
92329
+ const url2 = join28(resolve13(workdir), ".spur", "spur.db");
92330
+ mkdirSync8(join28(url2, ".."), { recursive: true });
92300
92331
  const adapter = await createMigratedDb({ url: url2 });
92301
92332
  return { adapter, close: () => adapter.close() };
92302
92333
  }
@@ -93248,8 +93279,8 @@ var init_project_start = __esm(() => {
93248
93279
  });
93249
93280
 
93250
93281
  // ../../packages/app/src/services/rule-service.ts
93251
- import { homedir as homedir7 } from "os";
93252
- import { delimiter, join as join28, relative as relative4, resolve as resolve15 } from "path";
93282
+ import { homedir as homedir8 } from "os";
93283
+ import { delimiter, join as join29, relative as relative4, resolve as resolve15 } from "path";
93253
93284
 
93254
93285
  class RuleService {
93255
93286
  context;
@@ -93444,13 +93475,13 @@ ${ruleIds.join(`
93444
93475
  const hasGlobalOverride = globalOverride !== undefined && globalOverride.length > 0;
93445
93476
  layers.push({
93446
93477
  id: "global",
93447
- path: hasGlobalOverride ? resolve15(cwd, globalOverride) : join28(homedir7(), GLOBAL_RULES_DIR),
93478
+ path: hasGlobalOverride ? resolve15(cwd, globalOverride) : join29(homedir8(), GLOBAL_RULES_DIR),
93448
93479
  priority: 10
93449
93480
  });
93450
93481
  if (opts.includeBundled && !hasGlobalOverride) {
93451
93482
  const bundledConfig = bundledConfigRoot();
93452
93483
  if (bundledConfig !== null) {
93453
- layers.push({ id: "bundled-config", path: join28(bundledConfig, "rules"), priority: 15 });
93484
+ layers.push({ id: "bundled-config", path: join29(bundledConfig, "rules"), priority: 15 });
93454
93485
  }
93455
93486
  const bundled = await bundledRulesRoot();
93456
93487
  if (bundled !== null)
@@ -93663,7 +93694,7 @@ ${ruleIds.join(`
93663
93694
  const { fs: fs3 } = this.context;
93664
93695
  for (const root of await this.ruleRoots()) {
93665
93696
  for (const ext of ["yaml", "yml", "json"]) {
93666
- if (await fs3.exists(join28(root, `${name}.${ext}`)))
93697
+ if (await fs3.exists(join29(root, `${name}.${ext}`)))
93667
93698
  return true;
93668
93699
  }
93669
93700
  }
@@ -93699,7 +93730,7 @@ ${ruleIds.join(`
93699
93730
  for (const layer of await this.existingRuleSourceLayers()) {
93700
93731
  const entries = await this.context.fs.readDir(layer.path);
93701
93732
  const named = entries.map((entry) => ({ entry, name: entry.match(/^([\w-]+)\.(?:ya?ml|json)$/i)?.[1] ?? "" })).filter(({ name }) => name.length > 0);
93702
- const stats = await Promise.all(named.map(({ entry }) => this.context.fs.stat(join28(layer.path, entry))));
93733
+ const stats = await Promise.all(named.map(({ entry }) => this.context.fs.stat(join29(layer.path, entry))));
93703
93734
  named.forEach(({ name }, i2) => {
93704
93735
  if (stats[i2]?.isFile())
93705
93736
  candidates.add(name);
@@ -93721,7 +93752,7 @@ ${ruleIds.join(`
93721
93752
  for (const layer of layers) {
93722
93753
  for (const file2 of await this.listRuleFilesInLayer(layer.path)) {
93723
93754
  if (!merged.has(file2))
93724
- merged.set(file2, { absolutePath: join28(layer.path, file2), source: layer.id });
93755
+ merged.set(file2, { absolutePath: join29(layer.path, file2), source: layer.id });
93725
93756
  }
93726
93757
  }
93727
93758
  const files = [];
@@ -93789,7 +93820,7 @@ ${ruleIds.join(`
93789
93820
  for (const entry of entries.sort()) {
93790
93821
  if (entry === "presets")
93791
93822
  continue;
93792
- const stat2 = await this.context.fs.stat(join28(root, entry));
93823
+ const stat2 = await this.context.fs.stat(join29(root, entry));
93793
93824
  if (stat2?.isDirectory())
93794
93825
  dirs.push(entry);
93795
93826
  }
@@ -93797,12 +93828,12 @@ ${ruleIds.join(`
93797
93828
  }
93798
93829
  async listRuleFiles(root, relativeDir) {
93799
93830
  const { fs: fs3 } = this.context;
93800
- const dir = join28(root, relativeDir);
93831
+ const dir = join29(root, relativeDir);
93801
93832
  const entries = await fs3.readDir(dir);
93802
93833
  const files = [];
93803
93834
  for (const entry of entries.sort()) {
93804
- const relativePath2 = relativeDir.length === 0 ? entry : join28(relativeDir, entry);
93805
- const absolutePath = join28(root, relativePath2);
93835
+ const relativePath2 = relativeDir.length === 0 ? entry : join29(relativeDir, entry);
93836
+ const absolutePath = join29(root, relativePath2);
93806
93837
  const stat2 = await fs3.stat(absolutePath);
93807
93838
  if (stat2?.isDirectory()) {
93808
93839
  files.push(...await this.listRuleFiles(root, relativePath2));
@@ -93936,8 +93967,8 @@ var init_rule_service = __esm(() => {
93936
93967
  init_dist10();
93937
93968
  init_agent_execution();
93938
93969
  init_system_event_envelope();
93939
- LOCAL_RULES_DIR = join28(".spur", "rules");
93940
- GLOBAL_RULES_DIR = join28(".config", "spur", "rules");
93970
+ LOCAL_RULES_DIR = join29(".spur", "rules");
93971
+ GLOBAL_RULES_DIR = join29(".config", "spur", "rules");
93941
93972
  SEVERITY_RANK2 = {
93942
93973
  info: 0,
93943
93974
  warning: 1,
@@ -94152,6 +94183,368 @@ var init_run_store_service = __esm(() => {
94152
94183
  };
94153
94184
  });
94154
94185
 
94186
+ // ../../packages/app/src/services/slash-commands-service.ts
94187
+ import { existsSync as existsSync8, mkdirSync as mkdirSync9, readdirSync as readdirSync7, readFileSync as readFileSync10, writeFileSync as writeFileSync6 } from "fs";
94188
+ import { homedir as homedir9 } from "os";
94189
+ import { basename as basename11, dirname as dirname19, join as join30, resolve as resolve16 } from "path";
94190
+ function getBuiltinClaudeCommands() {
94191
+ return BUILTIN_CLAUDE_COMMANDS.map((cmd) => ({ ...cmd }));
94192
+ }
94193
+ function deduceCommandCategory(nameOrStem) {
94194
+ const lower = nameOrStem.toLowerCase();
94195
+ if (/(git|commit|review|revert|pr-review|diff|branch|stash)/.test(lower)) {
94196
+ return "git";
94197
+ }
94198
+ if (/(rule|workflow|init|harness|spur|plan|run|verify|wrap|refine|parallel|idea)/.test(lower)) {
94199
+ return "harness";
94200
+ }
94201
+ if (/(doctor|cost|compact|clear|terminal|\bbug\b|config|login|logout|sys|status|ps)/.test(lower)) {
94202
+ return "sys";
94203
+ }
94204
+ return "dev";
94205
+ }
94206
+ function findPluginsSpCommandsDir(startDir = process.cwd()) {
94207
+ let current = resolve16(startDir);
94208
+ while (true) {
94209
+ try {
94210
+ const candidate = join30(current, "plugins", "sp", "commands");
94211
+ if (existsSync8(candidate)) {
94212
+ return candidate;
94213
+ }
94214
+ } catch {
94215
+ break;
94216
+ }
94217
+ const parent = dirname19(current);
94218
+ if (parent === current) {
94219
+ break;
94220
+ }
94221
+ current = parent;
94222
+ }
94223
+ return null;
94224
+ }
94225
+ function findProjectClaudeCommandsDir(startDir = process.cwd()) {
94226
+ let current = resolve16(startDir);
94227
+ while (true) {
94228
+ try {
94229
+ const candidate = join30(current, ".claude", "commands");
94230
+ if (existsSync8(candidate)) {
94231
+ return candidate;
94232
+ }
94233
+ } catch {
94234
+ break;
94235
+ }
94236
+ const parent = dirname19(current);
94237
+ if (parent === current) {
94238
+ break;
94239
+ }
94240
+ current = parent;
94241
+ }
94242
+ return null;
94243
+ }
94244
+ function parseMarkdownFrontmatter(rawContent) {
94245
+ const trimmed = rawContent.trimStart();
94246
+ if (!trimmed.startsWith("---")) {
94247
+ return { frontmatter: {}, body: rawContent };
94248
+ }
94249
+ const match = trimmed.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/);
94250
+ if (!match) {
94251
+ return { frontmatter: {}, body: rawContent };
94252
+ }
94253
+ try {
94254
+ const parsed = $parse(match[1] ?? "");
94255
+ return {
94256
+ frontmatter: typeof parsed === "object" && parsed !== null ? parsed : {},
94257
+ body: match[2] ?? ""
94258
+ };
94259
+ } catch {
94260
+ return { frontmatter: {}, body: rawContent };
94261
+ }
94262
+ }
94263
+ function scanMarkdownCommands(dirPath, options = {}) {
94264
+ if (!existsSync8(dirPath)) {
94265
+ return [];
94266
+ }
94267
+ const { prefix = "/", source = "plugin:sp", defaultCategory } = options;
94268
+ const items = [];
94269
+ try {
94270
+ const entries = readdirSync7(dirPath, { withFileTypes: true });
94271
+ for (const entry of entries) {
94272
+ if (!entry.isFile() || !entry.name.endsWith(".md")) {
94273
+ continue;
94274
+ }
94275
+ const fullPath = join30(dirPath, entry.name);
94276
+ const stem = basename11(entry.name, ".md");
94277
+ const fileContent = readFileSync10(fullPath, "utf-8");
94278
+ const { frontmatter, body } = parseMarkdownFrontmatter(fileContent);
94279
+ const cleanPrefix = prefix.endsWith(":") ? prefix : prefix.endsWith("/") ? prefix : `${prefix}:`;
94280
+ const name = prefix === "/" ? `/${stem}` : `${cleanPrefix}${stem}`;
94281
+ let description = "";
94282
+ if (typeof frontmatter.description === "string" && frontmatter.description.trim().length > 0) {
94283
+ description = frontmatter.description.trim();
94284
+ } else {
94285
+ const lines = body.split(`
94286
+ `).map((l) => l.trim()).filter((l) => l.length > 0);
94287
+ const firstHeading = lines.find((l) => l.startsWith("# "));
94288
+ const firstLine = lines[0];
94289
+ if (firstHeading) {
94290
+ description = firstHeading.replace(/^#\s+/, "").trim();
94291
+ } else if (firstLine !== undefined) {
94292
+ description = firstLine.replace(/^[#*-\s]+/, "").trim();
94293
+ } else {
94294
+ description = stem.replace(/[-_]/g, " ");
94295
+ }
94296
+ }
94297
+ let category;
94298
+ const fmCategory = typeof frontmatter.category === "string" ? frontmatter.category.toLowerCase() : "";
94299
+ if (fmCategory === "git" || fmCategory === "dev" || fmCategory === "sys" || fmCategory === "harness") {
94300
+ category = fmCategory;
94301
+ } else {
94302
+ category = defaultCategory ?? deduceCommandCategory(stem);
94303
+ }
94304
+ const hintRaw = frontmatter["argument-hint"] ?? frontmatter.argumentHint;
94305
+ const argumentHint = typeof hintRaw === "string" && hintRaw.trim().length > 0 ? hintRaw.trim() : undefined;
94306
+ const roleRaw = frontmatter.role;
94307
+ const role = typeof roleRaw === "string" && roleRaw.trim().length > 0 ? roleRaw.trim() : undefined;
94308
+ items.push({
94309
+ name,
94310
+ description,
94311
+ category,
94312
+ argumentHint,
94313
+ role,
94314
+ source
94315
+ });
94316
+ }
94317
+ } catch {}
94318
+ return items;
94319
+ }
94320
+ function generateSlashCommands(options = {}) {
94321
+ const {
94322
+ projectRoot = process.cwd(),
94323
+ includeBuiltin = true,
94324
+ includePluginSp = true,
94325
+ includeProjectClaude = true,
94326
+ includeUserClaude = true,
94327
+ includeUserSpur = true
94328
+ } = options;
94329
+ const commandMap = new Map;
94330
+ if (includeBuiltin) {
94331
+ for (const cmd of getBuiltinClaudeCommands()) {
94332
+ commandMap.set(cmd.name, cmd);
94333
+ }
94334
+ }
94335
+ if (includePluginSp) {
94336
+ const spCommandsDir = findPluginsSpCommandsDir(projectRoot) ?? resolve16(projectRoot, "plugins", "sp", "commands");
94337
+ const spCommands = scanMarkdownCommands(spCommandsDir, {
94338
+ prefix: "/sp:",
94339
+ source: "plugin:sp",
94340
+ defaultCategory: "harness"
94341
+ });
94342
+ for (const cmd of spCommands) {
94343
+ commandMap.set(cmd.name, cmd);
94344
+ }
94345
+ }
94346
+ if (includeProjectClaude) {
94347
+ const projectClaudeDir = findProjectClaudeCommandsDir(projectRoot) ?? resolve16(projectRoot, ".claude", "commands");
94348
+ const projectCommands = scanMarkdownCommands(projectClaudeDir, {
94349
+ prefix: "/",
94350
+ source: "claude:project"
94351
+ });
94352
+ for (const cmd of projectCommands) {
94353
+ commandMap.set(cmd.name, cmd);
94354
+ }
94355
+ }
94356
+ if (includeUserClaude) {
94357
+ const userClaudeDir = join30(homedir9(), ".claude", "commands");
94358
+ const userClaudeCommands = scanMarkdownCommands(userClaudeDir, {
94359
+ prefix: "/",
94360
+ source: "claude:user"
94361
+ });
94362
+ for (const cmd of userClaudeCommands) {
94363
+ commandMap.set(cmd.name, cmd);
94364
+ }
94365
+ }
94366
+ if (includeUserSpur) {
94367
+ const userSpurDir = join30(homedir9(), ".config", "spur", "commands");
94368
+ const userSpurCommands = scanMarkdownCommands(userSpurDir, {
94369
+ prefix: "/sp:",
94370
+ source: "spur:user",
94371
+ defaultCategory: "harness"
94372
+ });
94373
+ for (const cmd of userSpurCommands) {
94374
+ commandMap.set(cmd.name, cmd);
94375
+ }
94376
+ }
94377
+ return Array.from(commandMap.values());
94378
+ }
94379
+ function generateSlashCommandsFile(targetPath = getSlashCommandsFilePath(), options = {}) {
94380
+ const commands = generateSlashCommands(options);
94381
+ const filePayload = {
94382
+ version: 1,
94383
+ updatedAt: new Date().toISOString(),
94384
+ commands
94385
+ };
94386
+ try {
94387
+ const dir = dirname19(targetPath);
94388
+ if (!existsSync8(dir)) {
94389
+ mkdirSync9(dir, { recursive: true });
94390
+ }
94391
+ writeFileSync6(targetPath, JSON.stringify(filePayload, null, 2), "utf-8");
94392
+ } catch {}
94393
+ return {
94394
+ path: targetPath,
94395
+ count: commands.length,
94396
+ commands
94397
+ };
94398
+ }
94399
+ function loadSlashCommands(filePath = getSlashCommandsFilePath(), autoGenerateIfMissing = true, options = {}) {
94400
+ if (!existsSync8(filePath)) {
94401
+ if (autoGenerateIfMissing) {
94402
+ const generated = generateSlashCommandsFile(filePath, options);
94403
+ return generated.commands;
94404
+ }
94405
+ return getBuiltinClaudeCommands();
94406
+ }
94407
+ try {
94408
+ const content = readFileSync10(filePath, "utf-8");
94409
+ const raw = JSON.parse(content);
94410
+ const parsed = slashCommandsFileSchema.safeParse(raw);
94411
+ if (parsed.success && parsed.data.commands.length > 0) {
94412
+ return parsed.data.commands;
94413
+ }
94414
+ } catch {}
94415
+ if (autoGenerateIfMissing) {
94416
+ const generated = generateSlashCommandsFile(filePath, options);
94417
+ return generated.commands;
94418
+ }
94419
+ return getBuiltinClaudeCommands();
94420
+ }
94421
+
94422
+ class SlashCommandsService {
94423
+ filePath;
94424
+ projectRoot;
94425
+ cachedCommands = null;
94426
+ constructor(options = {}) {
94427
+ this.filePath = options.filePath ?? getSlashCommandsFilePath();
94428
+ this.projectRoot = options.projectRoot ?? process.cwd();
94429
+ }
94430
+ getFilePath() {
94431
+ return this.filePath;
94432
+ }
94433
+ getCommands(forceReload = false) {
94434
+ if (!this.cachedCommands || forceReload) {
94435
+ this.cachedCommands = loadSlashCommands(this.filePath, true, {
94436
+ projectRoot: this.projectRoot
94437
+ });
94438
+ }
94439
+ return this.cachedCommands;
94440
+ }
94441
+ generate(targetPath) {
94442
+ const dest = targetPath ?? this.filePath;
94443
+ const result = generateSlashCommandsFile(dest, {
94444
+ projectRoot: this.projectRoot
94445
+ });
94446
+ this.cachedCommands = result.commands;
94447
+ return result;
94448
+ }
94449
+ }
94450
+ var BUILTIN_CLAUDE_COMMANDS;
94451
+ var init_slash_commands_service = __esm(() => {
94452
+ init_src();
94453
+ init_dist2();
94454
+ BUILTIN_CLAUDE_COMMANDS = [
94455
+ {
94456
+ name: "/help",
94457
+ description: "View available commands, tools, and usage hints",
94458
+ category: "sys",
94459
+ source: "builtin"
94460
+ },
94461
+ {
94462
+ name: "/clear",
94463
+ description: "Clear conversation history and reset context window",
94464
+ category: "sys",
94465
+ source: "builtin"
94466
+ },
94467
+ {
94468
+ name: "/compact",
94469
+ description: "Purge execution trace and condense context window",
94470
+ category: "sys",
94471
+ source: "builtin"
94472
+ },
94473
+ {
94474
+ name: "/cost",
94475
+ description: "Inspect token breakdown and USD expenditure",
94476
+ category: "sys",
94477
+ source: "builtin"
94478
+ },
94479
+ {
94480
+ name: "/doctor",
94481
+ description: "Run diagnostic health checks on environment and tools",
94482
+ category: "sys",
94483
+ source: "builtin"
94484
+ },
94485
+ {
94486
+ name: "/init",
94487
+ description: "Initialize project instructions, settings and guidelines",
94488
+ category: "harness",
94489
+ source: "builtin"
94490
+ },
94491
+ {
94492
+ name: "/review",
94493
+ description: "Inspect staged git diff, verify test coverage & lint",
94494
+ category: "git",
94495
+ source: "builtin"
94496
+ },
94497
+ {
94498
+ name: "/commit",
94499
+ description: "Draft conventional commit message from staged hunks",
94500
+ category: "git",
94501
+ source: "builtin"
94502
+ },
94503
+ {
94504
+ name: "/terminal",
94505
+ description: "Run isolated bash execution in sandbox mirror",
94506
+ category: "sys",
94507
+ source: "builtin"
94508
+ },
94509
+ {
94510
+ name: "/revert",
94511
+ description: "Undo last agent file changes or restore git stash",
94512
+ category: "git",
94513
+ source: "builtin"
94514
+ },
94515
+ {
94516
+ name: "/resume",
94517
+ description: "Resume paused background agent run",
94518
+ category: "dev",
94519
+ source: "builtin"
94520
+ },
94521
+ {
94522
+ name: "/bug",
94523
+ description: "Report a bug or issue with diagnostic transcript",
94524
+ category: "sys",
94525
+ source: "builtin"
94526
+ },
94527
+ {
94528
+ name: "/config",
94529
+ description: "View or update local/global configuration settings",
94530
+ category: "sys",
94531
+ source: "builtin"
94532
+ },
94533
+ {
94534
+ name: "/login",
94535
+ description: "Authenticate account and refresh API credentials",
94536
+ category: "sys",
94537
+ source: "builtin"
94538
+ },
94539
+ {
94540
+ name: "/logout",
94541
+ description: "Sign out of current account and remove stored session",
94542
+ category: "sys",
94543
+ source: "builtin"
94544
+ }
94545
+ ];
94546
+ });
94547
+
94155
94548
  // ../../packages/app/src/services/write-slot-service.ts
94156
94549
  import { randomUUID as randomUUID2 } from "crypto";
94157
94550
 
@@ -94501,7 +94894,7 @@ var init_strategy_runtime = __esm(() => {
94501
94894
  });
94502
94895
 
94503
94896
  // ../../packages/app/src/services/supervisor-service.ts
94504
- import { dirname as dirname19 } from "path";
94897
+ import { dirname as dirname20 } from "path";
94505
94898
  function defaultWrapperArgv(agentId) {
94506
94899
  return {
94507
94900
  command: process.execPath,
@@ -94561,7 +94954,7 @@ class SupervisorService {
94561
94954
  }
94562
94955
  if (spec.tags.some((tag) => tag.startsWith("fleet:"))) {
94563
94956
  await new FleetService({
94564
- fs: createNodeFileSystem3(dirname19(dirname19(this.configDir)))
94957
+ fs: createNodeFileSystem3(dirname20(dirname20(this.configDir)))
94565
94958
  }).assertLaunchGroundTruth(spec.workspace);
94566
94959
  }
94567
94960
  const { command, args } = this.resolveCommand(spec);
@@ -94651,10 +95044,10 @@ class SupervisorService {
94651
95044
  proc.handle.kill("SIGTERM");
94652
95045
  let timedOut = false;
94653
95046
  const exitPromise = proc.handle.exited;
94654
- const timeout = new Promise((resolve16) => {
95047
+ const timeout = new Promise((resolve17) => {
94655
95048
  setTimeout(() => {
94656
95049
  timedOut = true;
94657
- resolve16();
95050
+ resolve17();
94658
95051
  }, 3000);
94659
95052
  });
94660
95053
  await Promise.race([exitPromise, timeout]);
@@ -95054,7 +95447,7 @@ async function* followSystemEventsAfter(getDb, opts) {
95054
95447
  await sleep3(FOLLOW_POLL_INTERVAL_MS);
95055
95448
  }
95056
95449
  }
95057
- var FOLLOW_POLL_INTERVAL_MS = 100, FOLLOW_BATCH_SIZE = 512, sleep3 = (ms) => new Promise((resolve16) => setTimeout(resolve16, ms));
95450
+ var FOLLOW_POLL_INTERVAL_MS = 100, FOLLOW_BATCH_SIZE = 512, sleep3 = (ms) => new Promise((resolve17) => setTimeout(resolve17, ms));
95058
95451
  var init_system_event_follow = __esm(() => {
95059
95452
  init_src2();
95060
95453
  });
@@ -95302,7 +95695,7 @@ var init_task_readiness = __esm(() => {
95302
95695
  });
95303
95696
 
95304
95697
  // ../../packages/app/src/services/task-scaffold.ts
95305
- import { dirname as dirname20 } from "path";
95698
+ import { dirname as dirname21 } from "path";
95306
95699
 
95307
95700
  class TaskScaffoldService {
95308
95701
  ctx;
@@ -95345,7 +95738,7 @@ class TaskScaffoldService {
95345
95738
  fileExists2 = false;
95346
95739
  }
95347
95740
  const mergeResult = mergeStubs(existingContent, stubs);
95348
- const dir = dirname20(targetFile);
95741
+ const dir = dirname21(targetFile);
95349
95742
  await this.ctx.fs.ensureDir(dir);
95350
95743
  if (mergeResult.created > 0 || !fileExists2) {
95351
95744
  await this.ctx.fs.writeFile(targetFile, mergeResult.content);
@@ -95427,7 +95820,7 @@ var init_task_size_precheck = __esm(() => {
95427
95820
  });
95428
95821
 
95429
95822
  // ../../packages/app/src/services/task-service.ts
95430
- import { dirname as dirname21, isAbsolute as isAbsolute7, join as join29, relative as relative5 } from "path";
95823
+ import { dirname as dirname22, isAbsolute as isAbsolute7, join as join31, relative as relative5 } from "path";
95431
95824
  function renderRosterTable(rows) {
95432
95825
  const header = `| WBS | Sub-task | Status |
95433
95826
  | --- | -------- | ------ |`;
@@ -95567,7 +95960,8 @@ ${templateBackground}`;
95567
95960
  ...input.featureId !== undefined ? { feature_id: input.featureId } : {},
95568
95961
  ...input.parentWbs !== undefined ? { parent_wbs: input.parentWbs } : {},
95569
95962
  ...input.priority !== undefined ? { priority: input.priority } : {},
95570
- ...input.tags !== undefined && input.tags.length > 0 ? { tags: input.tags } : {}
95963
+ ...input.tags !== undefined && input.tags.length > 0 ? { tags: input.tags } : {},
95964
+ ...input.estimateHours !== undefined ? { estimate_hours: input.estimateHours } : {}
95571
95965
  });
95572
95966
  let status;
95573
95967
  if (input.explicitStatus !== undefined) {
@@ -95667,7 +96061,8 @@ ${templateBackground}`;
95667
96061
  done_forced: true,
95668
96062
  done_reason: true,
95669
96063
  ac_numbering: true,
95670
- ac_altitude: true
96064
+ ac_altitude: true,
96065
+ estimate_hours: true
95671
96066
  };
95672
96067
  if (!(key2 in allowed)) {
95673
96068
  throw new Error(`Field "${key2}" is not settable via update; allowed: ${Object.keys(allowed).join(", ")}.`);
@@ -95917,8 +96312,8 @@ ${templateBackground}`;
95917
96312
  const featureId2 = fm.feature_id ?? fm["feature-id"];
95918
96313
  if (!featureId2 || featureId2.length === 0)
95919
96314
  return [];
95920
- const tasksDir = dirname21(taskFilePath);
95921
- const featuresDir = join29(tasksDir, "..", "features");
96315
+ const tasksDir = dirname22(taskFilePath);
96316
+ const featuresDir = join31(tasksDir, "..", "features");
95922
96317
  const featurePath = await (async () => {
95923
96318
  try {
95924
96319
  for (const name of await this.ctx.fs.readDir(featuresDir)) {
@@ -96062,7 +96457,8 @@ ${issues}`);
96062
96457
  plan: item.plan,
96063
96458
  acceptanceCriteria: item.acceptance_criteria,
96064
96459
  priority: item.priority,
96065
- tags: item.tags
96460
+ tags: item.tags,
96461
+ estimateHours: item.estimate_hours
96066
96462
  });
96067
96463
  try {
96068
96464
  this.validateCandidateOrThrow(item.name, shape);
@@ -96229,8 +96625,8 @@ ${block}` : block);
96229
96625
  return { wbs: hit.wbs, filePath: hit.filePath };
96230
96626
  if (opts.strict === true)
96231
96627
  return null;
96232
- const basename11 = filePath.split("/").pop() ?? "";
96233
- const capturedWbs = /^(\d{4})_.+\.md$/.exec(basename11)?.[1];
96628
+ const basename12 = filePath.split("/").pop() ?? "";
96629
+ const capturedWbs = /^(\d{4})_.+\.md$/.exec(basename12)?.[1];
96234
96630
  if (capturedWbs) {
96235
96631
  const taskPath = await this.locator.findPathByWbs(capturedWbs);
96236
96632
  if (taskPath !== null)
@@ -96702,8 +97098,8 @@ var init_task_verdict = __esm(() => {
96702
97098
  });
96703
97099
 
96704
97100
  // ../../packages/app/src/services/token-ledger-service.ts
96705
- import { closeSync as closeSync3, existsSync as existsSync8, fstatSync, openSync as openSync3, readSync } from "fs";
96706
- import { join as join30 } from "path";
97101
+ import { closeSync as closeSync3, existsSync as existsSync9, fstatSync, openSync as openSync3, readSync } from "fs";
97102
+ import { join as join32 } from "path";
96707
97103
  function isSparseToolActivity(events2) {
96708
97104
  return events2.length === 0 || !events2.some((e) => TOOL_ACTIVITY_TYPES.has(e.type));
96709
97105
  }
@@ -96754,7 +97150,7 @@ function parseLedgerLine(line) {
96754
97150
  }
96755
97151
  }
96756
97152
  function tailTokenLedgerFile(filePath, limit, chunkSize = DEFAULT_CHUNK, before) {
96757
- if (!existsSync8(filePath)) {
97153
+ if (!existsSync9(filePath)) {
96758
97154
  return { events: [], truncated: false };
96759
97155
  }
96760
97156
  const target = limit + 1;
@@ -96804,7 +97200,7 @@ class TokenLedgerService {
96804
97200
  ledgerPath;
96805
97201
  chunkSize;
96806
97202
  constructor(options) {
96807
- this.ledgerPath = options.ledgerPath ?? join30(options.cwd, TOKEN_LEDGER_RELATIVE_PATH);
97203
+ this.ledgerPath = options.ledgerPath ?? join32(options.cwd, TOKEN_LEDGER_RELATIVE_PATH);
96808
97204
  this.chunkSize = options.chunkSize ?? DEFAULT_CHUNK;
96809
97205
  }
96810
97206
  get path() {
@@ -96845,12 +97241,12 @@ class TokenLedgerService {
96845
97241
  var TOOL_ACTIVITY_TYPES, TOKEN_LEDGER_DEFAULT_LIMIT = 200, TOKEN_LEDGER_MAX_LIMIT = 1000, TOKEN_LEDGER_RELATIVE_PATH, DEFAULT_CHUNK;
96846
97242
  var init_token_ledger_service = __esm(() => {
96847
97243
  TOOL_ACTIVITY_TYPES = new Set(["read", "write", "bash", "grep", "glob"]);
96848
- TOKEN_LEDGER_RELATIVE_PATH = join30(".spur", "context", "token-ledger.jsonl");
97244
+ TOKEN_LEDGER_RELATIVE_PATH = join32(".spur", "context", "token-ledger.jsonl");
96849
97245
  DEFAULT_CHUNK = 64 * 1024;
96850
97246
  });
96851
97247
 
96852
97248
  // ../../packages/app/src/services/token-ledger-watcher.ts
96853
- import { closeSync as closeSync4, existsSync as existsSync9, fstatSync as fstatSync2, openSync as openSync4, readSync as readSync2, watch } from "fs";
97249
+ import { closeSync as closeSync4, existsSync as existsSync10, fstatSync as fstatSync2, openSync as openSync4, readSync as readSync2, watch } from "fs";
96854
97250
 
96855
97251
  class TokenLedgerWatcher {
96856
97252
  ledgerPath;
@@ -96871,7 +97267,7 @@ class TokenLedgerWatcher {
96871
97267
  this.started = true;
96872
97268
  this.offset = this.currentSize();
96873
97269
  try {
96874
- const target = existsSync9(this.ledgerPath) ? this.ledgerPath : this.parentDir();
97270
+ const target = existsSync10(this.ledgerPath) ? this.ledgerPath : this.parentDir();
96875
97271
  this.watcher = watch(target, () => this.schedulePoll());
96876
97272
  } catch {
96877
97273
  this.watcher = undefined;
@@ -96906,7 +97302,7 @@ class TokenLedgerWatcher {
96906
97302
  return idx > 0 ? this.ledgerPath.slice(0, idx) : ".";
96907
97303
  }
96908
97304
  currentSize() {
96909
- if (!existsSync9(this.ledgerPath))
97305
+ if (!existsSync10(this.ledgerPath))
96910
97306
  return 0;
96911
97307
  try {
96912
97308
  const fd = openSync4(this.ledgerPath, "r");
@@ -96928,7 +97324,7 @@ class TokenLedgerWatcher {
96928
97324
  }, this.debounceMs);
96929
97325
  }
96930
97326
  pollNewBytes() {
96931
- if (!existsSync9(this.ledgerPath)) {
97327
+ if (!existsSync10(this.ledgerPath)) {
96932
97328
  this.offset = 0;
96933
97329
  this.carry = "";
96934
97330
  return;
@@ -96973,7 +97369,7 @@ var init_token_ledger_watcher = __esm(() => {
96973
97369
  });
96974
97370
 
96975
97371
  // ../../packages/app/src/workflow/idea-handoff.ts
96976
- import { resolve as resolve16 } from "path";
97372
+ import { resolve as resolve17 } from "path";
96977
97373
  function processEvidence(r) {
96978
97374
  return `exit=${r.exitCode ?? "null"}${r.signal ? ` signal=${r.signal}` : ""}: ${r.stderr.trim() || "no stderr"}`;
96979
97375
  }
@@ -96983,12 +97379,12 @@ async function finalizeIdeaHandoff(options) {
96983
97379
  const executor = options.processExecutor ?? new NodeProcessExecutor3;
96984
97380
  const spurBin = options.spurBin ?? "spur";
96985
97381
  const { runId, featureId: featureId2 } = options;
96986
- const runDir = resolve16(root, ".spur", "run");
96987
- const batchPath = resolve16(runDir, `${runId}-idea-task-batch.json`);
96988
- const resultPath = resolve16(runDir, `${runId}-idea-batch-create-result.json`);
96989
- const orderPath = resolve16(runDir, `${runId}-idea-task-order.json`);
96990
- const readyPath = resolve16(runDir, `${runId}-idea-ready.json`);
96991
- const reportPath = resolve16(runDir, `${runId}-idea-handoff.md`);
97382
+ const runDir = resolve17(root, ".spur", "run");
97383
+ const batchPath = resolve17(runDir, `${runId}-idea-task-batch.json`);
97384
+ const resultPath = resolve17(runDir, `${runId}-idea-batch-create-result.json`);
97385
+ const orderPath = resolve17(runDir, `${runId}-idea-task-order.json`);
97386
+ const readyPath = resolve17(runDir, `${runId}-idea-ready.json`);
97387
+ const reportPath = resolve17(runDir, `${runId}-idea-handoff.md`);
96992
97388
  const spurSplit = splitLaunchCommand(spurBin, 'idea-handoff "spurBin"');
96993
97389
  if ("error" in spurSplit) {
96994
97390
  return {
@@ -97781,7 +98177,7 @@ var init_progress_follow = __esm(() => {
97781
98177
  });
97782
98178
 
97783
98179
  // ../../packages/app/src/workflow/trace-writer.ts
97784
- import { dirname as dirname22, join as join31 } from "path";
98180
+ import { dirname as dirname23, join as join33 } from "path";
97785
98181
 
97786
98182
  class WorkflowTraceWriter {
97787
98183
  path;
@@ -97789,7 +98185,7 @@ class WorkflowTraceWriter {
97789
98185
  pending = Promise.resolve();
97790
98186
  constructor(cwd, runId) {
97791
98187
  const safeRunId = runId.replace(/[^A-Za-z0-9._-]/g, "_");
97792
- this.path = join31(cwd, ".spur", "workflow", `${safeRunId}.jsonl`);
98188
+ this.path = join33(cwd, ".spur", "workflow", `${safeRunId}.jsonl`);
97793
98189
  }
97794
98190
  attach(bus) {
97795
98191
  bus.on("workflow.run.started", (event) => this.enqueue("workflow.run.started", event));
@@ -97815,7 +98211,7 @@ class WorkflowTraceWriter {
97815
98211
  `;
97816
98212
  this.pending = this.pending.then(async () => {
97817
98213
  const fs3 = createNodeFileSystem3();
97818
- await fs3.ensureDir(dirname22(this.path));
98214
+ await fs3.ensureDir(dirname23(this.path));
97819
98215
  await fs3.appendFile(this.path, line);
97820
98216
  });
97821
98217
  }
@@ -97910,6 +98306,7 @@ __export(exports_src2, {
97910
98306
  setPortProbeForTests: () => setPortProbeForTests,
97911
98307
  setDetachedServeSpawnForTests: () => setDetachedServeSpawnForTests,
97912
98308
  schedulerJobTimeoutEnvName: () => schedulerJobTimeoutEnvName,
98309
+ scanMarkdownCommands: () => scanMarkdownCommands,
97913
98310
  satisfies: () => satisfies,
97914
98311
  runIdeaHandoffCli: () => runIdeaHandoffCli,
97915
98312
  runHistoryReport: () => runHistoryReport,
@@ -97982,6 +98379,7 @@ __export(exports_src2, {
97982
98379
  normalizeLegacyTimeoutMs: () => normalizeLegacyTimeoutMs,
97983
98380
  materializeRoster: () => materializeRoster,
97984
98381
  looksLikeOpaqueId: () => looksLikeOpaqueId,
98382
+ loadSlashCommands: () => loadSlashCommands,
97985
98383
  isSystemEventEnvelopeV2: () => isSystemEventEnvelopeV2,
97986
98384
  isSchedulerCustomActiveConflict: () => isSchedulerCustomActiveConflict,
97987
98385
  isRecordAuthoredReview: () => isRecordAuthoredReview,
@@ -98001,7 +98399,10 @@ __export(exports_src2, {
98001
98399
  handleHistoryRefreshJob: () => handleHistoryRefreshJob,
98002
98400
  gtdStrategy: () => gtdStrategy,
98003
98401
  getLatestSystemEventSequence: () => getLatestSystemEventSequence,
98402
+ getBuiltinClaudeCommands: () => getBuiltinClaudeCommands,
98004
98403
  genericSystemEventCatalogEntry: () => genericSystemEventCatalogEntry,
98404
+ generateSlashCommandsFile: () => generateSlashCommandsFile,
98405
+ generateSlashCommands: () => generateSlashCommands,
98005
98406
  formatNoopMessage: () => formatNoopMessage,
98006
98407
  formatIssue: () => formatIssue,
98007
98408
  formatDenialMessage: () => formatDenialMessage,
@@ -98024,6 +98425,7 @@ __export(exports_src2, {
98024
98425
  encodeRunListCursor: () => encodeRunListCursor,
98025
98426
  drainPendingAgentQuotaUpdates: () => drainPendingAgentQuotaUpdates,
98026
98427
  deriveVerdict: () => deriveVerdict,
98428
+ deduceCommandCategory: () => deduceCommandCategory,
98027
98429
  decorateWorkflowEvent: () => decorateWorkflowEvent,
98028
98430
  decodeRunListCursor: () => decodeRunListCursor,
98029
98431
  decisionKindForGate: () => decisionKindForGate,
@@ -98086,6 +98488,7 @@ __export(exports_src2, {
98086
98488
  SystemEventEmitter: () => SystemEventEmitter,
98087
98489
  SupervisorService: () => SupervisorService,
98088
98490
  StrategyRuntime: () => StrategyRuntime,
98491
+ SlashCommandsService: () => SlashCommandsService,
98089
98492
  SectionMutationError: () => SectionMutationError,
98090
98493
  SYSTEM_EVENT_UNCATALOGED_WARN_EVENT: () => SYSTEM_EVENT_UNCATALOGED_WARN_EVENT,
98091
98494
  SYSTEM_EVENT_STREAMED_NAMES: () => SYSTEM_EVENT_STREAMED_NAMES,
@@ -98174,6 +98577,7 @@ __export(exports_src2, {
98174
98577
  CommandGateActionRunner: () => CommandGateActionRunner,
98175
98578
  CHILD_KILL_GRACE_MS: () => CHILD_KILL_GRACE_MS,
98176
98579
  BusPlanningEventEmitter: () => BusPlanningEventEmitter,
98580
+ BUILTIN_CLAUDE_COMMANDS: () => BUILTIN_CLAUDE_COMMANDS,
98177
98581
  AgentService: () => AgentService,
98178
98582
  AgentRunActionRunner: () => AgentRunActionRunner,
98179
98583
  AgentExecutionLifecycle: () => AgentExecutionLifecycle,
@@ -98224,6 +98628,7 @@ var init_src3 = __esm(async () => {
98224
98628
  init_run_session_observer();
98225
98629
  init_run_store_service();
98226
98630
  init_scheduler_custom_job_service();
98631
+ init_slash_commands_service();
98227
98632
  init_strategy_runtime();
98228
98633
  init_supervisor_service();
98229
98634
  init_system_event_catch_all();
@@ -106024,10 +106429,10 @@ init_src2();
106024
106429
  init_dist7();
106025
106430
  init_dist5();
106026
106431
  await init_src3();
106027
- import { existsSync as existsSync10, readFileSync as readFileSync10 } from "fs";
106432
+ import { existsSync as existsSync11, readFileSync as readFileSync11 } from "fs";
106028
106433
  import { rm, writeFile } from "fs/promises";
106029
106434
  import { tmpdir as tmpdir3 } from "os";
106030
- import { dirname as dirname23, join as join32 } from "path";
106435
+ import { dirname as dirname24, join as join34 } from "path";
106031
106436
 
106032
106437
  // src/colors.ts
106033
106438
  var CODES = {
@@ -106992,9 +107397,9 @@ init_src2();
106992
107397
  await init_src3();
106993
107398
 
106994
107399
  // src/workflow/resolve-spur-bin.ts
106995
- import { basename as basename11 } from "path";
107400
+ import { basename as basename12 } from "path";
106996
107401
  function resolveSpurBinFrom(launch) {
106997
- const runtime = basename11(launch.execPath).toLowerCase().replace(/\.exe$/, "");
107402
+ const runtime = basename12(launch.execPath).toLowerCase().replace(/\.exe$/, "");
106998
107403
  const isJsRuntime = runtime === "bun" || runtime === "node";
106999
107404
  if (isJsRuntime && launch.mainModule) {
107000
107405
  return `${launch.execPath} ${launch.mainModule}`;
@@ -107252,7 +107657,7 @@ ${result.content}`);
107252
107657
  'Sections replace, with one exception: `--section "Q&A"` APPENDS a timestamped',
107253
107658
  "`#### Q&A entry \u2014 <ISO>` block. Start the body with `<!-- qa:replace -->` to replace it wholesale."
107254
107659
  ].join(`
107255
- `)).option(...SHARED_OPTIONS.section).option(...SHARED_OPTIONS.fromFile).option(...SHARED_OPTIONS.featureFrontmatter).option(...SHARED_OPTIONS.prioritySet).option("--ac-numbering <mode>", "Set the ac_numbering frontmatter field (task-local) \u2014 opts the task into the Requirements\u2194AC coverage check").option("--ac-altitude <mode>", "Set the ac_altitude frontmatter field. Valid: `graduating` (default; feature-AC subset rule enforced) or `task-local` (skip the DD-09 subset rule \u2014 task scenarios are intentionally not feature ship criteria). Mirrors the L1 schema enum (packages/domain/src/planning/schema.ts:304).").option("--no-lifecycle", "Suppress lifecycle workflow run creation (use during pipeline runs to avoid orphaned lifecycle runs)").option("--assignee <spec-id>", "Set the assignee frontmatter field to an agent spec id").option("--force-done", "Allow transitioning to `done` even when the verify verdict is not PASS; records an override (task 0292). Waives the verdict only \u2014 the FSM path still applies, so from an earlier status walk the hops first: `todo` \u2192 `wip` \u2192 `testing` \u2192 `done` (each hop runs the structural `spur task check`)").option("--reason <text>", "Rationale for a forced-done override (paired with --force-done; persisted as done_reason)").option("--verdict-dir <path>", "Directory holding <wbs>-verdict.json artifacts (default: .spur/run)").option(...SHARED_OPTIONS.folderTasks).option(...SHARED_OPTIONS.json).option(...SHARED_OPTIONS.jsonEnvelope).action(async (wbs, status, options) => {
107660
+ `)).option(...SHARED_OPTIONS.section).option(...SHARED_OPTIONS.fromFile).option(...SHARED_OPTIONS.featureFrontmatter).option(...SHARED_OPTIONS.prioritySet).option("--ac-numbering <mode>", "Set the ac_numbering frontmatter field (task-local) \u2014 opts the task into the Requirements\u2194AC coverage check").option("--ac-altitude <mode>", "Set the ac_altitude frontmatter field. Valid: `graduating` (default; feature-AC subset rule enforced) or `task-local` (skip the DD-09 subset rule \u2014 task scenarios are intentionally not feature ship criteria). Mirrors the L1 schema enum (packages/domain/src/planning/schema.ts:304).").option("--estimate-hours <n>", "Set the estimate_hours frontmatter field (positive number) \u2014 decomposition size estimate; the inline pipeline driver dispatches no subagent at/below its floor").option("--no-lifecycle", "Suppress lifecycle workflow run creation (use during pipeline runs to avoid orphaned lifecycle runs)").option("--assignee <spec-id>", "Set the assignee frontmatter field to an agent spec id").option("--force-done", "Allow transitioning to `done` even when the verify verdict is not PASS; records an override (task 0292). Waives the verdict only \u2014 the FSM path still applies, so from an earlier status walk the hops first: `todo` \u2192 `wip` \u2192 `testing` \u2192 `done` (each hop runs the structural `spur task check`)").option("--reason <text>", "Rationale for a forced-done override (paired with --force-done; persisted as done_reason)").option("--verdict-dir <path>", "Directory holding <wbs>-verdict.json artifacts (default: .spur/run)").option(...SHARED_OPTIONS.folderTasks).option(...SHARED_OPTIONS.json).option(...SHARED_OPTIONS.jsonEnvelope).action(async (wbs, status, options) => {
107256
107661
  const svc = await makeService(context4, options.folder, options.lifecycle === false);
107257
107662
  try {
107258
107663
  if (options.assignee !== undefined) {
@@ -107290,9 +107695,9 @@ ${result.content}`);
107290
107695
  }
107291
107696
  context4.output.write(`Updated section '${options.section}' in task ${result.ref.id}`);
107292
107697
  }
107293
- } else if (options.feature !== undefined || options.priority !== undefined || options.acNumbering !== undefined || options.acAltitude !== undefined) {
107294
- const key2 = options.feature !== undefined ? "feature_id" : options.priority !== undefined ? "priority" : options.acNumbering !== undefined ? "ac_numbering" : "ac_altitude";
107295
- const value = options.feature ?? options.priority ?? options.acNumbering ?? options.acAltitude ?? "";
107698
+ } else if (options.feature !== undefined || options.priority !== undefined || options.acNumbering !== undefined || options.acAltitude !== undefined || options.estimateHours !== undefined) {
107699
+ const key2 = options.feature !== undefined ? "feature_id" : options.priority !== undefined ? "priority" : options.acNumbering !== undefined ? "ac_numbering" : options.acAltitude !== undefined ? "ac_altitude" : "estimate_hours";
107700
+ const value = options.feature ?? options.priority ?? options.acNumbering ?? options.acAltitude ?? options.estimateHours ?? "";
107296
107701
  const result = await svc.updateField(wbs, key2, value);
107297
107702
  if (options.json) {
107298
107703
  context4.output.write(toEnvelopeJson(result, { enveloped: options.jsonEnvelope }));
@@ -107322,7 +107727,7 @@ ${result.content}`);
107322
107727
  let forcedDoneVerdict;
107323
107728
  if (status === "done") {
107324
107729
  const current = await svc.show(wbs);
107325
- const verdictDir = options.verdictDir ?? join32(context4.cwd, ".spur", "run");
107730
+ const verdictDir = options.verdictDir ?? join34(context4.cwd, ".spur", "run");
107326
107731
  const loaded = await readVerdictArtifact(context4.fs, verdictDir, wbs);
107327
107732
  const guardOutcome = evaluateDoneTransition({
107328
107733
  wbs,
@@ -107384,7 +107789,7 @@ ${result.content}`);
107384
107789
  }
107385
107790
  }
107386
107791
  } else {
107387
- context4.output.error("Either <status>, --section/--from-file, or --feature/--priority is required");
107792
+ context4.output.error("Either <status>, --section/--from-file, or a field flag (--feature/--priority/--ac-numbering/--ac-altitude/--estimate-hours) is required");
107388
107793
  context4.setExitCode(2);
107389
107794
  }
107390
107795
  } catch (err) {
@@ -107558,7 +107963,7 @@ ${result.content}`);
107558
107963
  dryRun,
107559
107964
  projectRoot: context4.cwd,
107560
107965
  write: async (filePath, wbs, section, newBody) => {
107561
- const ref = { kind: "task", id: wbs, filePath, folder: dirname23(filePath) };
107966
+ const ref = { kind: "task", id: wbs, filePath, folder: dirname24(filePath) };
107562
107967
  const ws = new PlanningWriteService({ fs: context4.fs, emitter: makePlanningEmitter(context4) });
107563
107968
  await ws.updateSection(ref, section, newBody);
107564
107969
  }
@@ -107632,7 +108037,7 @@ ${result.content}`);
107632
108037
  agentSelector: options.agent,
107633
108038
  cwd: context4.cwd
107634
108039
  });
107635
- tmpPath = join32(tmpdir3(), `spur-ready-batch-${Date.now()}-${Math.random().toString(36).slice(2, 8)}.json`);
108040
+ tmpPath = join34(tmpdir3(), `spur-ready-batch-${Date.now()}-${Math.random().toString(36).slice(2, 8)}.json`);
107636
108041
  await writeFile(tmpPath, `${JSON.stringify(prepared.items, null, 2)}
107637
108042
  `);
107638
108043
  batchFile = tmpPath;
@@ -108065,15 +108470,15 @@ function loadTemplateBodies(projectRoot, variant) {
108065
108470
  if (cached2 !== undefined)
108066
108471
  return cached2;
108067
108472
  let bodies = {};
108068
- const localPath = join32(projectRoot, ".spur", "tasks", "templates", `${variant}.md`);
108069
- if (existsSync10(localPath)) {
108070
- bodies = extractTemplateBodies(readFileSync10(localPath, "utf8"));
108473
+ const localPath = join34(projectRoot, ".spur", "tasks", "templates", `${variant}.md`);
108474
+ if (existsSync11(localPath)) {
108475
+ bodies = extractTemplateBodies(readFileSync11(localPath, "utf8"));
108071
108476
  } else {
108072
108477
  const root = bundledConfigRoot();
108073
108478
  if (root !== null) {
108074
- const templatePath = join32(root, "templates", "task", `${variant}.md`);
108075
- if (existsSync10(templatePath)) {
108076
- bodies = extractTemplateBodies(readFileSync10(templatePath, "utf8"));
108479
+ const templatePath = join34(root, "templates", "task", `${variant}.md`);
108480
+ if (existsSync11(templatePath)) {
108481
+ bodies = extractTemplateBodies(readFileSync11(templatePath, "utf8"));
108077
108482
  }
108078
108483
  }
108079
108484
  }
@@ -108129,7 +108534,7 @@ async function loadSectionMatrixUncached(projectRoot) {
108129
108534
  }
108130
108535
  const root = bundledConfigRoot();
108131
108536
  if (root !== null) {
108132
- const matrixPath = join32(root, "tasks", "section-matrix.yaml");
108537
+ const matrixPath = join34(root, "tasks", "section-matrix.yaml");
108133
108538
  if (await fs3.exists(matrixPath)) {
108134
108539
  const data = await loadStructuredSpurConfig(matrixPath, {
108135
108540
  validateJsonSchema: true,
@@ -108140,7 +108545,7 @@ async function loadSectionMatrixUncached(projectRoot) {
108140
108545
  }
108141
108546
  throw new Error(`no canonical section-matrix found for task section authority (F92 R1); tried:
108142
108547
  ` + ` - ${localPath}
108143
- ` + (root !== null ? ` - ${join32(root, "tasks", "section-matrix.yaml")}
108548
+ ` + (root !== null ? ` - ${join34(root, "tasks", "section-matrix.yaml")}
108144
108549
  ` : "") + "copy/generate section-matrix.yaml from the canonical build-time matrix asset (repo `config` `tasks` tree) into one of those paths");
108145
108550
  }
108146
108551
 
@@ -108518,15 +108923,15 @@ function parseTimeout(raw) {
108518
108923
  return n3;
108519
108924
  }
108520
108925
  function loopSleep(ms, signal) {
108521
- return new Promise((resolve17) => {
108926
+ return new Promise((resolve18) => {
108522
108927
  if (signal?.aborted) {
108523
- resolve17();
108928
+ resolve18();
108524
108929
  return;
108525
108930
  }
108526
- const timer = setTimeout(resolve17, ms);
108931
+ const timer = setTimeout(resolve18, ms);
108527
108932
  signal?.addEventListener("abort", () => {
108528
108933
  clearTimeout(timer);
108529
- resolve17();
108934
+ resolve18();
108530
108935
  }, { once: true });
108531
108936
  });
108532
108937
  }
@@ -108846,13 +109251,13 @@ function waitFail(context4, options, code, message) {
108846
109251
  // src/release-ops.ts
108847
109252
  init_src();
108848
109253
  init_dist5();
108849
- import { existsSync as existsSync12, readdirSync as readdirSync7, readFileSync as readFileSync11 } from "fs";
108850
- import { join as join34 } from "path";
109254
+ import { existsSync as existsSync13, readdirSync as readdirSync8, readFileSync as readFileSync12 } from "fs";
109255
+ import { join as join36 } from "path";
108851
109256
 
108852
109257
  // src/version-carriers.ts
108853
109258
  init_zod();
108854
- import { existsSync as existsSync11 } from "fs";
108855
- import { join as join33 } from "path";
109259
+ import { existsSync as existsSync12 } from "fs";
109260
+ import { join as join35 } from "path";
108856
109261
  var defaultLiteralProbe = { file: "src/config.ts", identifier: "binaryVersion" };
108857
109262
  var registry2 = new Map;
108858
109263
  function registerCarrierType(type, def) {
@@ -108888,7 +109293,7 @@ function findLiteralProbe(carriers, packageDir) {
108888
109293
  return;
108889
109294
  }
108890
109295
  async function readJson(path9) {
108891
- if (!existsSync11(path9))
109296
+ if (!existsSync12(path9))
108892
109297
  return null;
108893
109298
  try {
108894
109299
  return JSON.parse(await Bun.file(path9).text());
@@ -108904,7 +109309,7 @@ registerCarrierType("plugin-manifest", {
108904
109309
  schema: PluginManifestCarrierSchema,
108905
109310
  async syncRepoWide(carrier, { repoRoot }, version3, staged, output2) {
108906
109311
  for (const rel of carrier.paths) {
108907
- const absPath = join33(repoRoot, rel);
109312
+ const absPath = join35(repoRoot, rel);
108908
109313
  const manifest = await readJson(absPath);
108909
109314
  if (manifest === null) {
108910
109315
  output2.write(` \u26A0 ${rel}: not found or malformed \u2014 skipping`);
@@ -108988,7 +109393,7 @@ async function readJson2(path9) {
108988
109393
  function rootWorkspaceGlobs(repoRoot) {
108989
109394
  let root;
108990
109395
  try {
108991
- root = JSON.parse(readFileSync11(join34(repoRoot, "package.json"), "utf8"));
109396
+ root = JSON.parse(readFileSync12(join36(repoRoot, "package.json"), "utf8"));
108992
109397
  } catch {
108993
109398
  return [];
108994
109399
  }
@@ -109005,11 +109410,11 @@ function workspaceDirs(repoRoot) {
109005
109410
  if (!glob.endsWith("/*"))
109006
109411
  continue;
109007
109412
  const parent = glob.slice(0, -2);
109008
- const parentAbs = join34(repoRoot, parent);
109009
- if (!existsSync12(parentAbs))
109413
+ const parentAbs = join36(repoRoot, parent);
109414
+ if (!existsSync13(parentAbs))
109010
109415
  continue;
109011
- for (const entry of readdirSync7(parentAbs, { withFileTypes: true })) {
109012
- if (entry.isDirectory() && existsSync12(join34(parentAbs, entry.name, "package.json"))) {
109416
+ for (const entry of readdirSync8(parentAbs, { withFileTypes: true })) {
109417
+ if (entry.isDirectory() && existsSync13(join36(parentAbs, entry.name, "package.json"))) {
109013
109418
  dirs.push(`${parent}/${entry.name}`);
109014
109419
  }
109015
109420
  }
@@ -109017,14 +109422,14 @@ function workspaceDirs(repoRoot) {
109017
109422
  return dirs;
109018
109423
  }
109019
109424
  async function releaseContext(repoRoot, bumpVerConfig = resolveBuilderBumpVerConfig(null)) {
109020
- const rootManifest = await readJson2(join34(repoRoot, "package.json"));
109425
+ const rootManifest = await readJson2(join36(repoRoot, "package.json"));
109021
109426
  if (rootManifest === null) {
109022
109427
  throw new Error(`no package.json found at ${repoRoot} \u2014 builder operates on a package workspace root.`);
109023
109428
  }
109024
109429
  const rootName = typeof rootManifest.name === "string" ? rootManifest.name : "root";
109025
109430
  const workspaces2 = [];
109026
109431
  for (const dir of workspaceDirs(repoRoot)) {
109027
- const manifest = await readJson2(join34(repoRoot, dir, "package.json"));
109432
+ const manifest = await readJson2(join36(repoRoot, dir, "package.json"));
109028
109433
  if (manifest === null)
109029
109434
  continue;
109030
109435
  workspaces2.push({
@@ -109039,8 +109444,8 @@ async function releaseContext(repoRoot, bumpVerConfig = resolveBuilderBumpVerCon
109039
109444
  const packages = new Map;
109040
109445
  for (const ws of workspaces2) {
109041
109446
  const probe = findLiteralProbe(versionCarriers, ws.dir) ?? defaultLiteralProbe;
109042
- const literalProbe = join34(ws.dir, probe.file);
109043
- const versionSourceFile = existsSync12(join34(repoRoot, literalProbe)) ? literalProbe : undefined;
109447
+ const literalProbe = join36(ws.dir, probe.file);
109448
+ const versionSourceFile = existsSync13(join36(repoRoot, literalProbe)) ? literalProbe : undefined;
109044
109449
  packages.set(shortName(ws.name), {
109045
109450
  packageDir: ws.dir,
109046
109451
  packageName: ws.name,
@@ -109078,7 +109483,7 @@ async function updateWorkspacePins(ctx, pkgName, oldVersion, newVersion, output2
109078
109483
  const changed = [];
109079
109484
  for (const dir of workspaceDirs(ctx.repoRoot)) {
109080
109485
  const relPath = `${dir}/package.json`;
109081
- const manifest = await readJson2(join34(ctx.repoRoot, relPath));
109486
+ const manifest = await readJson2(join36(ctx.repoRoot, relPath));
109082
109487
  if (manifest === null)
109083
109488
  continue;
109084
109489
  let dirty = false;
@@ -109095,7 +109500,7 @@ async function updateWorkspacePins(ctx, pkgName, oldVersion, newVersion, output2
109095
109500
  }
109096
109501
  }
109097
109502
  if (dirty) {
109098
- await Bun.write(join34(ctx.repoRoot, relPath), `${JSON.stringify(manifest, null, 4)}
109503
+ await Bun.write(join36(ctx.repoRoot, relPath), `${JSON.stringify(manifest, null, 4)}
109099
109504
  `);
109100
109505
  output2.write(` \u21B3 ${relPath}: ${pkgName} workspace pin ${oldVersion} \u2192 ${newVersion}`);
109101
109506
  changed.push(relPath);
@@ -109104,7 +109509,7 @@ async function updateWorkspacePins(ctx, pkgName, oldVersion, newVersion, output2
109104
109509
  return changed;
109105
109510
  }
109106
109511
  async function updateVersionSourceFile(ctx, filePath, previous, next, output2, identifier = "binaryVersion") {
109107
- const absPath = join34(ctx.repoRoot, filePath);
109512
+ const absPath = join36(ctx.repoRoot, filePath);
109108
109513
  const content = await Bun.file(absPath).text();
109109
109514
  const pattern = new RegExp(`(${identifier.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}:\\s*['"])\\d+\\.\\d+\\.\\d+(?:-[0-9A-Za-z-.]+)?(?:\\+[0-9A-Za-z-.]+)?(['"])`);
109110
109515
  const updated = content.replace(pattern, `$1${next}$2`);
@@ -109122,7 +109527,7 @@ async function syncExtraCarriers(ctx, version3, staged, output2) {
109122
109527
  }
109123
109528
  }
109124
109529
  async function syncMarketplaceAndPlugins(ctx, version3, staged, output2) {
109125
- const marketplacePath = join34(ctx.repoRoot, ".claude-plugin", "marketplace.json");
109530
+ const marketplacePath = join36(ctx.repoRoot, ".claude-plugin", "marketplace.json");
109126
109531
  const marketplaceFile = Bun.file(marketplacePath);
109127
109532
  if (!await marketplaceFile.exists())
109128
109533
  return;
@@ -109147,7 +109552,7 @@ async function syncMarketplaceAndPlugins(ctx, version3, staged, output2) {
109147
109552
  output2.write(`Bumped marketplace plugins to ${version3}`);
109148
109553
  }
109149
109554
  for (const entry of plugins) {
109150
- const pluginJsonPath = join34(ctx.repoRoot, entry.source, "plugin.json");
109555
+ const pluginJsonPath = join36(ctx.repoRoot, entry.source, "plugin.json");
109151
109556
  const pluginJson = await readJson2(pluginJsonPath);
109152
109557
  if (pluginJson === null) {
109153
109558
  output2.write(` \u26A0 plugin.json not found at ${entry.source}/plugin.json \u2014 skipping`);
@@ -109200,7 +109605,7 @@ async function bumpVersion(ctx, config4, version3, options, output2) {
109200
109605
  if (await npmViewVersion(ctx.repoRoot, config4.packageName, version3)) {
109201
109606
  throw new Error(`${config4.packageName}@${version3} is already published on npm. Use a new version.`);
109202
109607
  }
109203
- const manifestPath = join34(ctx.repoRoot, config4.packageDir, "package.json");
109608
+ const manifestPath = join36(ctx.repoRoot, config4.packageDir, "package.json");
109204
109609
  const manifest = await readJson2(manifestPath);
109205
109610
  if (manifest === null)
109206
109611
  throw new Error(`missing or malformed manifest at ${config4.packageDir}/package.json`);
@@ -109218,8 +109623,8 @@ async function bumpVersion(ctx, config4, version3, options, output2) {
109218
109623
  staged.push(...await updateWorkspacePins(ctx, config4.packageName, previous, version3, output2));
109219
109624
  await syncMarketplaceAndPlugins(ctx, version3, staged, output2);
109220
109625
  await syncExtraCarriers(ctx, version3, staged, output2);
109221
- const lockPath = join34(ctx.repoRoot, "bun.lock");
109222
- if (existsSync12(lockPath) && Bun.file(lockPath).size > 0)
109626
+ const lockPath = join36(ctx.repoRoot, "bun.lock");
109627
+ if (existsSync13(lockPath) && Bun.file(lockPath).size > 0)
109223
109628
  staged.push("bun.lock");
109224
109629
  await git2(ctx.repoRoot, ["add", ...staged]);
109225
109630
  const message = `${config4.releaseCommitType}(${config4.releaseCommitScope}): ${config4.releaseCommitSubject(version3)}`;
@@ -109274,7 +109679,7 @@ async function bumpAll(ctx, version3, options, output2) {
109274
109679
  }
109275
109680
  const staged = [];
109276
109681
  for (const config4 of configs) {
109277
- const manifestPath = join34(ctx.repoRoot, config4.packageDir, "package.json");
109682
+ const manifestPath = join36(ctx.repoRoot, config4.packageDir, "package.json");
109278
109683
  const manifest = await readJson2(manifestPath);
109279
109684
  if (manifest === null) {
109280
109685
  throw new Error(`missing or malformed manifest at ${config4.packageDir}/package.json`);
@@ -109294,8 +109699,8 @@ async function bumpAll(ctx, version3, options, output2) {
109294
109699
  }
109295
109700
  await syncMarketplaceAndPlugins(ctx, version3, staged, output2);
109296
109701
  await syncExtraCarriers(ctx, version3, staged, output2);
109297
- const lockPath = join34(ctx.repoRoot, "bun.lock");
109298
- if (existsSync12(lockPath) && Bun.file(lockPath).size > 0)
109702
+ const lockPath = join36(ctx.repoRoot, "bun.lock");
109703
+ if (existsSync13(lockPath) && Bun.file(lockPath).size > 0)
109299
109704
  staged.push("bun.lock");
109300
109705
  await git2(ctx.repoRoot, ["add", ...staged]);
109301
109706
  const shortNames = configs.map((c3) => c3.packageName.split("/").pop() ?? c3.packageName).join(" + ");
@@ -109900,7 +110305,7 @@ import { createRequire } from "module";
109900
110305
  var CLI_CONFIG = {
109901
110306
  binaryName: "spur",
109902
110307
  binaryLabel: "spur",
109903
- binaryVersion: "0.3.83",
110308
+ binaryVersion: "0.3.84",
109904
110309
  configDir: ".spur",
109905
110310
  configFile: ".spur/config.yaml",
109906
110311
  databaseFile: ".spur/spur.db"
@@ -110311,8 +110716,8 @@ init_src();
110311
110716
  init_loader();
110312
110717
  init_src2();
110313
110718
  init_dist10();
110314
- import { homedir as homedir8 } from "os";
110315
- import { join as join35, resolve as resolve17 } from "path";
110719
+ import { homedir as homedir10 } from "os";
110720
+ import { join as join37, resolve as resolve18 } from "path";
110316
110721
 
110317
110722
  // src/config/scaffold-manifest.ts
110318
110723
  var SCAFFOLD_MANIFEST = [
@@ -110341,8 +110746,8 @@ var SCAFFOLD_MANIFEST = [
110341
110746
  ];
110342
110747
 
110343
110748
  // src/commands/init.ts
110344
- var GLOBAL_CONFIG_DIR = join35(".config", "spur");
110345
- var GLOBAL_RULES_DIR2 = join35(GLOBAL_CONFIG_DIR, "rules");
110749
+ var GLOBAL_CONFIG_DIR = join37(".config", "spur");
110750
+ var GLOBAL_RULES_DIR2 = join37(GLOBAL_CONFIG_DIR, "rules");
110346
110751
  var GLOBAL_CONFIG_EXAMPLE = BUNDLED_GLOBAL_CONFIG;
110347
110752
  var GLOBAL_CONFIG_FILE2 = "config.yaml";
110348
110753
  var INDEXED_CONTEXT_MARKER = "## Indexed context";
@@ -110373,7 +110778,7 @@ If \`.spur/context/\` is absent, proceed normally. Never block work on its absen
110373
110778
  `;
110374
110779
  function globalRulesRoot(context4) {
110375
110780
  const override = context4.env.SPUR_GLOBAL_RULES_DIR;
110376
- return override !== undefined && override.length > 0 ? resolve17(context4.cwd, override) : join35(homedir8(), GLOBAL_RULES_DIR2);
110781
+ return override !== undefined && override.length > 0 ? resolve18(context4.cwd, override) : join37(homedir10(), GLOBAL_RULES_DIR2);
110377
110782
  }
110378
110783
  async function writeIfNew(context4, path9, content, force, result) {
110379
110784
  if (!force && await context4.fs.exists(path9)) {
@@ -110390,18 +110795,18 @@ async function seedGlobalRules(context4) {
110390
110795
  const target = globalRulesRoot(context4);
110391
110796
  let written = 0;
110392
110797
  for (const relPath of await listBundledRuleFiles()) {
110393
- const destination = join35(target, relPath);
110798
+ const destination = join37(target, relPath);
110394
110799
  if (await context4.fs.exists(destination))
110395
110800
  continue;
110396
- await context4.fs.ensureDir(join35(target, ...relPath.split("/").slice(0, -1)));
110397
- await context4.fs.writeFile(destination, await context4.fs.readFile(join35(source, relPath)));
110801
+ await context4.fs.ensureDir(join37(target, ...relPath.split("/").slice(0, -1)));
110802
+ await context4.fs.writeFile(destination, await context4.fs.readFile(join37(source, relPath)));
110398
110803
  written += 1;
110399
110804
  }
110400
110805
  return written;
110401
110806
  }
110402
110807
  function resolveGlobalConfigDir(context4) {
110403
110808
  const globalOverride = context4.env.SPUR_GLOBAL_RULES_DIR;
110404
- return globalOverride !== undefined && globalOverride.length > 0 ? resolve17(context4.cwd, globalOverride) : join35(homedir8(), GLOBAL_CONFIG_DIR);
110809
+ return globalOverride !== undefined && globalOverride.length > 0 ? resolve18(context4.cwd, globalOverride) : join37(homedir10(), GLOBAL_CONFIG_DIR);
110405
110810
  }
110406
110811
  async function seedGlobalConfig(context4) {
110407
110812
  const source = bundledConfigRoot();
@@ -110412,15 +110817,15 @@ async function seedGlobalConfig(context4) {
110412
110817
  for (const relPath of listBundledConfigFiles()) {
110413
110818
  if (relPath === GLOBAL_CONFIG_EXAMPLE)
110414
110819
  continue;
110415
- const destination = join35(target, relPath);
110820
+ const destination = join37(target, relPath);
110416
110821
  if (await context4.fs.exists(destination))
110417
110822
  continue;
110418
- await context4.fs.ensureDir(join35(target, ...relPath.split("/").slice(0, -1)));
110419
- await context4.fs.writeFile(destination, await context4.fs.readFile(join35(source, relPath)));
110823
+ await context4.fs.ensureDir(join37(target, ...relPath.split("/").slice(0, -1)));
110824
+ await context4.fs.writeFile(destination, await context4.fs.readFile(join37(source, relPath)));
110420
110825
  written += 1;
110421
110826
  }
110422
- const examplePath = join35(source, GLOBAL_CONFIG_EXAMPLE);
110423
- const globalConfigPath = join35(target, GLOBAL_CONFIG_FILE2);
110827
+ const examplePath = join37(source, GLOBAL_CONFIG_EXAMPLE);
110828
+ const globalConfigPath = join37(target, GLOBAL_CONFIG_FILE2);
110424
110829
  if (await context4.fs.exists(examplePath) && !await context4.fs.exists(globalConfigPath)) {
110425
110830
  await context4.fs.ensureDir(target);
110426
110831
  await context4.fs.writeFile(globalConfigPath, await context4.fs.readFile(examplePath));
@@ -110435,10 +110840,10 @@ function registerInitCommand(program2, context4, options = {}) {
110435
110840
  const minimal = options2.minimal === true;
110436
110841
  const adoptGlobal = options2.adoptGlobalConfig === true;
110437
110842
  const projectName = options2.name ?? "default";
110438
- const configPath = join35(context4.cwd, CLI_CONFIG.configFile);
110843
+ const configPath = join37(context4.cwd, CLI_CONFIG.configFile);
110439
110844
  const result = { created: [], skipped: [] };
110440
110845
  const globalConfigDir = resolveGlobalConfigDir(context4);
110441
- const globalConfigPath = join35(globalConfigDir, GLOBAL_CONFIG_FILE2);
110846
+ const globalConfigPath = join37(globalConfigDir, GLOBAL_CONFIG_FILE2);
110442
110847
  const globalConfigExists = await context4.fs.exists(globalConfigPath);
110443
110848
  let misplacedKeys = [];
110444
110849
  if (globalConfigExists) {
@@ -110451,20 +110856,20 @@ function registerInitCommand(program2, context4, options = {}) {
110451
110856
  const configRoot = bundledConfigRoot();
110452
110857
  if (configRoot !== null && !minimal) {
110453
110858
  for (const relPath of listBundledProjectSeedFiles()) {
110454
- const sourcePath = join35(configRoot, relPath);
110859
+ const sourcePath = join37(configRoot, relPath);
110455
110860
  if (!await context4.fs.exists(sourcePath))
110456
110861
  continue;
110457
- const targetPath = join35(context4.cwd, CLI_CONFIG.configDir, relPath);
110458
- await context4.fs.ensureDir(join35(targetPath, ".."));
110862
+ const targetPath = join37(context4.cwd, CLI_CONFIG.configDir, relPath);
110863
+ await context4.fs.ensureDir(join37(targetPath, ".."));
110459
110864
  await writeIfNew(context4, targetPath, await context4.fs.readFile(sourcePath), false, result);
110460
110865
  }
110461
110866
  for (const entry of SCAFFOLD_MANIFEST) {
110462
- const sourcePath = join35(configRoot, entry.source);
110867
+ const sourcePath = join37(configRoot, entry.source);
110463
110868
  if (!await context4.fs.exists(sourcePath))
110464
110869
  continue;
110465
- const baseDir = entry.root === true ? context4.cwd : join35(context4.cwd, CLI_CONFIG.configDir);
110466
- const targetPath = join35(baseDir, entry.target);
110467
- await context4.fs.ensureDir(join35(targetPath, ".."));
110870
+ const baseDir = entry.root === true ? context4.cwd : join37(context4.cwd, CLI_CONFIG.configDir);
110871
+ const targetPath = join37(baseDir, entry.target);
110872
+ await context4.fs.ensureDir(join37(targetPath, ".."));
110468
110873
  const entryForce = false;
110469
110874
  let body = await context4.fs.readFile(sourcePath);
110470
110875
  if (entry.target === "AGENTS.md") {
@@ -110481,7 +110886,7 @@ function registerInitCommand(program2, context4, options = {}) {
110481
110886
  const backupPath = `${globalConfigPath}.bak-${new Date().toISOString().replace(/[:.]/g, "-")}`;
110482
110887
  await context4.fs.writeFile(backupPath, await context4.fs.readFile(globalConfigPath));
110483
110888
  const bundledRoot = bundledConfigRoot();
110484
- const examplePath = bundledRoot !== null ? join35(bundledRoot, GLOBAL_CONFIG_EXAMPLE) : null;
110889
+ const examplePath = bundledRoot !== null ? join37(bundledRoot, GLOBAL_CONFIG_EXAMPLE) : null;
110485
110890
  if (examplePath !== null && await context4.fs.exists(examplePath)) {
110486
110891
  await context4.fs.writeFile(globalConfigPath, await context4.fs.readFile(examplePath));
110487
110892
  adoptedGlobal = true;
@@ -110551,13 +110956,13 @@ function registerInitCommand(program2, context4, options = {}) {
110551
110956
  ].join(`
110552
110957
  `)}
110553
110958
  `;
110554
- await context4.fs.ensureDir(join35(context4.cwd, CLI_CONFIG.configDir));
110959
+ await context4.fs.ensureDir(join37(context4.cwd, CLI_CONFIG.configDir));
110555
110960
  await context4.fs.writeFile(configPath, configYaml);
110556
110961
  result.created.push(configPath);
110557
- const agentsDir = join35(context4.cwd, CLI_CONFIG.configDir, "agents");
110962
+ const agentsDir = join37(context4.cwd, CLI_CONFIG.configDir, "agents");
110558
110963
  await context4.fs.ensureDir(agentsDir);
110559
- await writeIfNew(context4, join35(agentsDir, ".gitkeep"), "", force, result);
110560
- const gitignorePath = join35(context4.cwd, ".gitignore");
110964
+ await writeIfNew(context4, join37(agentsDir, ".gitkeep"), "", force, result);
110965
+ const gitignorePath = join37(context4.cwd, ".gitignore");
110561
110966
  const contextEntry = ".spur/context/";
110562
110967
  if (await context4.fs.exists(gitignorePath)) {
110563
110968
  const existing = await context4.fs.readFile(gitignorePath);
@@ -110577,20 +110982,20 @@ ${contextEntry}
110577
110982
  const configRoot = bundledConfigRoot();
110578
110983
  if (configRoot !== null) {
110579
110984
  for (const relPath of listBundledProjectSeedFiles()) {
110580
- const sourcePath = join35(configRoot, relPath);
110985
+ const sourcePath = join37(configRoot, relPath);
110581
110986
  if (!await context4.fs.exists(sourcePath))
110582
110987
  continue;
110583
- const targetPath = join35(context4.cwd, CLI_CONFIG.configDir, relPath);
110584
- await context4.fs.ensureDir(join35(targetPath, ".."));
110988
+ const targetPath = join37(context4.cwd, CLI_CONFIG.configDir, relPath);
110989
+ await context4.fs.ensureDir(join37(targetPath, ".."));
110585
110990
  await writeIfNew(context4, targetPath, await context4.fs.readFile(sourcePath), force, result);
110586
110991
  }
110587
110992
  for (const entry of SCAFFOLD_MANIFEST) {
110588
- const sourcePath = join35(configRoot, entry.source);
110993
+ const sourcePath = join37(configRoot, entry.source);
110589
110994
  if (!await context4.fs.exists(sourcePath))
110590
110995
  continue;
110591
- const baseDir = entry.root === true ? context4.cwd : join35(context4.cwd, CLI_CONFIG.configDir);
110592
- const targetPath = join35(baseDir, entry.target);
110593
- await context4.fs.ensureDir(join35(targetPath, ".."));
110996
+ const baseDir = entry.root === true ? context4.cwd : join37(context4.cwd, CLI_CONFIG.configDir);
110997
+ const targetPath = join37(baseDir, entry.target);
110998
+ await context4.fs.ensureDir(join37(targetPath, ".."));
110594
110999
  const entryForce = entry.preserve === true ? false : force;
110595
111000
  let body = await context4.fs.readFile(sourcePath);
110596
111001
  if (entry.target === "AGENTS.md") {
@@ -110603,7 +111008,7 @@ ${contextEntry}
110603
111008
  }
110604
111009
  }
110605
111010
  }
110606
- const agentsMdPath = join35(context4.cwd, "AGENTS.md");
111011
+ const agentsMdPath = join37(context4.cwd, "AGENTS.md");
110607
111012
  if (await context4.fs.exists(agentsMdPath)) {
110608
111013
  const existing = await context4.fs.readFile(agentsMdPath);
110609
111014
  if (!existing.includes(INDEXED_CONTEXT_MARKER)) {
@@ -110644,11 +111049,11 @@ ${contextEntry}
110644
111049
  // src/commands/maintain.ts
110645
111050
  init_src();
110646
111051
  init_src2();
110647
- import { join as join36 } from "path";
111052
+ import { join as join38 } from "path";
110648
111053
  function registerMaintainCommand(program2, context4, options = {}) {
110649
111054
  program2.command("maintain", { hidden: options.hidden === true }).summary("run database maintenance (optimize, WAL checkpoint truncation, optional VACUUM)").description("Run database maintenance: PRAGMA optimize, WAL checkpoint truncation; optionally VACUUM compaction.").option("--vacuum", "Run VACUUM defragmentation and page compaction", false).option(...SHARED_OPTIONS.jsonSupported).option(...SHARED_OPTIONS.jsonEnvelope).action(async (options2) => {
110650
111055
  const db2 = await context4.getDb();
110651
- const dbPath = context4.env.DATABASE_URL ?? join36(context4.cwd, DEFAULT_DATABASE_URL);
111056
+ const dbPath = context4.env.DATABASE_URL ?? join38(context4.cwd, DEFAULT_DATABASE_URL);
110652
111057
  const result = await maintainDatabase(db2, {
110653
111058
  vacuum: options2.vacuum === true,
110654
111059
  dbPath: dbPath.startsWith(":memory:") ? undefined : dbPath
@@ -110971,15 +111376,15 @@ async function runMessageWatch(svc, output2, options, runtime = {}) {
110971
111376
  }
110972
111377
  }
110973
111378
  function defaultSleep(ms, signal) {
110974
- return new Promise((resolve18) => {
111379
+ return new Promise((resolve19) => {
110975
111380
  if (signal?.aborted) {
110976
- resolve18();
111381
+ resolve19();
110977
111382
  return;
110978
111383
  }
110979
- const timer = setTimeout(resolve18, ms);
111384
+ const timer = setTimeout(resolve19, ms);
110980
111385
  signal?.addEventListener("abort", () => {
110981
111386
  clearTimeout(timer);
110982
- resolve18();
111387
+ resolve19();
110983
111388
  }, { once: true });
110984
111389
  });
110985
111390
  }
@@ -111006,15 +111411,15 @@ function parseTimeout2(raw) {
111006
111411
  return n3;
111007
111412
  }
111008
111413
  function sendSleep(ms, signal) {
111009
- return new Promise((resolve18) => {
111414
+ return new Promise((resolve19) => {
111010
111415
  if (signal?.aborted) {
111011
- resolve18();
111416
+ resolve19();
111012
111417
  return;
111013
111418
  }
111014
- const timer = setTimeout(resolve18, ms);
111419
+ const timer = setTimeout(resolve19, ms);
111015
111420
  signal?.addEventListener("abort", () => {
111016
111421
  clearTimeout(timer);
111017
- resolve18();
111422
+ resolve19();
111018
111423
  }, { once: true });
111019
111424
  });
111020
111425
  }
@@ -111072,10 +111477,10 @@ async function waitForPendingDrain(agentService, teamService, pin, timeoutMs, si
111072
111477
 
111073
111478
  // src/commands/migrate.ts
111074
111479
  init_src2();
111075
- import { join as join37 } from "path";
111480
+ import { join as join39 } from "path";
111076
111481
  function registerMigrateCommand(program2, context4, options = {}) {
111077
111482
  program2.command("migrate", { hidden: options.hidden === true }).summary("apply CLI-owned schema migrations").option(...SHARED_OPTIONS.json).option(...SHARED_OPTIONS.jsonEnvelope).action(async (options2) => {
111078
- const migrations = await loadSqlMigrations(join37(context4.cwd, "drizzle")).catch(() => {
111483
+ const migrations = await loadSqlMigrations(join39(context4.cwd, "drizzle")).catch(() => {
111079
111484
  return;
111080
111485
  });
111081
111486
  const applied = await applyCliMigrations(await context4.getDb(), migrations);
@@ -111088,16 +111493,16 @@ function registerMigrateCommand(program2, context4, options = {}) {
111088
111493
  init_src2();
111089
111494
  init_dist5();
111090
111495
  await init_src3();
111091
- import { basename as basename12, dirname as dirname24, join as join38, resolve as resolve18 } from "path";
111496
+ import { basename as basename13, dirname as dirname25, join as join40, resolve as resolve19 } from "path";
111092
111497
  function registerProjectsCommand(program2, context4) {
111093
111498
  const projectsCmd = program2.command("projects").summary("manage the Spur multi-project registry");
111094
111499
  projectsCmd.command("add").argument("<path>", "Project root directory path").option(...SHARED_OPTIONS.nameProjectDisplay).option(...SHARED_OPTIONS.jsonProjectsResponse).option(...SHARED_OPTIONS.jsonEnvelope).action(async (pathArg, options) => {
111095
111500
  try {
111096
- const absolutePath = resolve18(context4.cwd, pathArg);
111501
+ const absolutePath = resolve19(context4.cwd, pathArg);
111097
111502
  if (!await context4.fs.exists(absolutePath)) {
111098
111503
  throw new Error(`Directory does not exist: ${absolutePath}`);
111099
111504
  }
111100
- const name = options.name ?? basename12(absolutePath);
111505
+ const name = options.name ?? basename13(absolutePath);
111101
111506
  const registry3 = new ProjectRegistry;
111102
111507
  const entry = await registry3.upsert({ path: absolutePath, name, port: 0 });
111103
111508
  if (options.json) {
@@ -111146,8 +111551,8 @@ function registerProjectsCommand(program2, context4) {
111146
111551
  running: p.port > 0 ? await isPortLive(p.port) : false
111147
111552
  })));
111148
111553
  const openProjectDb = async (projectPath) => {
111149
- const url2 = join38(projectPath, ".spur", "spur.db");
111150
- await context4.fs.ensureDir(dirname24(url2));
111554
+ const url2 = join40(projectPath, ".spur", "spur.db");
111555
+ await context4.fs.ensureDir(dirname25(url2));
111151
111556
  return createMigratedDb({ url: url2 });
111152
111557
  };
111153
111558
  const fleets = options.fleet ? await Promise.all(projects3.map(async (p) => {
@@ -111589,7 +111994,7 @@ function formatTraceDetail(detail) {
111589
111994
  // src/commands/serve.ts
111590
111995
  init_src();
111591
111996
  import { statSync as statSync7 } from "fs";
111592
- import { join as join42, resolve as resolve19 } from "path";
111997
+ import { join as join44, resolve as resolve20 } from "path";
111593
111998
 
111594
111999
  // ../server/src/index.ts
111595
112000
  init_src();
@@ -111599,11 +112004,11 @@ init_src();
111599
112004
  init_loader();
111600
112005
  init_src2();
111601
112006
  await init_src3();
111602
- import { basename as basename14, dirname as dirname26, isAbsolute as isAbsolute8, join as join41 } from "path";
112007
+ import { basename as basename15, dirname as dirname27, isAbsolute as isAbsolute8, join as join43 } from "path";
111603
112008
  init_dist5();
111604
112009
 
111605
112010
  // ../server/src/bootstrap.ts
111606
- import { join as join39 } from "path";
112011
+ import { join as join41 } from "path";
111607
112012
 
111608
112013
  // ../../node_modules/.bun/radash@12.1.1/node_modules/radash/dist/esm/async.mjs
111609
112014
  var guard = (func, shouldGuard) => {
@@ -111876,8 +112281,8 @@ class EventPublisher {
111876
112281
  if (bufferedEvents.length > 0) {
111877
112282
  return { done: false, value: bufferedEvents.shift() };
111878
112283
  }
111879
- return new Promise((resolve19, reject) => {
111880
- pullResolvers.push([resolve19, reject]);
112284
+ return new Promise((resolve20, reject) => {
112285
+ pullResolvers.push([resolve20, reject]);
111881
112286
  });
111882
112287
  }, async () => {
111883
112288
  unsubscribe();
@@ -116997,6 +117402,55 @@ function mountMiddleware(app, appRt) {
116997
117402
  }
116998
117403
  }
116999
117404
 
117405
+ // ../server/src/modules/commands/index.ts
117406
+ init_src();
117407
+ await init_src3();
117408
+ var commandsModule = {
117409
+ name: "commands",
117410
+ mount(app, ctx) {
117411
+ const projectRoot = ctx?.cwd ?? process.cwd();
117412
+ const filePath = getSlashCommandsFilePath();
117413
+ const service = new SlashCommandsService({ filePath, projectRoot });
117414
+ let cachedCommands = [];
117415
+ try {
117416
+ cachedCommands = service.getCommands();
117417
+ } catch {}
117418
+ const handleList = (c3) => {
117419
+ const reload = c3.req.query("reload") === "true";
117420
+ if (reload || cachedCommands.length === 0) {
117421
+ try {
117422
+ cachedCommands = service.getCommands(reload);
117423
+ } catch {}
117424
+ }
117425
+ return c3.json({
117426
+ commands: cachedCommands,
117427
+ count: cachedCommands.length,
117428
+ filePath: service.getFilePath()
117429
+ });
117430
+ };
117431
+ app.get("/api/commands", handleList);
117432
+ app.get("/api/agent/commands", handleList);
117433
+ app.post("/api/commands/generate", (c3) => {
117434
+ try {
117435
+ const result = service.generate();
117436
+ cachedCommands = result.commands;
117437
+ return c3.json({
117438
+ ok: true,
117439
+ count: result.count,
117440
+ filePath: result.path,
117441
+ commands: result.commands
117442
+ });
117443
+ } catch (err) {
117444
+ return c3.json({
117445
+ ok: false,
117446
+ error: err instanceof Error ? err.message : String(err),
117447
+ filePath: service.getFilePath()
117448
+ }, 500);
117449
+ }
117450
+ });
117451
+ }
117452
+ };
117453
+
117000
117454
  // ../server/src/modules/sse/stream-helpers.ts
117001
117455
  function sendSseKeepalive(closed, controller, encoder) {
117002
117456
  if (closed.current)
@@ -118305,7 +118759,7 @@ var featureModule = {
118305
118759
  // ../server/src/modules/health/index.ts
118306
118760
  init_src2();
118307
118761
  await init_src3();
118308
- import { basename as basename13 } from "path";
118762
+ import { basename as basename14 } from "path";
118309
118763
  var startedAt = Date.now();
118310
118764
  var OPERATOR_AGENT_ID = "board-operator";
118311
118765
  var healthModule = {
@@ -118332,7 +118786,7 @@ var healthModule = {
118332
118786
  return c3.json({ status: "error", db: "unreachable" }, 503);
118333
118787
  });
118334
118788
  app.get("/api/project", (c3) => {
118335
- return c3.json({ name: ctx ? basename13(ctx.cwd) : null, path: ctx ? normalizeProjectPath(ctx.cwd) : null });
118789
+ return c3.json({ name: ctx ? basename14(ctx.cwd) : null, path: ctx ? normalizeProjectPath(ctx.cwd) : null });
118336
118790
  });
118337
118791
  app.get("/api/project/fleet", async (c3) => {
118338
118792
  if (!ctx) {
@@ -119412,7 +119866,8 @@ var builtins = [
119412
119866
  processesModule,
119413
119867
  observabilityModule,
119414
119868
  runsModule,
119415
- historyModule
119869
+ historyModule,
119870
+ commandsModule
119416
119871
  ];
119417
119872
  function registerModules(app, ctx, modules = builtins) {
119418
119873
  for (const mod of modules) {
@@ -121430,7 +121885,7 @@ function createApp(appRt, opts) {
121430
121885
  app.use("*", async (c3, next) => {
121431
121886
  const pathname = c3.req.path === "/" ? "/index.html" : c3.req.path;
121432
121887
  try {
121433
- const file2 = Bun.file(join39(webDistPath, pathname));
121888
+ const file2 = Bun.file(join41(webDistPath, pathname));
121434
121889
  if (await file2.exists()) {
121435
121890
  const headers = new Headers({ "content-type": file2.type });
121436
121891
  return new Response(file2.stream(), { headers });
@@ -121443,7 +121898,7 @@ function createApp(appRt, opts) {
121443
121898
  return c3.json({ error: "Not Found" }, 404);
121444
121899
  }
121445
121900
  try {
121446
- const indexFile = Bun.file(join39(webDistPath, "index.html"));
121901
+ const indexFile = Bun.file(join41(webDistPath, "index.html"));
121447
121902
  if (await indexFile.exists()) {
121448
121903
  return new Response(indexFile.stream(), {
121449
121904
  headers: { "content-type": "text/html; charset=utf-8" }
@@ -121465,7 +121920,7 @@ init_loader();
121465
121920
  init_src2();
121466
121921
  init_dist5();
121467
121922
  await init_src3();
121468
- import { dirname as dirname25, join as join40 } from "path";
121923
+ import { dirname as dirname26, join as join42 } from "path";
121469
121924
  var NOOP_OUTPUT = { write: (_s) => {}, error: (_s) => {} };
121470
121925
 
121471
121926
  class LazyPlanningEventEmitter {
@@ -121501,7 +121956,7 @@ class NotConfiguredError extends Error {
121501
121956
  function createServerContext(appRt, options) {
121502
121957
  const cwd = options.cwd;
121503
121958
  const fs3 = options.fs;
121504
- const dbUrl = options.dbUrl ?? join40(cwd, DEFAULT_DATABASE_URL);
121959
+ const dbUrl = options.dbUrl ?? join42(cwd, DEFAULT_DATABASE_URL);
121505
121960
  const eventsBus = options.eventsBus ?? appRt.events;
121506
121961
  const jobQueueEnabled = options.jobQueueEnabled ?? false;
121507
121962
  const eventProjectContext = systemEventProjectContext(cwd);
@@ -121538,7 +121993,7 @@ function createServerContext(appRt, options) {
121538
121993
  if (!dbPromise) {
121539
121994
  const created = (async () => {
121540
121995
  if (dbUrl !== IN_MEMORY_DATABASE_URL) {
121541
- await fs3.ensureDir(dirname25(dbUrl));
121996
+ await fs3.ensureDir(dirname26(dbUrl));
121542
121997
  }
121543
121998
  return createMigratedDbViaRuntime({ url: dbUrl });
121544
121999
  })();
@@ -121806,7 +122261,7 @@ async function loadServerSectionMatrix(projectRoot) {
121806
122261
  }
121807
122262
  const root = bundledConfigRoot();
121808
122263
  if (root !== null) {
121809
- const matrixPath = join41(root, "tasks", "section-matrix.yaml");
122264
+ const matrixPath = join43(root, "tasks", "section-matrix.yaml");
121810
122265
  if (await nodeFs.exists(matrixPath)) {
121811
122266
  return await loadStructuredSpurConfig(matrixPath, {
121812
122267
  validateJsonSchema: false
@@ -121815,7 +122270,7 @@ async function loadServerSectionMatrix(projectRoot) {
121815
122270
  }
121816
122271
  throw new Error(`no canonical section-matrix found for task creation (F92 R1); tried:
121817
122272
  ` + ` - ${localPath}
121818
- ` + (root !== null ? ` - ${join41(root, "tasks", "section-matrix.yaml")}
122273
+ ` + (root !== null ? ` - ${join43(root, "tasks", "section-matrix.yaml")}
121819
122274
  ` : "") + "copy/generate section-matrix.yaml from the canonical build-time matrix asset (repo `config` `tasks` tree) into one of those paths");
121820
122275
  }
121821
122276
  var SYSTEM_EVENTS_PRUNE_JOB = "system-events-prune";
@@ -122050,15 +122505,15 @@ async function handleFeatureActionJob(ctx, env, payload) {
122050
122505
  await runFeatureActionJob(ctx, env, payload);
122051
122506
  }
122052
122507
  async function resolveWebDistPath(configuredPath, projectRoot = process.cwd()) {
122053
- const candidates = configuredPath && configuredPath.trim() !== "" ? [isAbsolute8(configuredPath) ? configuredPath : join41(projectRoot, configuredPath)] : [
122054
- join41(projectRoot, "dist/web"),
122055
- join41(import.meta.dir, "web"),
122056
- join41(dirname26(process.execPath), "web"),
122057
- join41(dirname26(process.execPath), "../web"),
122058
- join41(import.meta.dir, "../../../dist/web")
122508
+ const candidates = configuredPath && configuredPath.trim() !== "" ? [isAbsolute8(configuredPath) ? configuredPath : join43(projectRoot, configuredPath)] : [
122509
+ join43(projectRoot, "dist/web"),
122510
+ join43(import.meta.dir, "web"),
122511
+ join43(dirname27(process.execPath), "web"),
122512
+ join43(dirname27(process.execPath), "../web"),
122513
+ join43(import.meta.dir, "../../../dist/web")
122059
122514
  ];
122060
122515
  for (const candidate of candidates) {
122061
- if (await Bun.file(join41(candidate, "index.html")).exists()) {
122516
+ if (await Bun.file(join43(candidate, "index.html")).exists()) {
122062
122517
  return candidate;
122063
122518
  }
122064
122519
  }
@@ -122075,7 +122530,7 @@ async function startServer(options, deps = defaultDeps) {
122075
122530
  async start(appRt) {
122076
122531
  const fs3 = deps.createNodeFileSystem(projectRoot);
122077
122532
  if (options.dbUrl && options.dbUrl !== IN_MEMORY_DATABASE_URL) {
122078
- await fs3.ensureDir(dirname26(options.dbUrl));
122533
+ await fs3.ensureDir(dirname27(options.dbUrl));
122079
122534
  }
122080
122535
  const scheduler3 = appRt.config.scheduler.enabled ? appRt.scheduler : undefined;
122081
122536
  const webDistPath = await resolveWebDistPath(options.webDistPath, projectRoot);
@@ -122254,7 +122709,7 @@ async function startServer(options, deps = defaultDeps) {
122254
122709
  });
122255
122710
  const projectRegistry = new ProjectRegistry;
122256
122711
  const projectCwd = projectRoot;
122257
- const projectName = basename14(projectCwd);
122712
+ const projectName = basename15(projectCwd);
122258
122713
  try {
122259
122714
  const existingProject = await projectRegistry.getByPath(projectCwd);
122260
122715
  await projectRegistry.upsert({
@@ -122374,10 +122829,10 @@ var SQLITE_BUSY_MESSAGE_CONSTANTS = Object.freeze({
122374
122829
 
122375
122830
  // src/commands/serve.ts
122376
122831
  function resolveServeDbUrl(cwd, env, configuredUrl) {
122377
- return env.DATABASE_URL === undefined ? join42(cwd, DEFAULT_DATABASE_URL) : configuredUrl;
122832
+ return env.DATABASE_URL === undefined ? join44(cwd, DEFAULT_DATABASE_URL) : configuredUrl;
122378
122833
  }
122379
122834
  function resolveServeCwd(cwd) {
122380
- const resolved = resolve19(cwd);
122835
+ const resolved = resolve20(cwd);
122381
122836
  let isDirectory = false;
122382
122837
  try {
122383
122838
  isDirectory = statSync7(resolved).isDirectory();
@@ -122430,7 +122885,7 @@ function registerServeCommand(program2, context4, options = {}) {
122430
122885
  }
122431
122886
 
122432
122887
  // src/commands/status.ts
122433
- import { join as join43 } from "path";
122888
+ import { join as join45 } from "path";
122434
122889
 
122435
122890
  // src/git-context.ts
122436
122891
  init_dist5();
@@ -122478,8 +122933,8 @@ function registerStatusCommand(program2, context4, options = {}) {
122478
122933
  }
122479
122934
  async function runStatusCore(path9, options, context4) {
122480
122935
  const [packageJsonExists, spurConfigExists, git3, agentSpecs] = await Promise.all([
122481
- context4.fs.exists(join43(context4.cwd, "package.json")),
122482
- context4.fs.exists(join43(context4.cwd, ".spur", "config.yaml")),
122936
+ context4.fs.exists(join45(context4.cwd, "package.json")),
122937
+ context4.fs.exists(join45(context4.cwd, ".spur", "config.yaml")),
122483
122938
  gitContext(context4.cwd),
122484
122939
  listAgentSpecIds(context4)
122485
122940
  ]);
@@ -122507,14 +122962,14 @@ async function runStatusCore(path9, options, context4) {
122507
122962
  return status.ok ? 0 : 1;
122508
122963
  }
122509
122964
  async function listAgentSpecIds(context4) {
122510
- const dir = join43(context4.cwd, ".spur", "agents");
122965
+ const dir = join45(context4.cwd, ".spur", "agents");
122511
122966
  if (!await context4.fs.exists(dir))
122512
122967
  return [];
122513
122968
  const entries = await context4.fs.readDir(dir);
122514
122969
  return entries.filter((entry) => entry.endsWith(".yaml") || entry.endsWith(".yml")).map((entry) => entry.replace(/\.ya?ml$/, "")).sort();
122515
122970
  }
122516
122971
  async function readTargetStatus(context4, targetPath) {
122517
- const resolved = join43(context4.cwd, targetPath);
122972
+ const resolved = join45(context4.cwd, targetPath);
122518
122973
  const stat2 = await context4.fs.stat(resolved);
122519
122974
  if (stat2 === null)
122520
122975
  throw new CommandError(`status failed: path does not exist at ${resolved}`);
@@ -122527,7 +122982,7 @@ init_dist7();
122527
122982
  init_dist5();
122528
122983
  await init_src3();
122529
122984
  import { closeSync as closeSync5, fstatSync as fstatSync3, openSync as openSync5, readSync as readSync3 } from "fs";
122530
- import { join as join44 } from "path";
122985
+ import { join as join46 } from "path";
122531
122986
  import { createInterface } from "readline";
122532
122987
  import { setTimeout as sleep5 } from "timers/promises";
122533
122988
 
@@ -122706,9 +123161,9 @@ async function writeWorkflowPlanArtifact(cwd, runId, resolved, secretValues) {
122706
123161
  }))
122707
123162
  });
122708
123163
  const { mkdir, writeFile: writeFile2 } = await import("fs/promises");
122709
- const artifactsDir = join44(cwd, ".spur", "run");
123164
+ const artifactsDir = join46(cwd, ".spur", "run");
122710
123165
  await mkdir(artifactsDir, { recursive: true });
122711
- const artifactPath = join44(artifactsDir, `${runId}-workflow-plan.json`);
123166
+ const artifactPath = join46(artifactsDir, `${runId}-workflow-plan.json`);
122712
123167
  await writeFile2(artifactPath, payload);
122713
123168
  return artifactPath;
122714
123169
  }
@@ -122993,7 +123448,7 @@ Monitor with: spur workflow trace ${runId2} --follow`);
122993
123448
  }
122994
123449
  const runLog = options.log === false ? undefined : new WorkflowRunLogSink({
122995
123450
  bus,
122996
- dir: join44(context4.cwd, ".spur", "run"),
123451
+ dir: join46(context4.cwd, ".spur", "run"),
122997
123452
  runId,
122998
123453
  ...planPreview !== undefined ? { planPreview } : {},
122999
123454
  ...resolveOutputLogConfig(context4.spurConfig ?? null)
@@ -123531,7 +123986,7 @@ function readRunLogChunk(logPath, offset) {
123531
123986
  }
123532
123987
  }
123533
123988
  async function followRunLog(service, runId, dir, pollMs, write, wait = (ms) => sleep5(ms)) {
123534
- const logPath = join44(dir, ".spur", "run", `${runId}.log`);
123989
+ const logPath = join46(dir, ".spur", "run", `${runId}.log`);
123535
123990
  let offset = 0;
123536
123991
  let everRead = false;
123537
123992
  while (true) {
@@ -123594,7 +124049,7 @@ init_src();
123594
124049
  init_src2();
123595
124050
  init_dist5();
123596
124051
  await init_src3();
123597
- import { dirname as dirname27, join as join45, resolve as resolve20 } from "path";
124052
+ import { dirname as dirname28, join as join47, resolve as resolve21 } from "path";
123598
124053
  import { isatty as isatty4 } from "tty";
123599
124054
 
123600
124055
  // ../../node_modules/.bun/@clack+core@1.4.1/node_modules/@clack/core/dist/index.mjs
@@ -124978,7 +125433,7 @@ class DefaultHitlResponder {
124978
125433
  // src/context.ts
124979
125434
  await init_src3();
124980
125435
  function createCliContext(options) {
124981
- const cwd = resolve20(options.cwd ?? process.cwd());
125436
+ const cwd = resolve21(options.cwd ?? process.cwd());
124982
125437
  const env = options.env ?? process.env;
124983
125438
  const fs3 = createNodeFileSystem3(cwd);
124984
125439
  const agentConfig = options.agentConfig ?? options.spurConfig?.agent;
@@ -125031,10 +125486,10 @@ function createCliContext(options) {
125031
125486
  function noopSetExitCode(_code) {}
125032
125487
  async function createMigratedDbAdapter(cwd = process.cwd(), env = process.env, dbUrl) {
125033
125488
  const config4 = buildConfigFromEnv(env);
125034
- const configuredUrl = env.DATABASE_URL === undefined ? join45(cwd, DEFAULT_DATABASE_URL) : config4.database.url;
125489
+ const configuredUrl = env.DATABASE_URL === undefined ? join47(cwd, DEFAULT_DATABASE_URL) : config4.database.url;
125035
125490
  const url2 = dbUrl ?? configuredUrl;
125036
125491
  if (url2 !== IN_MEMORY_DATABASE_URL) {
125037
- await createNodeFileSystem3().ensureDir(dirname27(url2));
125492
+ await createNodeFileSystem3().ensureDir(dirname28(url2));
125038
125493
  }
125039
125494
  return createMigratedDb({ url: url2 });
125040
125495
  }