@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.
- package/.claude-plugin/marketplace.json +1 -1
- package/config/rules/strict/runtime-boundaries.yaml +1 -0
- package/package.json +1 -1
- package/plugins/sp/lib/idea-handoff.generated.mjs +1 -1
- package/plugins/sp/plugin.json +1 -1
- package/plugins/sp/skills/parallel-execution/references/dispatch-surface.md +37 -0
- package/plugins/sp/skills/parallel-execution/references/fan-out-patterns.md +55 -1
- package/plugins/sp/skills/spec-decomposition/references/decomposition.md +12 -0
- package/plugins/sp/skills/spur-dev/references/cross-cutting.md +4 -1
- package/plugins/sp/skills/spur-dev/references/inline-pipeline-driver.md +60 -4
- package/schemas/task-batch.schema.json +5 -0
- package/spur.js +780 -325
- package/web/_astro/{BoardApp.D8bM9pKL.js → BoardApp.D4mBUGLT.js} +64 -64
- package/web/_astro/BoardApp.DFPYpI5O.js +1 -0
- package/web/_astro/{TaskDetail.BPRqgVUE.js → TaskDetail.DhCWaOPR.js} +1 -1
- package/web/_astro/{arc.BPrPES3z.js → arc.D3X0nfq-.js} +1 -1
- package/web/_astro/{architectureDiagram-3BPJPVTR.qX_7q02P.js → architectureDiagram-3BPJPVTR.BQDoiGme.js} +1 -1
- package/web/_astro/{blockDiagram-GPEHLZMM.CUZfj5V7.js → blockDiagram-GPEHLZMM.BjHekBbM.js} +1 -1
- package/web/_astro/{c4Diagram-AAUBKEIU.CTaOr8hH.js → c4Diagram-AAUBKEIU.BvHt171l.js} +1 -1
- package/web/_astro/channel.BlQwxyoI.js +1 -0
- package/web/_astro/{chunk-2J33WTMH.Dt-9wf3h.js → chunk-2J33WTMH.CwxGXlDR.js} +1 -1
- package/web/_astro/{chunk-4BX2VUAB.CTC2sdoN.js → chunk-4BX2VUAB.Dia1YtwU.js} +1 -1
- package/web/_astro/{chunk-55IACEB6.DQcxt2_g.js → chunk-55IACEB6.Oz9epCXa.js} +1 -1
- package/web/_astro/{chunk-727SXJPM.DXFPSn-a.js → chunk-727SXJPM.DKFYJjYJ.js} +1 -1
- package/web/_astro/{chunk-AQP2D5EJ.BCx3U4bT.js → chunk-AQP2D5EJ.AD7w5oVz.js} +1 -1
- package/web/_astro/{chunk-FMBD7UC4.DL2tJkdO.js → chunk-FMBD7UC4.D0OqTj52.js} +1 -1
- package/web/_astro/{chunk-ND2GUHAM.DZyflMro.js → chunk-ND2GUHAM.CU5ppR7j.js} +1 -1
- package/web/_astro/{chunk-QZHKN3VN.CUI2mT09.js → chunk-QZHKN3VN.Bu1rFztw.js} +1 -1
- package/web/_astro/{classDiagram-4FO5ZUOK.g4rX4Fr1.js → classDiagram-4FO5ZUOK.C0Pgm5yE.js} +1 -1
- package/web/_astro/{classDiagram-v2-Q7XG4LA2.g4rX4Fr1.js → classDiagram-v2-Q7XG4LA2.C0Pgm5yE.js} +1 -1
- package/web/_astro/{cose-bilkent-S5V4N54A.CzWJLqp0.js → cose-bilkent-S5V4N54A.C0ecLb1e.js} +1 -1
- package/web/_astro/{cynefin-OW5HDTMX.WgsvQeCR.js → cynefin-OW5HDTMX.CpStVmhO.js} +1 -1
- package/web/_astro/{dagre-BM42HDAG.Dzv6ngql.js → dagre-BM42HDAG.BPWN3W9f.js} +1 -1
- package/web/_astro/{diagram-2AECGRRQ.CpJ4a9rU.js → diagram-2AECGRRQ.DnXbEot4.js} +1 -1
- package/web/_astro/{diagram-5GNKFQAL.CzPlF_dq.js → diagram-5GNKFQAL.BYJsgUiI.js} +1 -1
- package/web/_astro/{diagram-KO2AKTUF.TAkZNTcQ.js → diagram-KO2AKTUF.CU4Bqprx.js} +1 -1
- package/web/_astro/{diagram-LMA3HP47.uCjoKSag.js → diagram-LMA3HP47.BQLOANIu.js} +1 -1
- package/web/_astro/{diagram-OG6HWLK6.eMplIjoK.js → diagram-OG6HWLK6.Cn1UVhqj.js} +1 -1
- package/web/_astro/{erDiagram-TEJ5UH35.Bf7zoXGz.js → erDiagram-TEJ5UH35.C8FdZyvA.js} +1 -1
- package/web/_astro/{flowDiagram-I6XJVG4X.B_bHj3gN.js → flowDiagram-I6XJVG4X.QSZCR8Uo.js} +1 -1
- package/web/_astro/{ganttDiagram-6RSMTGT7.BasrHRMj.js → ganttDiagram-6RSMTGT7.O1Py31MY.js} +1 -1
- package/web/_astro/{gitGraphDiagram-PVQCEYII.C6iphq1x.js → gitGraphDiagram-PVQCEYII.DoeJRBfY.js} +1 -1
- package/web/_astro/index.TPF1FerP.css +1 -0
- package/web/_astro/{infoDiagram-5YYISTIA.HXmDMhW4.js → infoDiagram-5YYISTIA.9npLJecW.js} +1 -1
- package/web/_astro/{ishikawaDiagram-YF4QCWOH.BSmW8NiU.js → ishikawaDiagram-YF4QCWOH.DXanvOr3.js} +1 -1
- package/web/_astro/{journeyDiagram-JHISSGLW.DEQow5fo.js → journeyDiagram-JHISSGLW.DxbVjxAv.js} +1 -1
- package/web/_astro/{kanban-definition-UN3LZRKU.IVm9cTdc.js → kanban-definition-UN3LZRKU.BDk6_iq0.js} +1 -1
- package/web/_astro/{linear.CrsM73_9.js → linear.C9cCDjT3.js} +1 -1
- package/web/_astro/{mermaid.core.CfBeDJls.js → mermaid.core.CpHRe5nH.js} +4 -4
- package/web/_astro/{mindmap-definition-RKZ34NQL.C3j60Y-0.js → mindmap-definition-RKZ34NQL.D-6C85bn.js} +1 -1
- package/web/_astro/{pieDiagram-4H26LBE5.B-aCMeEA.js → pieDiagram-4H26LBE5.B3Oxodty.js} +1 -1
- package/web/_astro/{quadrantDiagram-W4KKPZXB.Cib965yq.js → quadrantDiagram-W4KKPZXB.QZ_9Hshu.js} +1 -1
- package/web/_astro/{requirementDiagram-4Y6WPE33.D61cS4O-.js → requirementDiagram-4Y6WPE33.BimvuK53.js} +1 -1
- package/web/_astro/{sankeyDiagram-5OEKKPKP.GKF2qVPy.js → sankeyDiagram-5OEKKPKP.D5Kkpx2C.js} +1 -1
- package/web/_astro/{sequenceDiagram-3UESZ5HK.DZnq8F2h.js → sequenceDiagram-3UESZ5HK.B4YR6fAE.js} +1 -1
- package/web/_astro/{stateDiagram-AJRCARHV.DXUFmdgM.js → stateDiagram-AJRCARHV.Bt2wkZok.js} +1 -1
- package/web/_astro/{stateDiagram-v2-BHNVJYJU.BtHmhLEz.js → stateDiagram-v2-BHNVJYJU.YZ4X7dfQ.js} +1 -1
- package/web/_astro/{timeline-definition-PNZ67QCA.Cy-WW2ln.js → timeline-definition-PNZ67QCA.DmiTBL8w.js} +1 -1
- package/web/_astro/{vennDiagram-CIIHVFJN.SLp5b9KI.js → vennDiagram-CIIHVFJN.KNJV40mf.js} +1 -1
- package/web/_astro/{wardleyDiagram-YWT4CUSO.Bww45mWV.js → wardleyDiagram-YWT4CUSO.BVAaKgWH.js} +1 -1
- package/web/_astro/{xychartDiagram-2RQKCTM6.DR4swI6a.js → xychartDiagram-2RQKCTM6.D5Jx7zB2.js} +1 -1
- package/web/index.html +2 -2
- package/web/_astro/BoardApp.D-WlxiN2.js +0 -1
- package/web/_astro/channel.DGZaFHZx.js +0 -1
- 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
|
|
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 =
|
|
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(
|
|
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 =
|
|
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
|
|
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 =
|
|
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 =
|
|
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
|
|
40061
|
-
import { dirname as dirname5, join as
|
|
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 =
|
|
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 =
|
|
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([
|
|
40201
|
+
const candidates = new Set([join5(projectRoot, SPUR_CONFIG_DIR, "fleet.json")]);
|
|
40173
40202
|
if (projectConfigPath !== undefined)
|
|
40174
|
-
candidates.add(
|
|
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 ??
|
|
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(
|
|
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 =
|
|
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
|
|
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(
|
|
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
|
|
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:
|
|
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 =
|
|
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 =
|
|
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
|
|
71011
|
+
import { dirname as dirname8, join as join9 } from "path";
|
|
70983
71012
|
function lockPathForEntity(folder, entityId) {
|
|
70984
|
-
return
|
|
71013
|
+
return join9(folder, `.${entityId}.lock`);
|
|
70985
71014
|
}
|
|
70986
71015
|
function createLockPath(folder) {
|
|
70987
|
-
return
|
|
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 =
|
|
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 =
|
|
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(
|
|
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
|
|
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 =
|
|
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 =
|
|
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
|
|
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 =
|
|
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
|
|
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 ??
|
|
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
|
|
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:
|
|
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
|
|
75673
|
-
import { dirname as dirname9, join as
|
|
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 =
|
|
75709
|
+
expanded = homedir6();
|
|
75679
75710
|
} else if (trimmed.startsWith("~/")) {
|
|
75680
|
-
expanded =
|
|
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
|
|
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 =
|
|
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 =
|
|
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
|
|
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 =
|
|
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) =>
|
|
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
|
|
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) =>
|
|
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
|
|
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
|
|
78459
|
+
return join16(dirname11(dirname11(tasksDir)), ".spur", "run");
|
|
78429
78460
|
}
|
|
78430
|
-
return
|
|
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 ?
|
|
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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
|
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 = [
|
|
80076
|
+
const candidates = [join18(projectRoot, ".spur", "tasks", "section-matrix.yaml")];
|
|
80046
80077
|
const bundledRoot = bundledConfigRoot();
|
|
80047
80078
|
if (bundledRoot !== null)
|
|
80048
|
-
candidates.push(
|
|
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(
|
|
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(
|
|
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,
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
|
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) =>
|
|
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
|
|
86901
|
-
import { dirname as dirname14, isAbsolute as isAbsolute3, join as
|
|
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 =
|
|
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 =
|
|
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(
|
|
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 ??
|
|
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 ?
|
|
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 =
|
|
87602
|
+
const dateDir = join20(base2, artifact.generatedAt.slice(0, 10));
|
|
87572
87603
|
const name = `analyze-${selectorDigest(artifact.selector)}`;
|
|
87573
|
-
return { artifactPath:
|
|
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 =
|
|
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 =
|
|
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(
|
|
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
|
|
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(
|
|
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,
|
|
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,
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
|
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 =
|
|
88383
|
+
sessionDir = join22(cwd, ".spur", "run", context4.runId, "agent-sessions", targetAgentDir);
|
|
88353
88384
|
}
|
|
88354
88385
|
} else {
|
|
88355
88386
|
if (!sessionDir) {
|
|
88356
|
-
sessionDir =
|
|
88387
|
+
sessionDir = join22(cwd, ".spur", "run", context4.runId, "agent-sessions", targetAgentDir);
|
|
88357
88388
|
}
|
|
88358
88389
|
}
|
|
88359
88390
|
if (freshSession) {
|
|
88360
|
-
sessionDir =
|
|
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 :
|
|
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: ${
|
|
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 :
|
|
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 :
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
88846
|
-
|
|
88847
|
-
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
89057
|
-
|
|
89058
|
-
|
|
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
|
|
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(
|
|
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 =
|
|
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(
|
|
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
|
|
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(
|
|
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
|
|
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 =
|
|
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
|
|
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 =
|
|
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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 :
|
|
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 =
|
|
92041
|
-
return await fileExists(
|
|
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 =
|
|
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
|
|
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 =
|
|
92299
|
-
mkdirSync8(
|
|
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
|
|
93252
|
-
import { delimiter, join as
|
|
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) :
|
|
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:
|
|
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(
|
|
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(
|
|
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:
|
|
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(
|
|
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 =
|
|
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 :
|
|
93805
|
-
const absolutePath =
|
|
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 =
|
|
93940
|
-
GLOBAL_RULES_DIR =
|
|
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
|
|
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(
|
|
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((
|
|
95047
|
+
const timeout = new Promise((resolve17) => {
|
|
94655
95048
|
setTimeout(() => {
|
|
94656
95049
|
timedOut = true;
|
|
94657
|
-
|
|
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((
|
|
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
|
|
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 =
|
|
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
|
|
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 =
|
|
95921
|
-
const featuresDir =
|
|
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
|
|
96233
|
-
const capturedWbs = /^(\d{4})_.+\.md$/.exec(
|
|
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
|
|
96706
|
-
import { join as
|
|
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 (!
|
|
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 ??
|
|
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 =
|
|
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
|
|
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 =
|
|
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 (!
|
|
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 (!
|
|
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
|
|
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 =
|
|
96987
|
-
const batchPath =
|
|
96988
|
-
const resultPath =
|
|
96989
|
-
const orderPath =
|
|
96990
|
-
const readyPath =
|
|
96991
|
-
const reportPath =
|
|
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
|
|
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 =
|
|
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(
|
|
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
|
|
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
|
|
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
|
|
107400
|
+
import { basename as basename12 } from "path";
|
|
106996
107401
|
function resolveSpurBinFrom(launch) {
|
|
106997
|
-
const runtime =
|
|
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 ??
|
|
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:
|
|
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 =
|
|
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 =
|
|
108069
|
-
if (
|
|
108070
|
-
bodies = extractTemplateBodies(
|
|
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 =
|
|
108075
|
-
if (
|
|
108076
|
-
bodies = extractTemplateBodies(
|
|
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 =
|
|
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 ? ` - ${
|
|
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((
|
|
108926
|
+
return new Promise((resolve18) => {
|
|
108522
108927
|
if (signal?.aborted) {
|
|
108523
|
-
|
|
108928
|
+
resolve18();
|
|
108524
108929
|
return;
|
|
108525
108930
|
}
|
|
108526
|
-
const timer = setTimeout(
|
|
108931
|
+
const timer = setTimeout(resolve18, ms);
|
|
108527
108932
|
signal?.addEventListener("abort", () => {
|
|
108528
108933
|
clearTimeout(timer);
|
|
108529
|
-
|
|
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
|
|
108850
|
-
import { join as
|
|
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
|
|
108855
|
-
import { join as
|
|
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 (!
|
|
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 =
|
|
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(
|
|
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 =
|
|
109009
|
-
if (!
|
|
109413
|
+
const parentAbs = join36(repoRoot, parent);
|
|
109414
|
+
if (!existsSync13(parentAbs))
|
|
109010
109415
|
continue;
|
|
109011
|
-
for (const entry of
|
|
109012
|
-
if (entry.isDirectory() &&
|
|
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(
|
|
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(
|
|
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 =
|
|
109043
|
-
const versionSourceFile =
|
|
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(
|
|
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(
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
109222
|
-
if (
|
|
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 =
|
|
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 =
|
|
109298
|
-
if (
|
|
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.
|
|
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
|
|
110315
|
-
import { join as
|
|
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 =
|
|
110345
|
-
var GLOBAL_RULES_DIR2 =
|
|
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 ?
|
|
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 =
|
|
110798
|
+
const destination = join37(target, relPath);
|
|
110394
110799
|
if (await context4.fs.exists(destination))
|
|
110395
110800
|
continue;
|
|
110396
|
-
await context4.fs.ensureDir(
|
|
110397
|
-
await context4.fs.writeFile(destination, await context4.fs.readFile(
|
|
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 ?
|
|
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 =
|
|
110820
|
+
const destination = join37(target, relPath);
|
|
110416
110821
|
if (await context4.fs.exists(destination))
|
|
110417
110822
|
continue;
|
|
110418
|
-
await context4.fs.ensureDir(
|
|
110419
|
-
await context4.fs.writeFile(destination, await context4.fs.readFile(
|
|
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 =
|
|
110423
|
-
const globalConfigPath =
|
|
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 =
|
|
110843
|
+
const configPath = join37(context4.cwd, CLI_CONFIG.configFile);
|
|
110439
110844
|
const result = { created: [], skipped: [] };
|
|
110440
110845
|
const globalConfigDir = resolveGlobalConfigDir(context4);
|
|
110441
|
-
const globalConfigPath =
|
|
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 =
|
|
110859
|
+
const sourcePath = join37(configRoot, relPath);
|
|
110455
110860
|
if (!await context4.fs.exists(sourcePath))
|
|
110456
110861
|
continue;
|
|
110457
|
-
const targetPath =
|
|
110458
|
-
await context4.fs.ensureDir(
|
|
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 =
|
|
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 :
|
|
110466
|
-
const targetPath =
|
|
110467
|
-
await context4.fs.ensureDir(
|
|
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 ?
|
|
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(
|
|
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 =
|
|
110962
|
+
const agentsDir = join37(context4.cwd, CLI_CONFIG.configDir, "agents");
|
|
110558
110963
|
await context4.fs.ensureDir(agentsDir);
|
|
110559
|
-
await writeIfNew(context4,
|
|
110560
|
-
const gitignorePath =
|
|
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 =
|
|
110985
|
+
const sourcePath = join37(configRoot, relPath);
|
|
110581
110986
|
if (!await context4.fs.exists(sourcePath))
|
|
110582
110987
|
continue;
|
|
110583
|
-
const targetPath =
|
|
110584
|
-
await context4.fs.ensureDir(
|
|
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 =
|
|
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 :
|
|
110592
|
-
const targetPath =
|
|
110593
|
-
await context4.fs.ensureDir(
|
|
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 =
|
|
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
|
|
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 ??
|
|
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((
|
|
111379
|
+
return new Promise((resolve19) => {
|
|
110975
111380
|
if (signal?.aborted) {
|
|
110976
|
-
|
|
111381
|
+
resolve19();
|
|
110977
111382
|
return;
|
|
110978
111383
|
}
|
|
110979
|
-
const timer = setTimeout(
|
|
111384
|
+
const timer = setTimeout(resolve19, ms);
|
|
110980
111385
|
signal?.addEventListener("abort", () => {
|
|
110981
111386
|
clearTimeout(timer);
|
|
110982
|
-
|
|
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((
|
|
111414
|
+
return new Promise((resolve19) => {
|
|
111010
111415
|
if (signal?.aborted) {
|
|
111011
|
-
|
|
111416
|
+
resolve19();
|
|
111012
111417
|
return;
|
|
111013
111418
|
}
|
|
111014
|
-
const timer = setTimeout(
|
|
111419
|
+
const timer = setTimeout(resolve19, ms);
|
|
111015
111420
|
signal?.addEventListener("abort", () => {
|
|
111016
111421
|
clearTimeout(timer);
|
|
111017
|
-
|
|
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
|
|
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(
|
|
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
|
|
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 =
|
|
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 ??
|
|
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 =
|
|
111150
|
-
await context4.fs.ensureDir(
|
|
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
|
|
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
|
|
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
|
|
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((
|
|
111880
|
-
pullResolvers.push([
|
|
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
|
|
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 ?
|
|
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(
|
|
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(
|
|
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
|
|
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 ??
|
|
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(
|
|
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 =
|
|
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 ? ` - ${
|
|
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 :
|
|
122054
|
-
|
|
122055
|
-
|
|
122056
|
-
|
|
122057
|
-
|
|
122058
|
-
|
|
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(
|
|
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(
|
|
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 =
|
|
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 ?
|
|
122832
|
+
return env.DATABASE_URL === undefined ? join44(cwd, DEFAULT_DATABASE_URL) : configuredUrl;
|
|
122378
122833
|
}
|
|
122379
122834
|
function resolveServeCwd(cwd) {
|
|
122380
|
-
const resolved =
|
|
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
|
|
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(
|
|
122482
|
-
context4.fs.exists(
|
|
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 =
|
|
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 =
|
|
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
|
|
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 =
|
|
123164
|
+
const artifactsDir = join46(cwd, ".spur", "run");
|
|
122710
123165
|
await mkdir(artifactsDir, { recursive: true });
|
|
122711
|
-
const artifactPath =
|
|
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:
|
|
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 =
|
|
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
|
|
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 =
|
|
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 ?
|
|
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(
|
|
125492
|
+
await createNodeFileSystem3().ensureDir(dirname28(url2));
|
|
125038
125493
|
}
|
|
125039
125494
|
return createMigratedDb({ url: url2 });
|
|
125040
125495
|
}
|