@gobing-ai/spur 0.3.60 → 0.3.62
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/config.example.yaml +2 -2
- package/config/config.global.yaml +68 -57
- package/config/corpus-baseline.json +505 -57
- package/config/plugin-scripts.json +2 -2
- package/config/rules/boundary/config-loading-ownership.yaml +21 -0
- package/config/workflow-composition-baseline.json +1 -1
- package/config/workflows/history-anatomy.yaml +366 -0
- package/config/workflows/wayfinder-resolution.yaml +4 -6
- package/package.json +1 -1
- package/plugins/README.md +5 -4
- package/plugins/sp/README.md +22 -9
- package/plugins/sp/agents/super-planner.md +1 -1
- package/plugins/sp/commands/dev-find-issue.md +25 -46
- package/plugins/sp/commands/dev-pr-review.md +1 -1
- package/plugins/sp/commands/dev-run.md +22 -3
- package/plugins/sp/commands/dev-wrap.md +2 -2
- package/plugins/sp/commands/dev-wrapall.md +2 -2
- package/plugins/sp/lib/artifact-digest.generated.d.mts +7 -0
- package/plugins/sp/lib/artifact-digest.generated.mjs +48 -0
- package/plugins/sp/plugin.json +1 -1
- package/plugins/sp/references/roles.md +17 -14
- package/plugins/sp/scripts/history-anatomy-cache.mjs +669 -0
- package/plugins/sp/scripts/history-anatomy-cache.ts +818 -0
- package/plugins/sp/scripts/surface-drift-inventory.ts +51 -17
- package/plugins/sp/scripts/validate-commands.ts +11 -4
- package/plugins/sp/skills/code-verification/SKILL.md +1 -1
- package/plugins/sp/skills/code-verification/references/verdict-schema.md +1 -1
- package/plugins/sp/skills/history-anatomy/SKILL.md +67 -0
- package/plugins/sp/skills/history-anatomy/references/modes.md +82 -0
- package/plugins/sp/skills/history-anatomy/references/operations.md +67 -0
- package/plugins/sp/skills/history-anatomy/references/report-contract.md +133 -0
- package/plugins/sp/skills/issue-finding/SKILL.md +1 -1
- package/plugins/sp/skills/next-router/references/routing-table.md +1 -1
- package/plugins/sp/skills/pr-reviewing/SKILL.md +2 -2
- package/plugins/sp/skills/spec-decomposition/references/decomposition.md +1 -1
- package/plugins/sp/skills/spur-cli/references/init.md +1 -1
- package/plugins/sp/skills/spur-cli/references/tasks/l3-guard-cheatsheet.md +1 -1
- package/plugins/sp/skills/spur-cli/references/workflows/operations.md +1 -1
- package/plugins/sp/skills/spur-cli/references/workflows.md +4 -4
- package/plugins/sp/skills/spur-dev/SKILL.md +4 -4
- package/plugins/sp/skills/spur-dev/references/ac-style-guide.md +4 -4
- package/plugins/sp/skills/spur-dev/references/dev-operations.md +11 -11
- package/plugins/sp/skills/spur-dev/references/done-housekeeping.md +1 -1
- package/plugins/sp/skills/spur-dev/references/execution-batch.md +17 -4
- package/plugins/sp/skills/spur-dev/references/execution-workflow.md +8 -1
- package/plugins/sp/skills/spur-dev/references/feature-link-helper.md +3 -2
- package/plugins/sp/skills/spur-dev/references/flag-glossary.md +25 -13
- package/plugins/sp/skills/spur-dev/references/gate-checklists.md +1 -1
- package/plugins/sp/skills/spur-dev/references/inline-pipeline-driver.md +5 -2
- package/plugins/sp/skills/spur-dev/references/planning-workflow.md +2 -2
- package/schemas/spur-config.schema.json +1 -1
- package/spur.js +1278 -890
- package/web/_astro/BoardApp.Z9jMwI9G.js +1 -0
- package/web/_astro/BoardApp.rkWGVwwK.js +178 -0
- package/web/_astro/{TaskDetail.B0l1uzsB.js → TaskDetail.B7ODt_bA.js} +1 -1
- package/web/_astro/{arc.DPruHC3P.js → arc.C5QRz6AQ.js} +1 -1
- package/web/_astro/{architectureDiagram-3BPJPVTR.CuOqAck6.js → architectureDiagram-3BPJPVTR.CHptn8gZ.js} +1 -1
- package/web/_astro/{blockDiagram-GPEHLZMM.Cxb7HDIA.js → blockDiagram-GPEHLZMM.b1nEDkDw.js} +1 -1
- package/web/_astro/{c4Diagram-AAUBKEIU.Dw7wa-0S.js → c4Diagram-AAUBKEIU.BWj8S_Qq.js} +1 -1
- package/web/_astro/channel.BJtn6CGV.js +1 -0
- package/web/_astro/{chunk-2J33WTMH.MECQitzo.js → chunk-2J33WTMH.q0BBuE1n.js} +1 -1
- package/web/_astro/{chunk-4BX2VUAB.p3ofhIGE.js → chunk-4BX2VUAB.DP2KDkAU.js} +1 -1
- package/web/_astro/{chunk-55IACEB6.BmQGsPZP.js → chunk-55IACEB6.CkCId72p.js} +1 -1
- package/web/_astro/{chunk-727SXJPM.CwrK23OA.js → chunk-727SXJPM.oHWzxMot.js} +1 -1
- package/web/_astro/{chunk-AQP2D5EJ.CUKI_QXp.js → chunk-AQP2D5EJ.DkkgxfMP.js} +1 -1
- package/web/_astro/{chunk-FMBD7UC4.7AtDgShM.js → chunk-FMBD7UC4.lmFJDvRK.js} +1 -1
- package/web/_astro/{chunk-ND2GUHAM.f_YJbTs3.js → chunk-ND2GUHAM.52jt0eHK.js} +1 -1
- package/web/_astro/{chunk-QZHKN3VN.0q7V3gEg.js → chunk-QZHKN3VN.Cg8KEFoD.js} +1 -1
- package/web/_astro/{classDiagram-4FO5ZUOK.C_hG3HMK.js → classDiagram-4FO5ZUOK.BuOUhxcD.js} +1 -1
- package/web/_astro/{classDiagram-v2-Q7XG4LA2.C_hG3HMK.js → classDiagram-v2-Q7XG4LA2.BuOUhxcD.js} +1 -1
- package/web/_astro/{cose-bilkent-S5V4N54A.vsaaaEMy.js → cose-bilkent-S5V4N54A.BRUU8E_0.js} +1 -1
- package/web/_astro/{dagre-BM42HDAG.BN7XFqQ4.js → dagre-BM42HDAG.GDbfFYVV.js} +1 -1
- package/web/_astro/{diagram-2AECGRRQ.ED6AfryZ.js → diagram-2AECGRRQ.CvIDBeJF.js} +1 -1
- package/web/_astro/{diagram-5GNKFQAL.Dxllzg8R.js → diagram-5GNKFQAL.DMgJjWOX.js} +1 -1
- package/web/_astro/{diagram-KO2AKTUF.RuWppieD.js → diagram-KO2AKTUF.njjl-0AP.js} +1 -1
- package/web/_astro/{diagram-LMA3HP47.CL32Xn6s.js → diagram-LMA3HP47.CcCqgP8M.js} +1 -1
- package/web/_astro/{diagram-OG6HWLK6.CUneEhqB.js → diagram-OG6HWLK6.Btqd-YVE.js} +1 -1
- package/web/_astro/{erDiagram-TEJ5UH35.DI-92Lec.js → erDiagram-TEJ5UH35.BbhML_Xo.js} +1 -1
- package/web/_astro/{flowDiagram-I6XJVG4X.69Aqa1FF.js → flowDiagram-I6XJVG4X.CkvsIgY8.js} +1 -1
- package/web/_astro/{ganttDiagram-6RSMTGT7.DdpClZpa.js → ganttDiagram-6RSMTGT7.m8IWD_wW.js} +1 -1
- package/web/_astro/{gitGraphDiagram-PVQCEYII.xqWfkvB4.js → gitGraphDiagram-PVQCEYII.5z87HXO-.js} +1 -1
- package/web/_astro/index.nWve6EHS.css +1 -0
- package/web/_astro/{infoDiagram-5YYISTIA.B3G5sfKm.js → infoDiagram-5YYISTIA.Bvyvsd7Q.js} +1 -1
- package/web/_astro/{ishikawaDiagram-YF4QCWOH.ahVNsoAQ.js → ishikawaDiagram-YF4QCWOH.DdWVYO87.js} +1 -1
- package/web/_astro/{journeyDiagram-JHISSGLW.PmFHLc-X.js → journeyDiagram-JHISSGLW.C3kOlYH1.js} +1 -1
- package/web/_astro/{kanban-definition-UN3LZRKU.Co1qOPTd.js → kanban-definition-UN3LZRKU.CfKTUHVC.js} +1 -1
- package/web/_astro/{linear.DoHZ-iRt.js → linear.CMDHnzgX.js} +1 -1
- package/web/_astro/{mermaid.core.DNRElYN2.js → mermaid.core.DN7-WrsP.js} +4 -4
- package/web/_astro/{mindmap-definition-RKZ34NQL.CdfJZidJ.js → mindmap-definition-RKZ34NQL.DcQxLvqG.js} +1 -1
- package/web/_astro/{pieDiagram-4H26LBE5.C1A8dby4.js → pieDiagram-4H26LBE5.Nu-Inbw6.js} +1 -1
- package/web/_astro/{quadrantDiagram-W4KKPZXB.NmZqjG_c.js → quadrantDiagram-W4KKPZXB.Dck2EChs.js} +1 -1
- package/web/_astro/{requirementDiagram-4Y6WPE33.tY36zYtK.js → requirementDiagram-4Y6WPE33.C--E5XuW.js} +1 -1
- package/web/_astro/{sankeyDiagram-5OEKKPKP.rOEGZYjo.js → sankeyDiagram-5OEKKPKP.B_0iRNna.js} +1 -1
- package/web/_astro/{sequenceDiagram-3UESZ5HK.Dpnw3S9J.js → sequenceDiagram-3UESZ5HK.PKuKr9mk.js} +1 -1
- package/web/_astro/{stateDiagram-AJRCARHV.DGpvQ3Wz.js → stateDiagram-AJRCARHV.ClhGHb-O.js} +1 -1
- package/web/_astro/{stateDiagram-v2-BHNVJYJU.CbwQdEfu.js → stateDiagram-v2-BHNVJYJU.Bv6BBnvg.js} +1 -1
- package/web/_astro/{timeline-definition-PNZ67QCA.DAYUpUJT.js → timeline-definition-PNZ67QCA.BZm2ZvAH.js} +1 -1
- package/web/_astro/{vennDiagram-CIIHVFJN.C7JCCd6-.js → vennDiagram-CIIHVFJN.Dt6yZXry.js} +1 -1
- package/web/_astro/{wardley-L42UT6IY.BGgwOH5_.js → wardley-L42UT6IY.rUs-E00M.js} +1 -1
- package/web/_astro/{wardleyDiagram-YWT4CUSO.oIZqzI2l.js → wardleyDiagram-YWT4CUSO.BcWgv4cA.js} +1 -1
- package/web/_astro/{xychartDiagram-2RQKCTM6.DohcJzqm.js → xychartDiagram-2RQKCTM6.DH-M-cX9.js} +1 -1
- package/web/index.html +2 -2
- package/plugins/sp/commands/dev-history-load.md +0 -63
- package/plugins/sp/scripts/history-load.mjs +0 -268
- package/plugins/sp/scripts/history-load.ts +0 -400
- package/web/_astro/BoardApp.BJs3l7O8.js +0 -179
- package/web/_astro/BoardApp.D8InuCYx.js +0 -1
- package/web/_astro/channel.XCf1DcsL.js +0 -1
- package/web/_astro/index.DJl2RAVZ.css +0 -1
package/spur.js
CHANGED
|
@@ -37418,466 +37418,6 @@ var require_extra_typings = __commonJS((exports, module) => {
|
|
|
37418
37418
|
exports.createArgument = (name, description) => new commander.Argument(name, description);
|
|
37419
37419
|
});
|
|
37420
37420
|
|
|
37421
|
-
// ../../packages/config/src/finding-codes.ts
|
|
37422
|
-
function isFindingCode(code) {
|
|
37423
|
-
return ALL_FINDING_CODES.includes(code);
|
|
37424
|
-
}
|
|
37425
|
-
var ALL_FINDING_CODES, FINDING_CODES;
|
|
37426
|
-
var init_finding_codes = __esm(() => {
|
|
37427
|
-
ALL_FINDING_CODES = [
|
|
37428
|
-
"L1.markdown-parse",
|
|
37429
|
-
"L1.schema-validation",
|
|
37430
|
-
"L2.missing-required-section",
|
|
37431
|
-
"L2.forbidden-section",
|
|
37432
|
-
"L2.disallowed-section",
|
|
37433
|
-
"L2.heading-level",
|
|
37434
|
-
"L2.section-order",
|
|
37435
|
-
"L3.requirements-format",
|
|
37436
|
-
"L3.requirements-checkbox",
|
|
37437
|
-
"L3.requirements-empty",
|
|
37438
|
-
"L3.ac-empty",
|
|
37439
|
-
"L3.ac-requirement-coverage",
|
|
37440
|
-
"L3.solution-file-line",
|
|
37441
|
-
"L3.review-priority-table",
|
|
37442
|
-
"L3.testing-coverage",
|
|
37443
|
-
"L3.required-section-placeholder",
|
|
37444
|
-
"L3.plan-format",
|
|
37445
|
-
"L3.unchecked-checklist",
|
|
37446
|
-
"L3.ac-checklist-text",
|
|
37447
|
-
"L3.ac-bdd-error",
|
|
37448
|
-
"L3.ac-bdd-warning",
|
|
37449
|
-
"L3.ac-bdd-invalid",
|
|
37450
|
-
"L3.scope-delineation",
|
|
37451
|
-
"L3.one-active-goal",
|
|
37452
|
-
"L3.children-limit",
|
|
37453
|
-
"L4.design-placeholder",
|
|
37454
|
-
"L4.feature-not-found",
|
|
37455
|
-
"L4.feature-terminal",
|
|
37456
|
-
"L4.missing-feature-id",
|
|
37457
|
-
"L4.parent-not-found",
|
|
37458
|
-
"L4.dependency-not-found",
|
|
37459
|
-
"L4.rollup-subtasks-open",
|
|
37460
|
-
"L4.rollup-parent-open",
|
|
37461
|
-
"L4.rollup-missing-roster",
|
|
37462
|
-
"L4.readiness-blocked",
|
|
37463
|
-
"L4.prose-prerequisite-unlisted",
|
|
37464
|
-
"L4.prerequisite-cycle",
|
|
37465
|
-
"L4.prerequisite-not-done",
|
|
37466
|
-
"L4.gate-language",
|
|
37467
|
-
"L4.linked-task-parse-failed",
|
|
37468
|
-
"L4.orphan-scenarios",
|
|
37469
|
-
"L4.uncovered-task-scenario",
|
|
37470
|
-
"L4.uncovered-feature-scenario",
|
|
37471
|
-
"L4.verifying-incomplete-tasks",
|
|
37472
|
-
"L4.dogfood-missing",
|
|
37473
|
-
"L4.stale-line-anchor",
|
|
37474
|
-
"L4.anchor-subject-mismatch",
|
|
37475
|
-
"L4.malformed-verdict-artifact",
|
|
37476
|
-
"L4.scenario-unverified",
|
|
37477
|
-
"L4.testing-verdict-stub"
|
|
37478
|
-
];
|
|
37479
|
-
FINDING_CODES = {
|
|
37480
|
-
L1_MARKDOWN_PARSE: "L1.markdown-parse",
|
|
37481
|
-
L1_SCHEMA_VALIDATION: "L1.schema-validation",
|
|
37482
|
-
L2_MISSING_REQUIRED_SECTION: "L2.missing-required-section",
|
|
37483
|
-
L2_FORBIDDEN_SECTION: "L2.forbidden-section",
|
|
37484
|
-
L2_DISALLOWED_SECTION: "L2.disallowed-section",
|
|
37485
|
-
L2_HEADING_LEVEL: "L2.heading-level",
|
|
37486
|
-
L2_SECTION_ORDER: "L2.section-order",
|
|
37487
|
-
L3_REQUIREMENTS_FORMAT: "L3.requirements-format",
|
|
37488
|
-
L3_REQUIREMENTS_CHECKBOX: "L3.requirements-checkbox",
|
|
37489
|
-
L3_REQUIREMENTS_EMPTY: "L3.requirements-empty",
|
|
37490
|
-
L3_AC_EMPTY: "L3.ac-empty",
|
|
37491
|
-
L3_AC_REQUIREMENT_COVERAGE: "L3.ac-requirement-coverage",
|
|
37492
|
-
L3_SOLUTION_FILE_LINE: "L3.solution-file-line",
|
|
37493
|
-
L3_REVIEW_PRIORITY_TABLE: "L3.review-priority-table",
|
|
37494
|
-
L3_TESTING_COVERAGE: "L3.testing-coverage",
|
|
37495
|
-
L3_REQUIRED_SECTION_PLACEHOLDER: "L3.required-section-placeholder",
|
|
37496
|
-
L3_PLAN_FORMAT: "L3.plan-format",
|
|
37497
|
-
L3_UNCHECKED_CHECKLIST: "L3.unchecked-checklist",
|
|
37498
|
-
L3_AC_CHECKLIST_TEXT: "L3.ac-checklist-text",
|
|
37499
|
-
L3_AC_BDD_ERROR: "L3.ac-bdd-error",
|
|
37500
|
-
L3_AC_BDD_WARNING: "L3.ac-bdd-warning",
|
|
37501
|
-
L3_AC_BDD_INVALID: "L3.ac-bdd-invalid",
|
|
37502
|
-
L3_SCOPE_DELINEATION: "L3.scope-delineation",
|
|
37503
|
-
L3_ONE_ACTIVE_GOAL: "L3.one-active-goal",
|
|
37504
|
-
L3_CHILDREN_LIMIT: "L3.children-limit",
|
|
37505
|
-
L4_DESIGN_PLACEHOLDER: "L4.design-placeholder",
|
|
37506
|
-
L4_FEATURE_NOT_FOUND: "L4.feature-not-found",
|
|
37507
|
-
L4_FEATURE_TERMINAL: "L4.feature-terminal",
|
|
37508
|
-
L4_MISSING_FEATURE_ID: "L4.missing-feature-id",
|
|
37509
|
-
L4_PARENT_NOT_FOUND: "L4.parent-not-found",
|
|
37510
|
-
L4_DEPENDENCY_NOT_FOUND: "L4.dependency-not-found",
|
|
37511
|
-
L4_ROLLUP_SUBTASKS_OPEN: "L4.rollup-subtasks-open",
|
|
37512
|
-
L4_ROLLUP_PARENT_OPEN: "L4.rollup-parent-open",
|
|
37513
|
-
L4_ROLLUP_MISSING_ROSTER: "L4.rollup-missing-roster",
|
|
37514
|
-
L4_READINESS_BLOCKED: "L4.readiness-blocked",
|
|
37515
|
-
L4_PROSE_PREREQUISITE_UNLISTED: "L4.prose-prerequisite-unlisted",
|
|
37516
|
-
L4_PREREQUISITE_CYCLE: "L4.prerequisite-cycle",
|
|
37517
|
-
L4_PREREQUISITE_NOT_DONE: "L4.prerequisite-not-done",
|
|
37518
|
-
L4_GATE_LANGUAGE: "L4.gate-language",
|
|
37519
|
-
L4_LINKED_TASK_PARSE_FAILED: "L4.linked-task-parse-failed",
|
|
37520
|
-
L4_ORPHAN_SCENARIOS: "L4.orphan-scenarios",
|
|
37521
|
-
L4_UNCOVERED_TASK_SCENARIO: "L4.uncovered-task-scenario",
|
|
37522
|
-
L4_UNCOVERED_FEATURE_SCENARIO: "L4.uncovered-feature-scenario",
|
|
37523
|
-
L4_DOGFOOD_MISSING: "L4.dogfood-missing",
|
|
37524
|
-
L4_VERIFYING_INCOMPLETE_TASKS: "L4.verifying-incomplete-tasks",
|
|
37525
|
-
L4_STALE_LINE_ANCHOR: "L4.stale-line-anchor",
|
|
37526
|
-
L4_ANCHOR_SUBJECT_MISMATCH: "L4.anchor-subject-mismatch",
|
|
37527
|
-
L4_MALFORMED_VERDICT_ARTIFACT: "L4.malformed-verdict-artifact",
|
|
37528
|
-
L4_SCENARIO_UNVERIFIED: "L4.scenario-unverified",
|
|
37529
|
-
L4_TESTING_VERDICT_STUB: "L4.testing-verdict-stub"
|
|
37530
|
-
};
|
|
37531
|
-
});
|
|
37532
|
-
|
|
37533
|
-
// ../../packages/config/src/projects.ts
|
|
37534
|
-
import { homedir } from "os";
|
|
37535
|
-
import { join } from "path";
|
|
37536
|
-
function getProjectsFilePath() {
|
|
37537
|
-
if (process.env.SPUR_PROJECTS_FILE) {
|
|
37538
|
-
return process.env.SPUR_PROJECTS_FILE;
|
|
37539
|
-
}
|
|
37540
|
-
return join(homedir(), ".config", "spur", "projects.json");
|
|
37541
|
-
}
|
|
37542
|
-
var projectEntrySchema, projectsFileSchema;
|
|
37543
|
-
var init_projects = __esm(() => {
|
|
37544
|
-
init_zod();
|
|
37545
|
-
projectEntrySchema = exports_external.object({
|
|
37546
|
-
name: exports_external.string().min(1),
|
|
37547
|
-
path: exports_external.string().min(1),
|
|
37548
|
-
port: exports_external.number().int().nonnegative().default(0)
|
|
37549
|
-
});
|
|
37550
|
-
projectsFileSchema = exports_external.object({
|
|
37551
|
-
schema_version: exports_external.literal(1).default(1),
|
|
37552
|
-
projects: exports_external.array(projectEntrySchema).default([])
|
|
37553
|
-
});
|
|
37554
|
-
});
|
|
37555
|
-
|
|
37556
|
-
// ../../packages/config/src/index.ts
|
|
37557
|
-
function folderPathWithDefault(defaultPath) {
|
|
37558
|
-
return exports_external.preprocess((v) => v == null ? undefined : v, exports_external.string().default(defaultPath));
|
|
37559
|
-
}
|
|
37560
|
-
function normalizeExecutorTier(value) {
|
|
37561
|
-
return value === "capable" ? "capable-1" : value;
|
|
37562
|
-
}
|
|
37563
|
-
function normalizeMember(member) {
|
|
37564
|
-
return typeof member === "string" ? { executor: member } : { ...member };
|
|
37565
|
-
}
|
|
37566
|
-
function memberLocalId(member, roster, index2) {
|
|
37567
|
-
if (member.id !== undefined)
|
|
37568
|
-
return member.id;
|
|
37569
|
-
if (member.executor !== undefined)
|
|
37570
|
-
return member.executor;
|
|
37571
|
-
const role = member.role;
|
|
37572
|
-
if (role === undefined)
|
|
37573
|
-
return "";
|
|
37574
|
-
let n2 = 0;
|
|
37575
|
-
for (let i2 = 0;i2 <= index2; i2++) {
|
|
37576
|
-
const m = roster[i2];
|
|
37577
|
-
if (m !== undefined && m.id === undefined && m.executor === undefined && m.role === role)
|
|
37578
|
-
n2 += 1;
|
|
37579
|
-
}
|
|
37580
|
-
return `${role}-${n2}`;
|
|
37581
|
-
}
|
|
37582
|
-
function resolveExecutor(name, agentConfig, opts) {
|
|
37583
|
-
const exec = agentConfig?.executors?.find((entry) => entry.name === name);
|
|
37584
|
-
if (exec !== undefined)
|
|
37585
|
-
return { agent: exec.agent, model: exec.model };
|
|
37586
|
-
if (opts?.isCanonicalAgent === undefined || opts.isCanonicalAgent(name)) {
|
|
37587
|
-
return { agent: name };
|
|
37588
|
-
}
|
|
37589
|
-
throw new Error(`Unknown executor or agent reference: "${name}"`);
|
|
37590
|
-
}
|
|
37591
|
-
function resolveHistoryRefreshTrigger(config3) {
|
|
37592
|
-
const parsed = HistoryRefreshConfigSchema.parse(config3?.history?.refresh ?? {});
|
|
37593
|
-
return { onCompletion: parsed.on_completion, debounceMs: parsed.debounce_ms };
|
|
37594
|
-
}
|
|
37595
|
-
function parseEnvBoolean(value) {
|
|
37596
|
-
if (value === undefined || value === "")
|
|
37597
|
-
return;
|
|
37598
|
-
const normalized = value.toLowerCase();
|
|
37599
|
-
if (["1", "true", "yes", "on"].includes(normalized))
|
|
37600
|
-
return true;
|
|
37601
|
-
if (["0", "false", "no", "off"].includes(normalized))
|
|
37602
|
-
return false;
|
|
37603
|
-
throw new Error(`Invalid boolean environment value: expected true/false, received ${value}`);
|
|
37604
|
-
}
|
|
37605
|
-
function buildConfigFromEnv(env = process.env) {
|
|
37606
|
-
return configSchema2.parse({
|
|
37607
|
-
database: {
|
|
37608
|
-
url: env[SPUR_ENV_VARS.databaseUrl]
|
|
37609
|
-
},
|
|
37610
|
-
server: {
|
|
37611
|
-
port: env[SPUR_ENV_VARS.port],
|
|
37612
|
-
host: env[SPUR_ENV_VARS.host]
|
|
37613
|
-
},
|
|
37614
|
-
telemetry: {
|
|
37615
|
-
enabled: parseEnvBoolean(env.SPUR_TELEMETRY_ENABLED),
|
|
37616
|
-
endpoint: env.SPUR_TELEMETRY_ENDPOINT
|
|
37617
|
-
},
|
|
37618
|
-
logging: {
|
|
37619
|
-
level: env.SPUR_LOG_LEVEL
|
|
37620
|
-
}
|
|
37621
|
-
});
|
|
37622
|
-
}
|
|
37623
|
-
var SPUR_ENV_VARS, SPUR_LOG_LEVELS, DEFAULT_TASKS_DIR = "docs/tasks", DEFAULT_FEATURES_DIR = "docs/features", DEFAULT_DATABASE_URL = ".spur/spur.db", IN_MEMORY_DATABASE_URL = ":memory:", folderConfigSchema, tasksConfigSchema, featuresConfigSchema, EXECUTOR_CAPABILITY_TIERS, executorCapabilityTierSchema, AGENT_ROLE_NAMES, DEFAULT_AGENT_ROLES, AgentExecutorConfigSchema, AgentRoleConfigSchema, AGENT_ID_REGEX, TeamMemberConfigSchema, TeamConfigSchema, AgentOutputConfigSchema, AgentConfigSchema, RulesConfigSchema, WorkflowsConfigSchema, WorkflowConfigSchema, RedactionConfigSchema, HistoryRefreshConfigSchema, HistoryConfigSchema, spurConfigSchema, configSchema2;
|
|
37624
|
-
var init_src = __esm(() => {
|
|
37625
|
-
init_zod();
|
|
37626
|
-
init_finding_codes();
|
|
37627
|
-
init_projects();
|
|
37628
|
-
SPUR_ENV_VARS = {
|
|
37629
|
-
nodeEnv: "NODE_ENV",
|
|
37630
|
-
port: "PORT",
|
|
37631
|
-
host: "HOST",
|
|
37632
|
-
publicApiUrl: "PUBLIC_API_URL",
|
|
37633
|
-
databaseUrl: "DATABASE_URL"
|
|
37634
|
-
};
|
|
37635
|
-
SPUR_LOG_LEVELS = ["debug", "info", "warn", "error"];
|
|
37636
|
-
folderConfigSchema = exports_external.object({
|
|
37637
|
-
baseCounter: exports_external.number().int().nonnegative().default(0),
|
|
37638
|
-
label: exports_external.string().optional()
|
|
37639
|
-
});
|
|
37640
|
-
tasksConfigSchema = exports_external.object({
|
|
37641
|
-
folders: exports_external.record(exports_external.string(), folderConfigSchema).default({}),
|
|
37642
|
-
active: folderPathWithDefault(DEFAULT_TASKS_DIR),
|
|
37643
|
-
severity: exports_external.record(exports_external.string(), exports_external.enum(["error", "warning", "off"])).optional()
|
|
37644
|
-
}).superRefine((data, ctx) => {
|
|
37645
|
-
if (data.severity) {
|
|
37646
|
-
for (const code of Object.keys(data.severity)) {
|
|
37647
|
-
if (!isFindingCode(code)) {
|
|
37648
|
-
ctx.addIssue({
|
|
37649
|
-
code: exports_external.ZodIssueCode.custom,
|
|
37650
|
-
path: ["severity", code],
|
|
37651
|
-
message: `Unknown finding code "${code}" in severity overrides map`
|
|
37652
|
-
});
|
|
37653
|
-
}
|
|
37654
|
-
}
|
|
37655
|
-
}
|
|
37656
|
-
});
|
|
37657
|
-
featuresConfigSchema = exports_external.object({
|
|
37658
|
-
dir: folderPathWithDefault(DEFAULT_FEATURES_DIR)
|
|
37659
|
-
});
|
|
37660
|
-
EXECUTOR_CAPABILITY_TIERS = ["cheap", "standard", "capable-1", "capable-2", "capable-3"];
|
|
37661
|
-
executorCapabilityTierSchema = exports_external.preprocess((value) => {
|
|
37662
|
-
if (value === undefined || value === null)
|
|
37663
|
-
return;
|
|
37664
|
-
return normalizeExecutorTier(value);
|
|
37665
|
-
}, exports_external.enum(EXECUTOR_CAPABILITY_TIERS).optional());
|
|
37666
|
-
AGENT_ROLE_NAMES = ["scribe", "coder", "reviewer", "planner"];
|
|
37667
|
-
DEFAULT_AGENT_ROLES = new Map([
|
|
37668
|
-
["scribe", { tier: "cheap", stages: ["changelog"] }],
|
|
37669
|
-
["coder", { tier: "standard", stages: ["implement", "test", "wrap"] }],
|
|
37670
|
-
["reviewer", { tier: "capable-1", stages: ["verify", "review", "dogfood"] }],
|
|
37671
|
-
["planner", { tier: "capable-2", stages: ["plan", "refine", "brainstorm"] }]
|
|
37672
|
-
]);
|
|
37673
|
-
AgentExecutorConfigSchema = exports_external.object({
|
|
37674
|
-
name: exports_external.string().min(1),
|
|
37675
|
-
agent: exports_external.string().min(1),
|
|
37676
|
-
model: exports_external.string().min(1).optional(),
|
|
37677
|
-
tier: executorCapabilityTierSchema.optional()
|
|
37678
|
-
});
|
|
37679
|
-
AgentRoleConfigSchema = exports_external.object({
|
|
37680
|
-
tier: exports_external.enum(EXECUTOR_CAPABILITY_TIERS).optional(),
|
|
37681
|
-
stages: exports_external.array(exports_external.string().min(1)).min(1).optional()
|
|
37682
|
-
});
|
|
37683
|
-
AGENT_ID_REGEX = /^[a-z][a-z0-9_-]{1,63}$/;
|
|
37684
|
-
TeamMemberConfigSchema = exports_external.union([
|
|
37685
|
-
exports_external.string().min(1),
|
|
37686
|
-
exports_external.object({
|
|
37687
|
-
executor: exports_external.string().min(1).optional(),
|
|
37688
|
-
id: exports_external.string().min(1).optional(),
|
|
37689
|
-
role: exports_external.enum(AGENT_ROLE_NAMES, {
|
|
37690
|
-
error: (issue2) => new Error(`Unknown role "${issue2.input}" \u2014 expected one of: ${AGENT_ROLE_NAMES.join(", ")}`)
|
|
37691
|
-
}).optional(),
|
|
37692
|
-
purpose: exports_external.string().optional(),
|
|
37693
|
-
workspace: exports_external.string().min(1).optional(),
|
|
37694
|
-
model: exports_external.string().min(1).optional(),
|
|
37695
|
-
autonomy: exports_external.string().optional(),
|
|
37696
|
-
systemPrompt: exports_external.string().optional(),
|
|
37697
|
-
command: exports_external.array(exports_external.string().min(1)).optional(),
|
|
37698
|
-
autostart: exports_external.boolean().optional()
|
|
37699
|
-
})
|
|
37700
|
-
]);
|
|
37701
|
-
TeamConfigSchema = exports_external.object({
|
|
37702
|
-
name: exports_external.string().min(1),
|
|
37703
|
-
work_dir: exports_external.string().min(1),
|
|
37704
|
-
autostart: exports_external.boolean().optional(),
|
|
37705
|
-
members: exports_external.array(TeamMemberConfigSchema).min(1)
|
|
37706
|
-
});
|
|
37707
|
-
AgentOutputConfigSchema = exports_external.object({
|
|
37708
|
-
"max-bytes": exports_external.number().int().positive().optional(),
|
|
37709
|
-
"max-lines": exports_external.number().int().positive().optional()
|
|
37710
|
-
});
|
|
37711
|
-
AgentConfigSchema = exports_external.object({
|
|
37712
|
-
default: exports_external.string().optional(),
|
|
37713
|
-
executors: exports_external.array(AgentExecutorConfigSchema).optional(),
|
|
37714
|
-
roles: exports_external.record(exports_external.string(), AgentRoleConfigSchema).optional(),
|
|
37715
|
-
team: exports_external.record(exports_external.string(), TeamConfigSchema).optional(),
|
|
37716
|
-
output: AgentOutputConfigSchema.optional(),
|
|
37717
|
-
sessionAffinity: exports_external.boolean().optional()
|
|
37718
|
-
}).superRefine((value, ctx) => {
|
|
37719
|
-
for (const key of Object.keys(value.roles ?? {})) {
|
|
37720
|
-
if (!AGENT_ROLE_NAMES.includes(key)) {
|
|
37721
|
-
ctx.addIssue({
|
|
37722
|
-
code: exports_external.ZodIssueCode.custom,
|
|
37723
|
-
path: ["roles", key],
|
|
37724
|
-
message: `Unknown role "${key}" \u2014 expected one of: ${AGENT_ROLE_NAMES.join(", ")}`
|
|
37725
|
-
});
|
|
37726
|
-
}
|
|
37727
|
-
}
|
|
37728
|
-
const executors = value.executors;
|
|
37729
|
-
const executorNames = new Set;
|
|
37730
|
-
if (executors !== undefined) {
|
|
37731
|
-
const seen = new Set;
|
|
37732
|
-
for (const [index2, executor] of executors.entries()) {
|
|
37733
|
-
if (seen.has(executor.name)) {
|
|
37734
|
-
ctx.addIssue({
|
|
37735
|
-
code: exports_external.ZodIssueCode.custom,
|
|
37736
|
-
message: `Duplicate executor name: ${executor.name}`,
|
|
37737
|
-
path: ["executors", index2, "name"]
|
|
37738
|
-
});
|
|
37739
|
-
}
|
|
37740
|
-
if (executor.name === "inline" || executor.name === "auto") {
|
|
37741
|
-
ctx.addIssue({
|
|
37742
|
-
code: exports_external.ZodIssueCode.custom,
|
|
37743
|
-
message: `Executor name "${executor.name}" is reserved (the --agent selector value '${executor.name}' has fixed semantics); rename executor at index ${index2}.`,
|
|
37744
|
-
path: ["executors", index2, "name"]
|
|
37745
|
-
});
|
|
37746
|
-
}
|
|
37747
|
-
if (AGENT_ROLE_NAMES.includes(executor.name)) {
|
|
37748
|
-
ctx.addIssue({
|
|
37749
|
-
code: exports_external.ZodIssueCode.custom,
|
|
37750
|
-
message: `Executor name "${executor.name}" collides with the role selector namespace ("${executor.name}"); rename executor at index ${index2}.`,
|
|
37751
|
-
path: ["executors", index2, "name"]
|
|
37752
|
-
});
|
|
37753
|
-
}
|
|
37754
|
-
seen.add(executor.name);
|
|
37755
|
-
executorNames.add(executor.name);
|
|
37756
|
-
}
|
|
37757
|
-
}
|
|
37758
|
-
const team = value.team;
|
|
37759
|
-
if (team === undefined)
|
|
37760
|
-
return;
|
|
37761
|
-
const seenComposed = new Set;
|
|
37762
|
-
for (const [teamId, teamConfig] of Object.entries(team)) {
|
|
37763
|
-
const seenLocal = new Set;
|
|
37764
|
-
const members = teamConfig.members.map(normalizeMember);
|
|
37765
|
-
members.forEach((ref, index2) => {
|
|
37766
|
-
if (ref.executor === undefined && ref.role === undefined) {
|
|
37767
|
-
ctx.addIssue({
|
|
37768
|
-
code: exports_external.ZodIssueCode.custom,
|
|
37769
|
-
message: `Team member at index ${index2} in team "${teamId}" declares neither role nor executor \u2014 at least one of role or executor is required.`,
|
|
37770
|
-
path: ["team", teamId, "members", index2]
|
|
37771
|
-
});
|
|
37772
|
-
return;
|
|
37773
|
-
}
|
|
37774
|
-
const localId = memberLocalId(ref, members, index2);
|
|
37775
|
-
if (seenLocal.has(localId)) {
|
|
37776
|
-
ctx.addIssue({
|
|
37777
|
-
code: exports_external.ZodIssueCode.custom,
|
|
37778
|
-
message: `Duplicate team member id: ${localId} in team "${teamId}"`,
|
|
37779
|
-
path: ["team", teamId, "members", index2]
|
|
37780
|
-
});
|
|
37781
|
-
}
|
|
37782
|
-
seenLocal.add(localId);
|
|
37783
|
-
const composedId = `${teamId}-${localId}`;
|
|
37784
|
-
if (!AGENT_ID_REGEX.test(composedId)) {
|
|
37785
|
-
ctx.addIssue({
|
|
37786
|
-
code: exports_external.ZodIssueCode.custom,
|
|
37787
|
-
message: `Invalid composed agent id "${composedId}": team key "${teamId}" + member "${localId}" must match ^[a-z][a-z0-9_-]{1,63}$ (2-64 chars, lowercase).`,
|
|
37788
|
-
path: ["team", teamId, "members", index2]
|
|
37789
|
-
});
|
|
37790
|
-
}
|
|
37791
|
-
if (seenComposed.has(composedId)) {
|
|
37792
|
-
ctx.addIssue({
|
|
37793
|
-
code: exports_external.ZodIssueCode.custom,
|
|
37794
|
-
message: `Composed agent id "${composedId}" collides across teams \u2014 every <teamId>-<localId> must be globally unique (a hyphenated team key can overlap another team's member id).`,
|
|
37795
|
-
path: ["team", teamId, "members", index2]
|
|
37796
|
-
});
|
|
37797
|
-
}
|
|
37798
|
-
seenComposed.add(composedId);
|
|
37799
|
-
if (ref.id !== undefined && AGENT_ROLE_NAMES.includes(ref.id)) {
|
|
37800
|
-
ctx.addIssue({
|
|
37801
|
-
code: exports_external.ZodIssueCode.custom,
|
|
37802
|
-
message: `Team member id "${ref.id}" collides with the role selector namespace ("${ref.id}") in team "${teamId}"; rename the member id.`,
|
|
37803
|
-
path: ["team", teamId, "members", index2]
|
|
37804
|
-
});
|
|
37805
|
-
}
|
|
37806
|
-
if (ref.id !== undefined && executorNames.has(ref.id)) {
|
|
37807
|
-
ctx.addIssue({
|
|
37808
|
-
code: exports_external.ZodIssueCode.custom,
|
|
37809
|
-
message: `Team member id "${ref.id}" collides with executor name "${ref.id}" in team "${teamId}"; the --agent selector namespace must be pairwise disjoint.`,
|
|
37810
|
-
path: ["team", teamId, "members", index2]
|
|
37811
|
-
});
|
|
37812
|
-
}
|
|
37813
|
-
if (executorNames.has(composedId)) {
|
|
37814
|
-
ctx.addIssue({
|
|
37815
|
-
code: exports_external.ZodIssueCode.custom,
|
|
37816
|
-
message: `Composed agent id "${composedId}" collides with executor name "${composedId}"; the --agent selector namespace must be pairwise disjoint.`,
|
|
37817
|
-
path: ["team", teamId, "members", index2]
|
|
37818
|
-
});
|
|
37819
|
-
}
|
|
37820
|
-
if (AGENT_ROLE_NAMES.includes(composedId)) {
|
|
37821
|
-
ctx.addIssue({
|
|
37822
|
-
code: exports_external.ZodIssueCode.custom,
|
|
37823
|
-
message: `Composed agent id "${composedId}" collides with the role selector namespace ("${composedId}"); the --agent selector namespace must be pairwise disjoint.`,
|
|
37824
|
-
path: ["team", teamId, "members", index2]
|
|
37825
|
-
});
|
|
37826
|
-
}
|
|
37827
|
-
});
|
|
37828
|
-
}
|
|
37829
|
-
});
|
|
37830
|
-
RulesConfigSchema = exports_external.object({
|
|
37831
|
-
paths: exports_external.array(exports_external.string()).optional()
|
|
37832
|
-
});
|
|
37833
|
-
WorkflowsConfigSchema = exports_external.object({
|
|
37834
|
-
paths: exports_external.array(exports_external.string()).optional()
|
|
37835
|
-
});
|
|
37836
|
-
WorkflowConfigSchema = exports_external.object({
|
|
37837
|
-
logRetentionDays: exports_external.number().int().positive().default(30)
|
|
37838
|
-
});
|
|
37839
|
-
RedactionConfigSchema = exports_external.object({
|
|
37840
|
-
enabled: exports_external.boolean().optional()
|
|
37841
|
-
});
|
|
37842
|
-
HistoryRefreshConfigSchema = exports_external.object({
|
|
37843
|
-
on_completion: exports_external.boolean().default(false),
|
|
37844
|
-
debounce_ms: exports_external.number().int().min(1000).default(600000)
|
|
37845
|
-
});
|
|
37846
|
-
HistoryConfigSchema = exports_external.object({
|
|
37847
|
-
refresh: HistoryRefreshConfigSchema.optional()
|
|
37848
|
-
});
|
|
37849
|
-
spurConfigSchema = exports_external.object({
|
|
37850
|
-
version: exports_external.string().optional(),
|
|
37851
|
-
name: exports_external.string().optional(),
|
|
37852
|
-
agent: AgentConfigSchema.optional(),
|
|
37853
|
-
rules: RulesConfigSchema.optional(),
|
|
37854
|
-
workflows: WorkflowsConfigSchema.optional(),
|
|
37855
|
-
workflow: WorkflowConfigSchema.optional(),
|
|
37856
|
-
redaction: RedactionConfigSchema.optional(),
|
|
37857
|
-
history: HistoryConfigSchema.optional(),
|
|
37858
|
-
tasks: tasksConfigSchema.optional(),
|
|
37859
|
-
features: featuresConfigSchema.optional()
|
|
37860
|
-
});
|
|
37861
|
-
configSchema2 = exports_external.object({
|
|
37862
|
-
database: exports_external.object({
|
|
37863
|
-
url: exports_external.string().default(DEFAULT_DATABASE_URL)
|
|
37864
|
-
}).default({ url: DEFAULT_DATABASE_URL }),
|
|
37865
|
-
server: exports_external.object({
|
|
37866
|
-
port: exports_external.coerce.number().int().positive().default(3000),
|
|
37867
|
-
host: exports_external.string().default("localhost"),
|
|
37868
|
-
openBrowser: exports_external.boolean().default(true),
|
|
37869
|
-
webDistPath: exports_external.string().nullable().default(null)
|
|
37870
|
-
}).default({ port: 3000, host: "localhost", openBrowser: true, webDistPath: null }),
|
|
37871
|
-
telemetry: exports_external.object({
|
|
37872
|
-
enabled: exports_external.boolean().default(false),
|
|
37873
|
-
endpoint: exports_external.string().optional()
|
|
37874
|
-
}).default({ enabled: false }),
|
|
37875
|
-
logging: exports_external.object({
|
|
37876
|
-
level: exports_external.enum(SPUR_LOG_LEVELS).default("info")
|
|
37877
|
-
}).default({ level: "info" })
|
|
37878
|
-
});
|
|
37879
|
-
});
|
|
37880
|
-
|
|
37881
37421
|
// ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.42+815552c3ca302057/node_modules/@gobing-ai/ts-runtime/dist/config.js
|
|
37882
37422
|
function parseYamlObject(text3) {
|
|
37883
37423
|
let parsed;
|
|
@@ -37927,7 +37467,7 @@ function interpolateTree2(value) {
|
|
|
37927
37467
|
function buildConfigFromObject2(raw, options = {}) {
|
|
37928
37468
|
const interpolated = interpolateTree2(raw);
|
|
37929
37469
|
const merged = options.overrides ? deepMerge(interpolated, options.overrides) : interpolated;
|
|
37930
|
-
const result =
|
|
37470
|
+
const result = configSchema2.safeParse(merged);
|
|
37931
37471
|
if (!result.success) {
|
|
37932
37472
|
throw new ConfigLoadError2("Config validation failed", result.error.issues);
|
|
37933
37473
|
}
|
|
@@ -37964,12 +37504,12 @@ function deepFreeze2(obj) {
|
|
|
37964
37504
|
}
|
|
37965
37505
|
return obj;
|
|
37966
37506
|
}
|
|
37967
|
-
var
|
|
37507
|
+
var configSchema2, ENV_INTERPOLATION_RE2, YamlParseError, ConfigLoadError2;
|
|
37968
37508
|
var init_config2 = __esm(() => {
|
|
37969
37509
|
init_dist();
|
|
37970
37510
|
init_dist2();
|
|
37971
37511
|
init_zod();
|
|
37972
|
-
|
|
37512
|
+
configSchema2 = exports_external.object({
|
|
37973
37513
|
app: exports_external.object({
|
|
37974
37514
|
name: exports_external.string().default("app"),
|
|
37975
37515
|
env: exports_external.enum(["development", "staging", "production", "test"]).default("development"),
|
|
@@ -39435,7 +38975,7 @@ __export(exports_dist2, {
|
|
|
39435
38975
|
createLogStream: () => createLogStream2,
|
|
39436
38976
|
createInMemoryProcessRegistry: () => createInMemoryProcessRegistry2,
|
|
39437
38977
|
createCfFileSystem: () => createCfFileSystem2,
|
|
39438
|
-
configSchema: () =>
|
|
38978
|
+
configSchema: () => configSchema2,
|
|
39439
38979
|
cloudflareWorkersFactory: () => cloudflareWorkersFactory2,
|
|
39440
38980
|
buildConfigFromYaml: () => buildConfigFromYaml,
|
|
39441
38981
|
buildConfigFromObject: () => buildConfigFromObject2,
|
|
@@ -39475,6 +39015,481 @@ var init_dist5 = __esm(() => {
|
|
|
39475
39015
|
init_types2();
|
|
39476
39016
|
});
|
|
39477
39017
|
|
|
39018
|
+
// ../../packages/config/src/finding-codes.ts
|
|
39019
|
+
function isFindingCode(code) {
|
|
39020
|
+
return ALL_FINDING_CODES.includes(code);
|
|
39021
|
+
}
|
|
39022
|
+
var ALL_FINDING_CODES, FINDING_CODES;
|
|
39023
|
+
var init_finding_codes = __esm(() => {
|
|
39024
|
+
ALL_FINDING_CODES = [
|
|
39025
|
+
"L1.markdown-parse",
|
|
39026
|
+
"L1.schema-validation",
|
|
39027
|
+
"L2.missing-required-section",
|
|
39028
|
+
"L2.forbidden-section",
|
|
39029
|
+
"L2.disallowed-section",
|
|
39030
|
+
"L2.heading-level",
|
|
39031
|
+
"L2.section-order",
|
|
39032
|
+
"L3.requirements-format",
|
|
39033
|
+
"L3.requirements-checkbox",
|
|
39034
|
+
"L3.requirements-empty",
|
|
39035
|
+
"L3.ac-empty",
|
|
39036
|
+
"L3.ac-requirement-coverage",
|
|
39037
|
+
"L3.solution-file-line",
|
|
39038
|
+
"L3.review-priority-table",
|
|
39039
|
+
"L3.testing-coverage",
|
|
39040
|
+
"L3.required-section-placeholder",
|
|
39041
|
+
"L3.plan-format",
|
|
39042
|
+
"L3.unchecked-checklist",
|
|
39043
|
+
"L3.ac-checklist-text",
|
|
39044
|
+
"L3.ac-bdd-error",
|
|
39045
|
+
"L3.ac-bdd-warning",
|
|
39046
|
+
"L3.ac-bdd-invalid",
|
|
39047
|
+
"L3.scope-delineation",
|
|
39048
|
+
"L3.one-active-goal",
|
|
39049
|
+
"L3.children-limit",
|
|
39050
|
+
"L4.design-placeholder",
|
|
39051
|
+
"L4.feature-not-found",
|
|
39052
|
+
"L4.feature-terminal",
|
|
39053
|
+
"L4.missing-feature-id",
|
|
39054
|
+
"L4.parent-not-found",
|
|
39055
|
+
"L4.dependency-not-found",
|
|
39056
|
+
"L4.rollup-subtasks-open",
|
|
39057
|
+
"L4.rollup-parent-open",
|
|
39058
|
+
"L4.rollup-missing-roster",
|
|
39059
|
+
"L4.readiness-blocked",
|
|
39060
|
+
"L4.prose-prerequisite-unlisted",
|
|
39061
|
+
"L4.prerequisite-cycle",
|
|
39062
|
+
"L4.prerequisite-not-done",
|
|
39063
|
+
"L4.gate-language",
|
|
39064
|
+
"L4.linked-task-parse-failed",
|
|
39065
|
+
"L4.orphan-scenarios",
|
|
39066
|
+
"L4.uncovered-task-scenario",
|
|
39067
|
+
"L4.uncovered-feature-scenario",
|
|
39068
|
+
"L4.verifying-incomplete-tasks",
|
|
39069
|
+
"L4.dogfood-missing",
|
|
39070
|
+
"L4.stale-line-anchor",
|
|
39071
|
+
"L4.anchor-subject-mismatch",
|
|
39072
|
+
"L4.malformed-verdict-artifact",
|
|
39073
|
+
"L4.scenario-unverified",
|
|
39074
|
+
"L4.testing-verdict-stub",
|
|
39075
|
+
"L4.evidence-not-recoverable"
|
|
39076
|
+
];
|
|
39077
|
+
FINDING_CODES = {
|
|
39078
|
+
L1_MARKDOWN_PARSE: "L1.markdown-parse",
|
|
39079
|
+
L1_SCHEMA_VALIDATION: "L1.schema-validation",
|
|
39080
|
+
L2_MISSING_REQUIRED_SECTION: "L2.missing-required-section",
|
|
39081
|
+
L2_FORBIDDEN_SECTION: "L2.forbidden-section",
|
|
39082
|
+
L2_DISALLOWED_SECTION: "L2.disallowed-section",
|
|
39083
|
+
L2_HEADING_LEVEL: "L2.heading-level",
|
|
39084
|
+
L2_SECTION_ORDER: "L2.section-order",
|
|
39085
|
+
L3_REQUIREMENTS_FORMAT: "L3.requirements-format",
|
|
39086
|
+
L3_REQUIREMENTS_CHECKBOX: "L3.requirements-checkbox",
|
|
39087
|
+
L3_REQUIREMENTS_EMPTY: "L3.requirements-empty",
|
|
39088
|
+
L3_AC_EMPTY: "L3.ac-empty",
|
|
39089
|
+
L3_AC_REQUIREMENT_COVERAGE: "L3.ac-requirement-coverage",
|
|
39090
|
+
L3_SOLUTION_FILE_LINE: "L3.solution-file-line",
|
|
39091
|
+
L3_REVIEW_PRIORITY_TABLE: "L3.review-priority-table",
|
|
39092
|
+
L3_TESTING_COVERAGE: "L3.testing-coverage",
|
|
39093
|
+
L3_REQUIRED_SECTION_PLACEHOLDER: "L3.required-section-placeholder",
|
|
39094
|
+
L3_PLAN_FORMAT: "L3.plan-format",
|
|
39095
|
+
L3_UNCHECKED_CHECKLIST: "L3.unchecked-checklist",
|
|
39096
|
+
L3_AC_CHECKLIST_TEXT: "L3.ac-checklist-text",
|
|
39097
|
+
L3_AC_BDD_ERROR: "L3.ac-bdd-error",
|
|
39098
|
+
L3_AC_BDD_WARNING: "L3.ac-bdd-warning",
|
|
39099
|
+
L3_AC_BDD_INVALID: "L3.ac-bdd-invalid",
|
|
39100
|
+
L3_SCOPE_DELINEATION: "L3.scope-delineation",
|
|
39101
|
+
L3_ONE_ACTIVE_GOAL: "L3.one-active-goal",
|
|
39102
|
+
L3_CHILDREN_LIMIT: "L3.children-limit",
|
|
39103
|
+
L4_DESIGN_PLACEHOLDER: "L4.design-placeholder",
|
|
39104
|
+
L4_FEATURE_NOT_FOUND: "L4.feature-not-found",
|
|
39105
|
+
L4_FEATURE_TERMINAL: "L4.feature-terminal",
|
|
39106
|
+
L4_MISSING_FEATURE_ID: "L4.missing-feature-id",
|
|
39107
|
+
L4_PARENT_NOT_FOUND: "L4.parent-not-found",
|
|
39108
|
+
L4_DEPENDENCY_NOT_FOUND: "L4.dependency-not-found",
|
|
39109
|
+
L4_ROLLUP_SUBTASKS_OPEN: "L4.rollup-subtasks-open",
|
|
39110
|
+
L4_ROLLUP_PARENT_OPEN: "L4.rollup-parent-open",
|
|
39111
|
+
L4_ROLLUP_MISSING_ROSTER: "L4.rollup-missing-roster",
|
|
39112
|
+
L4_READINESS_BLOCKED: "L4.readiness-blocked",
|
|
39113
|
+
L4_PROSE_PREREQUISITE_UNLISTED: "L4.prose-prerequisite-unlisted",
|
|
39114
|
+
L4_PREREQUISITE_CYCLE: "L4.prerequisite-cycle",
|
|
39115
|
+
L4_PREREQUISITE_NOT_DONE: "L4.prerequisite-not-done",
|
|
39116
|
+
L4_GATE_LANGUAGE: "L4.gate-language",
|
|
39117
|
+
L4_LINKED_TASK_PARSE_FAILED: "L4.linked-task-parse-failed",
|
|
39118
|
+
L4_ORPHAN_SCENARIOS: "L4.orphan-scenarios",
|
|
39119
|
+
L4_UNCOVERED_TASK_SCENARIO: "L4.uncovered-task-scenario",
|
|
39120
|
+
L4_UNCOVERED_FEATURE_SCENARIO: "L4.uncovered-feature-scenario",
|
|
39121
|
+
L4_DOGFOOD_MISSING: "L4.dogfood-missing",
|
|
39122
|
+
L4_VERIFYING_INCOMPLETE_TASKS: "L4.verifying-incomplete-tasks",
|
|
39123
|
+
L4_STALE_LINE_ANCHOR: "L4.stale-line-anchor",
|
|
39124
|
+
L4_ANCHOR_SUBJECT_MISMATCH: "L4.anchor-subject-mismatch",
|
|
39125
|
+
L4_MALFORMED_VERDICT_ARTIFACT: "L4.malformed-verdict-artifact",
|
|
39126
|
+
L4_SCENARIO_UNVERIFIED: "L4.scenario-unverified",
|
|
39127
|
+
L4_TESTING_VERDICT_STUB: "L4.testing-verdict-stub",
|
|
39128
|
+
L4_EVIDENCE_NOT_RECOVERABLE: "L4.evidence-not-recoverable"
|
|
39129
|
+
};
|
|
39130
|
+
});
|
|
39131
|
+
|
|
39132
|
+
// ../../packages/config/src/projects.ts
|
|
39133
|
+
import { homedir } from "os";
|
|
39134
|
+
import { join } from "path";
|
|
39135
|
+
function getProjectsFilePath() {
|
|
39136
|
+
if (process.env.SPUR_PROJECTS_FILE) {
|
|
39137
|
+
return process.env.SPUR_PROJECTS_FILE;
|
|
39138
|
+
}
|
|
39139
|
+
return join(homedir(), ".config", "spur", "projects.json");
|
|
39140
|
+
}
|
|
39141
|
+
var projectEntrySchema, projectsFileSchema;
|
|
39142
|
+
var init_projects = __esm(() => {
|
|
39143
|
+
init_zod();
|
|
39144
|
+
projectEntrySchema = exports_external.object({
|
|
39145
|
+
name: exports_external.string().min(1),
|
|
39146
|
+
path: exports_external.string().min(1),
|
|
39147
|
+
port: exports_external.number().int().nonnegative().default(0)
|
|
39148
|
+
});
|
|
39149
|
+
projectsFileSchema = exports_external.object({
|
|
39150
|
+
schema_version: exports_external.literal(1).default(1),
|
|
39151
|
+
projects: exports_external.array(projectEntrySchema).default([])
|
|
39152
|
+
});
|
|
39153
|
+
});
|
|
39154
|
+
|
|
39155
|
+
// ../../packages/config/src/index.ts
|
|
39156
|
+
function folderPathWithDefault(defaultPath) {
|
|
39157
|
+
return exports_external.preprocess((v) => v == null ? undefined : v, exports_external.string().default(defaultPath));
|
|
39158
|
+
}
|
|
39159
|
+
function normalizeExecutorTier(value) {
|
|
39160
|
+
return value === "capable" ? "capable-1" : value;
|
|
39161
|
+
}
|
|
39162
|
+
function normalizeMember(member) {
|
|
39163
|
+
return typeof member === "string" ? { executor: member } : { ...member };
|
|
39164
|
+
}
|
|
39165
|
+
function memberLocalId(member, roster, index2) {
|
|
39166
|
+
if (member.id !== undefined)
|
|
39167
|
+
return member.id;
|
|
39168
|
+
if (member.executor !== undefined)
|
|
39169
|
+
return member.executor;
|
|
39170
|
+
const role = member.role;
|
|
39171
|
+
if (role === undefined)
|
|
39172
|
+
return "";
|
|
39173
|
+
let n2 = 0;
|
|
39174
|
+
for (let i2 = 0;i2 <= index2; i2++) {
|
|
39175
|
+
const m = roster[i2];
|
|
39176
|
+
if (m !== undefined && m.id === undefined && m.executor === undefined && m.role === role)
|
|
39177
|
+
n2 += 1;
|
|
39178
|
+
}
|
|
39179
|
+
return `${role}-${n2}`;
|
|
39180
|
+
}
|
|
39181
|
+
function resolveExecutor(name, agentConfig, opts) {
|
|
39182
|
+
const exec = agentConfig?.executors?.find((entry) => entry.name === name);
|
|
39183
|
+
if (exec !== undefined)
|
|
39184
|
+
return { agent: exec.agent, model: exec.model };
|
|
39185
|
+
if (opts?.isCanonicalAgent === undefined || opts.isCanonicalAgent(name)) {
|
|
39186
|
+
return { agent: name };
|
|
39187
|
+
}
|
|
39188
|
+
throw new Error(`Unknown executor or agent reference: "${name}"`);
|
|
39189
|
+
}
|
|
39190
|
+
function resolveHistoryRefreshTrigger(config4) {
|
|
39191
|
+
const parsed = HistoryRefreshConfigSchema.parse(config4?.history?.refresh ?? {});
|
|
39192
|
+
return { onCompletion: parsed.on_completion, debounceMs: parsed.debounce_ms };
|
|
39193
|
+
}
|
|
39194
|
+
function misplacedGlobalKeys(parsed) {
|
|
39195
|
+
const misplaced = [];
|
|
39196
|
+
for (const key of PROJECT_SHAPED_GLOBAL_KEYS) {
|
|
39197
|
+
if (key in parsed)
|
|
39198
|
+
misplaced.push(key);
|
|
39199
|
+
}
|
|
39200
|
+
const agent = parsed.agent;
|
|
39201
|
+
if (typeof agent === "object" && agent !== null && "team" in agent) {
|
|
39202
|
+
misplaced.push("agent.team");
|
|
39203
|
+
}
|
|
39204
|
+
return misplaced;
|
|
39205
|
+
}
|
|
39206
|
+
function parseEnvBoolean(value) {
|
|
39207
|
+
if (value === undefined || value === "")
|
|
39208
|
+
return;
|
|
39209
|
+
const normalized = value.toLowerCase();
|
|
39210
|
+
if (["1", "true", "yes", "on"].includes(normalized))
|
|
39211
|
+
return true;
|
|
39212
|
+
if (["0", "false", "no", "off"].includes(normalized))
|
|
39213
|
+
return false;
|
|
39214
|
+
throw new Error(`Invalid boolean environment value: expected true/false, received ${value}`);
|
|
39215
|
+
}
|
|
39216
|
+
function buildConfigFromEnv(env = process.env) {
|
|
39217
|
+
return configSchema3.parse({
|
|
39218
|
+
database: {
|
|
39219
|
+
url: env[SPUR_ENV_VARS.databaseUrl]
|
|
39220
|
+
},
|
|
39221
|
+
server: {
|
|
39222
|
+
port: env[SPUR_ENV_VARS.port],
|
|
39223
|
+
host: env[SPUR_ENV_VARS.host]
|
|
39224
|
+
},
|
|
39225
|
+
telemetry: {
|
|
39226
|
+
enabled: parseEnvBoolean(env.SPUR_TELEMETRY_ENABLED),
|
|
39227
|
+
endpoint: env.SPUR_TELEMETRY_ENDPOINT
|
|
39228
|
+
},
|
|
39229
|
+
logging: {
|
|
39230
|
+
level: env.SPUR_LOG_LEVEL
|
|
39231
|
+
}
|
|
39232
|
+
});
|
|
39233
|
+
}
|
|
39234
|
+
var SPUR_ENV_VARS, SPUR_LOG_LEVELS, DEFAULT_TASKS_DIR = "docs/tasks", DEFAULT_FEATURES_DIR = "docs/features", DEFAULT_DATABASE_URL = ".spur/spur.db", IN_MEMORY_DATABASE_URL = ":memory:", folderConfigSchema, tasksConfigSchema, featuresConfigSchema, EXECUTOR_CAPABILITY_TIERS, executorCapabilityTierSchema, AGENT_ROLE_NAMES, DEFAULT_AGENT_ROLES, AgentExecutorConfigSchema, AgentRoleConfigSchema, AGENT_ID_REGEX, TeamMemberConfigSchema, TeamConfigSchema, AgentOutputConfigSchema, AgentConfigSchema, RulesConfigSchema, WorkflowsConfigSchema, WorkflowConfigSchema, RedactionConfigSchema, HistoryRefreshConfigSchema, HistoryConfigSchema, spurConfigSchema, PROJECT_SHAPED_GLOBAL_KEYS, configSchema3;
|
|
39235
|
+
var init_src = __esm(() => {
|
|
39236
|
+
init_zod();
|
|
39237
|
+
init_finding_codes();
|
|
39238
|
+
init_projects();
|
|
39239
|
+
SPUR_ENV_VARS = {
|
|
39240
|
+
nodeEnv: "NODE_ENV",
|
|
39241
|
+
port: "PORT",
|
|
39242
|
+
host: "HOST",
|
|
39243
|
+
publicApiUrl: "PUBLIC_API_URL",
|
|
39244
|
+
databaseUrl: "DATABASE_URL"
|
|
39245
|
+
};
|
|
39246
|
+
SPUR_LOG_LEVELS = ["debug", "info", "warn", "error"];
|
|
39247
|
+
folderConfigSchema = exports_external.object({
|
|
39248
|
+
baseCounter: exports_external.number().int().nonnegative().default(0),
|
|
39249
|
+
label: exports_external.string().optional()
|
|
39250
|
+
});
|
|
39251
|
+
tasksConfigSchema = exports_external.object({
|
|
39252
|
+
folders: exports_external.record(exports_external.string(), folderConfigSchema).default({}),
|
|
39253
|
+
active: folderPathWithDefault(DEFAULT_TASKS_DIR),
|
|
39254
|
+
severity: exports_external.record(exports_external.string(), exports_external.enum(["error", "warning", "off"])).optional()
|
|
39255
|
+
}).superRefine((data, ctx) => {
|
|
39256
|
+
if (data.severity) {
|
|
39257
|
+
for (const code of Object.keys(data.severity)) {
|
|
39258
|
+
if (!isFindingCode(code)) {
|
|
39259
|
+
ctx.addIssue({
|
|
39260
|
+
code: exports_external.ZodIssueCode.custom,
|
|
39261
|
+
path: ["severity", code],
|
|
39262
|
+
message: `Unknown finding code "${code}" in severity overrides map`
|
|
39263
|
+
});
|
|
39264
|
+
}
|
|
39265
|
+
}
|
|
39266
|
+
}
|
|
39267
|
+
});
|
|
39268
|
+
featuresConfigSchema = exports_external.object({
|
|
39269
|
+
dir: folderPathWithDefault(DEFAULT_FEATURES_DIR)
|
|
39270
|
+
});
|
|
39271
|
+
EXECUTOR_CAPABILITY_TIERS = ["cheap", "standard", "capable-1", "capable-2", "capable-3"];
|
|
39272
|
+
executorCapabilityTierSchema = exports_external.preprocess((value) => {
|
|
39273
|
+
if (value === undefined || value === null)
|
|
39274
|
+
return;
|
|
39275
|
+
return typeof value === "string" ? normalizeExecutorTier(value) : value;
|
|
39276
|
+
}, exports_external.enum(EXECUTOR_CAPABILITY_TIERS).optional());
|
|
39277
|
+
AGENT_ROLE_NAMES = ["scribe", "coder", "reviewer", "planner"];
|
|
39278
|
+
DEFAULT_AGENT_ROLES = new Map([
|
|
39279
|
+
["scribe", { tier: "cheap", stages: ["changelog"] }],
|
|
39280
|
+
["coder", { tier: "standard", stages: ["implement", "test", "wrap"] }],
|
|
39281
|
+
["reviewer", { tier: "capable-1", stages: ["verify", "review", "dogfood"] }],
|
|
39282
|
+
["planner", { tier: "capable-2", stages: ["plan", "refine", "brainstorm"] }]
|
|
39283
|
+
]);
|
|
39284
|
+
AgentExecutorConfigSchema = exports_external.object({
|
|
39285
|
+
name: exports_external.string().min(1),
|
|
39286
|
+
agent: exports_external.string().min(1),
|
|
39287
|
+
model: exports_external.string().min(1).optional(),
|
|
39288
|
+
tier: executorCapabilityTierSchema.optional()
|
|
39289
|
+
});
|
|
39290
|
+
AgentRoleConfigSchema = exports_external.object({
|
|
39291
|
+
tier: exports_external.enum(EXECUTOR_CAPABILITY_TIERS).optional(),
|
|
39292
|
+
stages: exports_external.array(exports_external.string().min(1)).min(1).optional()
|
|
39293
|
+
});
|
|
39294
|
+
AGENT_ID_REGEX = /^[a-z][a-z0-9_-]{1,63}$/;
|
|
39295
|
+
TeamMemberConfigSchema = exports_external.union([
|
|
39296
|
+
exports_external.string().min(1),
|
|
39297
|
+
exports_external.object({
|
|
39298
|
+
executor: exports_external.string().min(1).optional(),
|
|
39299
|
+
id: exports_external.string().min(1).optional(),
|
|
39300
|
+
role: exports_external.enum(AGENT_ROLE_NAMES, {
|
|
39301
|
+
error: (issue2) => new Error(`Unknown role "${issue2.input}" \u2014 expected one of: ${AGENT_ROLE_NAMES.join(", ")}`)
|
|
39302
|
+
}).optional(),
|
|
39303
|
+
purpose: exports_external.string().optional(),
|
|
39304
|
+
workspace: exports_external.string().min(1).optional(),
|
|
39305
|
+
model: exports_external.string().min(1).optional(),
|
|
39306
|
+
autonomy: exports_external.string().optional(),
|
|
39307
|
+
systemPrompt: exports_external.string().optional(),
|
|
39308
|
+
command: exports_external.array(exports_external.string().min(1)).optional(),
|
|
39309
|
+
autostart: exports_external.boolean().optional()
|
|
39310
|
+
})
|
|
39311
|
+
]);
|
|
39312
|
+
TeamConfigSchema = exports_external.object({
|
|
39313
|
+
name: exports_external.string().min(1),
|
|
39314
|
+
work_dir: exports_external.string().min(1),
|
|
39315
|
+
autostart: exports_external.boolean().optional(),
|
|
39316
|
+
members: exports_external.array(TeamMemberConfigSchema).min(1)
|
|
39317
|
+
});
|
|
39318
|
+
AgentOutputConfigSchema = exports_external.object({
|
|
39319
|
+
"max-bytes": exports_external.number().int().positive().optional(),
|
|
39320
|
+
"max-lines": exports_external.number().int().positive().optional()
|
|
39321
|
+
});
|
|
39322
|
+
AgentConfigSchema = exports_external.object({
|
|
39323
|
+
default: exports_external.string().optional(),
|
|
39324
|
+
executors: exports_external.array(AgentExecutorConfigSchema).optional(),
|
|
39325
|
+
roles: exports_external.record(exports_external.string(), AgentRoleConfigSchema).optional(),
|
|
39326
|
+
team: exports_external.record(exports_external.string(), TeamConfigSchema).optional(),
|
|
39327
|
+
output: AgentOutputConfigSchema.optional(),
|
|
39328
|
+
sessionAffinity: exports_external.boolean().optional()
|
|
39329
|
+
}).superRefine((value, ctx) => {
|
|
39330
|
+
for (const key of Object.keys(value.roles ?? {})) {
|
|
39331
|
+
if (!AGENT_ROLE_NAMES.includes(key)) {
|
|
39332
|
+
ctx.addIssue({
|
|
39333
|
+
code: exports_external.ZodIssueCode.custom,
|
|
39334
|
+
path: ["roles", key],
|
|
39335
|
+
message: `Unknown role "${key}" \u2014 expected one of: ${AGENT_ROLE_NAMES.join(", ")}`
|
|
39336
|
+
});
|
|
39337
|
+
}
|
|
39338
|
+
}
|
|
39339
|
+
const executors = value.executors;
|
|
39340
|
+
const executorNames = new Set;
|
|
39341
|
+
if (executors !== undefined) {
|
|
39342
|
+
const seen = new Set;
|
|
39343
|
+
for (const [index2, executor] of executors.entries()) {
|
|
39344
|
+
if (seen.has(executor.name)) {
|
|
39345
|
+
ctx.addIssue({
|
|
39346
|
+
code: exports_external.ZodIssueCode.custom,
|
|
39347
|
+
message: `Duplicate executor name: ${executor.name}`,
|
|
39348
|
+
path: ["executors", index2, "name"]
|
|
39349
|
+
});
|
|
39350
|
+
}
|
|
39351
|
+
if (executor.name === "inline" || executor.name === "auto") {
|
|
39352
|
+
ctx.addIssue({
|
|
39353
|
+
code: exports_external.ZodIssueCode.custom,
|
|
39354
|
+
message: `Executor name "${executor.name}" is reserved (the --agent selector value '${executor.name}' has fixed semantics); rename executor at index ${index2}.`,
|
|
39355
|
+
path: ["executors", index2, "name"]
|
|
39356
|
+
});
|
|
39357
|
+
}
|
|
39358
|
+
if (AGENT_ROLE_NAMES.includes(executor.name)) {
|
|
39359
|
+
ctx.addIssue({
|
|
39360
|
+
code: exports_external.ZodIssueCode.custom,
|
|
39361
|
+
message: `Executor name "${executor.name}" collides with the role selector namespace ("${executor.name}"); rename executor at index ${index2}.`,
|
|
39362
|
+
path: ["executors", index2, "name"]
|
|
39363
|
+
});
|
|
39364
|
+
}
|
|
39365
|
+
seen.add(executor.name);
|
|
39366
|
+
executorNames.add(executor.name);
|
|
39367
|
+
}
|
|
39368
|
+
}
|
|
39369
|
+
const team = value.team;
|
|
39370
|
+
if (team === undefined)
|
|
39371
|
+
return;
|
|
39372
|
+
const seenComposed = new Set;
|
|
39373
|
+
for (const [teamId, teamConfig] of Object.entries(team)) {
|
|
39374
|
+
const seenLocal = new Set;
|
|
39375
|
+
const members = teamConfig.members.map(normalizeMember);
|
|
39376
|
+
members.forEach((ref, index2) => {
|
|
39377
|
+
if (ref.executor === undefined && ref.role === undefined) {
|
|
39378
|
+
ctx.addIssue({
|
|
39379
|
+
code: exports_external.ZodIssueCode.custom,
|
|
39380
|
+
message: `Team member at index ${index2} in team "${teamId}" declares neither role nor executor \u2014 at least one of role or executor is required.`,
|
|
39381
|
+
path: ["team", teamId, "members", index2]
|
|
39382
|
+
});
|
|
39383
|
+
return;
|
|
39384
|
+
}
|
|
39385
|
+
const localId = memberLocalId(ref, members, index2);
|
|
39386
|
+
if (seenLocal.has(localId)) {
|
|
39387
|
+
ctx.addIssue({
|
|
39388
|
+
code: exports_external.ZodIssueCode.custom,
|
|
39389
|
+
message: `Duplicate team member id: ${localId} in team "${teamId}"`,
|
|
39390
|
+
path: ["team", teamId, "members", index2]
|
|
39391
|
+
});
|
|
39392
|
+
}
|
|
39393
|
+
seenLocal.add(localId);
|
|
39394
|
+
const composedId = `${teamId}-${localId}`;
|
|
39395
|
+
if (!AGENT_ID_REGEX.test(composedId)) {
|
|
39396
|
+
ctx.addIssue({
|
|
39397
|
+
code: exports_external.ZodIssueCode.custom,
|
|
39398
|
+
message: `Invalid composed agent id "${composedId}": team key "${teamId}" + member "${localId}" must match ^[a-z][a-z0-9_-]{1,63}$ (2-64 chars, lowercase).`,
|
|
39399
|
+
path: ["team", teamId, "members", index2]
|
|
39400
|
+
});
|
|
39401
|
+
}
|
|
39402
|
+
if (seenComposed.has(composedId)) {
|
|
39403
|
+
ctx.addIssue({
|
|
39404
|
+
code: exports_external.ZodIssueCode.custom,
|
|
39405
|
+
message: `Composed agent id "${composedId}" collides across teams \u2014 every <teamId>-<localId> must be globally unique (a hyphenated team key can overlap another team's member id).`,
|
|
39406
|
+
path: ["team", teamId, "members", index2]
|
|
39407
|
+
});
|
|
39408
|
+
}
|
|
39409
|
+
seenComposed.add(composedId);
|
|
39410
|
+
if (ref.id !== undefined && AGENT_ROLE_NAMES.includes(ref.id)) {
|
|
39411
|
+
ctx.addIssue({
|
|
39412
|
+
code: exports_external.ZodIssueCode.custom,
|
|
39413
|
+
message: `Team member id "${ref.id}" collides with the role selector namespace ("${ref.id}") in team "${teamId}"; rename the member id.`,
|
|
39414
|
+
path: ["team", teamId, "members", index2]
|
|
39415
|
+
});
|
|
39416
|
+
}
|
|
39417
|
+
if (ref.id !== undefined && executorNames.has(ref.id)) {
|
|
39418
|
+
ctx.addIssue({
|
|
39419
|
+
code: exports_external.ZodIssueCode.custom,
|
|
39420
|
+
message: `Team member id "${ref.id}" collides with executor name "${ref.id}" in team "${teamId}"; the --agent selector namespace must be pairwise disjoint.`,
|
|
39421
|
+
path: ["team", teamId, "members", index2]
|
|
39422
|
+
});
|
|
39423
|
+
}
|
|
39424
|
+
if (executorNames.has(composedId)) {
|
|
39425
|
+
ctx.addIssue({
|
|
39426
|
+
code: exports_external.ZodIssueCode.custom,
|
|
39427
|
+
message: `Composed agent id "${composedId}" collides with executor name "${composedId}"; the --agent selector namespace must be pairwise disjoint.`,
|
|
39428
|
+
path: ["team", teamId, "members", index2]
|
|
39429
|
+
});
|
|
39430
|
+
}
|
|
39431
|
+
if (AGENT_ROLE_NAMES.includes(composedId)) {
|
|
39432
|
+
ctx.addIssue({
|
|
39433
|
+
code: exports_external.ZodIssueCode.custom,
|
|
39434
|
+
message: `Composed agent id "${composedId}" collides with the role selector namespace ("${composedId}"); the --agent selector namespace must be pairwise disjoint.`,
|
|
39435
|
+
path: ["team", teamId, "members", index2]
|
|
39436
|
+
});
|
|
39437
|
+
}
|
|
39438
|
+
});
|
|
39439
|
+
}
|
|
39440
|
+
});
|
|
39441
|
+
RulesConfigSchema = exports_external.object({
|
|
39442
|
+
paths: exports_external.array(exports_external.string()).optional()
|
|
39443
|
+
});
|
|
39444
|
+
WorkflowsConfigSchema = exports_external.object({
|
|
39445
|
+
paths: exports_external.array(exports_external.string()).optional()
|
|
39446
|
+
});
|
|
39447
|
+
WorkflowConfigSchema = exports_external.object({
|
|
39448
|
+
logRetentionDays: exports_external.number().int().positive().default(30)
|
|
39449
|
+
});
|
|
39450
|
+
RedactionConfigSchema = exports_external.object({
|
|
39451
|
+
enabled: exports_external.boolean().optional()
|
|
39452
|
+
});
|
|
39453
|
+
HistoryRefreshConfigSchema = exports_external.object({
|
|
39454
|
+
on_completion: exports_external.boolean().default(false),
|
|
39455
|
+
debounce_ms: exports_external.number().int().min(1000).default(600000)
|
|
39456
|
+
});
|
|
39457
|
+
HistoryConfigSchema = exports_external.object({
|
|
39458
|
+
refresh: HistoryRefreshConfigSchema.optional()
|
|
39459
|
+
});
|
|
39460
|
+
spurConfigSchema = exports_external.object({
|
|
39461
|
+
version: exports_external.string().optional(),
|
|
39462
|
+
name: exports_external.string().optional(),
|
|
39463
|
+
agent: AgentConfigSchema.optional(),
|
|
39464
|
+
rules: RulesConfigSchema.optional(),
|
|
39465
|
+
workflows: WorkflowsConfigSchema.optional(),
|
|
39466
|
+
workflow: WorkflowConfigSchema.optional(),
|
|
39467
|
+
redaction: RedactionConfigSchema.optional(),
|
|
39468
|
+
history: HistoryConfigSchema.optional(),
|
|
39469
|
+
tasks: tasksConfigSchema.optional(),
|
|
39470
|
+
features: featuresConfigSchema.optional()
|
|
39471
|
+
});
|
|
39472
|
+
PROJECT_SHAPED_GLOBAL_KEYS = ["name", "bootstrap", "rules", "redaction", "tasks", "features"];
|
|
39473
|
+
configSchema3 = exports_external.object({
|
|
39474
|
+
database: exports_external.object({
|
|
39475
|
+
url: exports_external.string().default(DEFAULT_DATABASE_URL)
|
|
39476
|
+
}).default({ url: DEFAULT_DATABASE_URL }),
|
|
39477
|
+
server: exports_external.object({
|
|
39478
|
+
port: exports_external.coerce.number().int().positive().default(3000),
|
|
39479
|
+
host: exports_external.string().default("localhost"),
|
|
39480
|
+
openBrowser: exports_external.boolean().default(true),
|
|
39481
|
+
webDistPath: exports_external.string().nullable().default(null)
|
|
39482
|
+
}).default({ port: 3000, host: "localhost", openBrowser: true, webDistPath: null }),
|
|
39483
|
+
telemetry: exports_external.object({
|
|
39484
|
+
enabled: exports_external.boolean().default(false),
|
|
39485
|
+
endpoint: exports_external.string().optional()
|
|
39486
|
+
}).default({ enabled: false }),
|
|
39487
|
+
logging: exports_external.object({
|
|
39488
|
+
level: exports_external.enum(SPUR_LOG_LEVELS).default("info")
|
|
39489
|
+
}).default({ level: "info" })
|
|
39490
|
+
});
|
|
39491
|
+
});
|
|
39492
|
+
|
|
39478
39493
|
// ../../packages/config/src/bundled-config.ts
|
|
39479
39494
|
import { existsSync as existsSync3, readdirSync as readdirSync3, statSync as statSync4 } from "fs";
|
|
39480
39495
|
import { dirname as dirname3, join as join2 } from "path";
|
|
@@ -39523,7 +39538,9 @@ function walk(dir, relPrefix, filter = /\.(ya?ml|json)$/i) {
|
|
|
39523
39538
|
function isDroppedFromProjectSeed(rel) {
|
|
39524
39539
|
if (rel === BUNDLED_GLOBAL_CONFIG)
|
|
39525
39540
|
return true;
|
|
39526
|
-
if (rel.startsWith("templates/
|
|
39541
|
+
if (rel.startsWith("templates/"))
|
|
39542
|
+
return true;
|
|
39543
|
+
if (rel.startsWith("workflows/"))
|
|
39527
39544
|
return true;
|
|
39528
39545
|
if (rel.startsWith("plugins/"))
|
|
39529
39546
|
return true;
|
|
@@ -39676,6 +39693,9 @@ async function readRawYamlLayer(configPath, kind) {
|
|
|
39676
39693
|
throw new Error(`Failed to parse ${kind} config ${configPath}: ${error51.message}`);
|
|
39677
39694
|
}
|
|
39678
39695
|
}
|
|
39696
|
+
function parseConfigYaml2(text3) {
|
|
39697
|
+
return $parse(text3) ?? {};
|
|
39698
|
+
}
|
|
39679
39699
|
function isPlainObject6(value) {
|
|
39680
39700
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
39681
39701
|
}
|
|
@@ -39718,21 +39738,20 @@ function mergeByKeyIdentity(globalItems, projectItems, identityOf, segments) {
|
|
|
39718
39738
|
const indexByIdentity = new Map;
|
|
39719
39739
|
for (const item of globalItems) {
|
|
39720
39740
|
const identity4 = identityOf(item);
|
|
39721
|
-
if (identity4
|
|
39722
|
-
|
|
39723
|
-
|
|
39724
|
-
merged.push(item);
|
|
39725
|
-
}
|
|
39741
|
+
if (identity4 !== undefined && !indexByIdentity.has(identity4))
|
|
39742
|
+
indexByIdentity.set(identity4, merged.length);
|
|
39743
|
+
merged.push(item);
|
|
39726
39744
|
}
|
|
39745
|
+
const matchedProjectIdentities = new Set;
|
|
39727
39746
|
for (const item of projectItems) {
|
|
39728
39747
|
const identity4 = identityOf(item);
|
|
39729
|
-
const existing = identity4 === undefined ? undefined : indexByIdentity.get(identity4);
|
|
39748
|
+
const existing = identity4 === undefined || matchedProjectIdentities.has(identity4) ? undefined : indexByIdentity.get(identity4);
|
|
39730
39749
|
if (existing === undefined) {
|
|
39731
|
-
if (identity4 !== undefined)
|
|
39732
|
-
indexByIdentity.set(identity4, merged.length);
|
|
39733
39750
|
merged.push(item);
|
|
39734
39751
|
continue;
|
|
39735
39752
|
}
|
|
39753
|
+
if (identity4 !== undefined)
|
|
39754
|
+
matchedProjectIdentities.add(identity4);
|
|
39736
39755
|
const base2 = merged[existing];
|
|
39737
39756
|
merged[existing] = isPlainObject6(base2) && isPlainObject6(item) ? mergeDeep(base2, item, [...segments, existing]) : item;
|
|
39738
39757
|
}
|
|
@@ -50252,6 +50271,53 @@ function selectorDigest(selector) {
|
|
|
50252
50271
|
var HISTORY_ARTIFACT_SCHEMA_VERSION = 1;
|
|
50253
50272
|
var init_artifact = () => {};
|
|
50254
50273
|
|
|
50274
|
+
// ../../packages/domain/src/analytics/artifact-digest.ts
|
|
50275
|
+
import { createHash as createHash2 } from "crypto";
|
|
50276
|
+
function canonicalize(value, key) {
|
|
50277
|
+
if (key === "generatedAt" || key === "validatedAt" || key === "baselineArtifactDigest")
|
|
50278
|
+
return null;
|
|
50279
|
+
if (Array.isArray(value)) {
|
|
50280
|
+
const raw = value.map((v) => JSON.stringify(canonicalize(v, "")));
|
|
50281
|
+
return RANKED_ARTIFACT_KEYS.has(key) ? raw : [...raw].sort();
|
|
50282
|
+
}
|
|
50283
|
+
if (value !== null && typeof value === "object") {
|
|
50284
|
+
const out = {};
|
|
50285
|
+
for (const k of Object.keys(value).sort()) {
|
|
50286
|
+
out[k] = canonicalize(value[k], k);
|
|
50287
|
+
}
|
|
50288
|
+
return out;
|
|
50289
|
+
}
|
|
50290
|
+
return value;
|
|
50291
|
+
}
|
|
50292
|
+
function semanticArtifactDigest(artifactJson) {
|
|
50293
|
+
const material = JSON.stringify(canonicalize(artifactJson, "root"));
|
|
50294
|
+
return createHash2("sha256").update(material).digest("hex");
|
|
50295
|
+
}
|
|
50296
|
+
var ARTIFACT_ARRAY_CLASSIFICATION, RANKED_ARTIFACT_KEYS;
|
|
50297
|
+
var init_artifact_digest = __esm(() => {
|
|
50298
|
+
ARTIFACT_ARRAY_CLASSIFICATION = {
|
|
50299
|
+
byTool: "ranked",
|
|
50300
|
+
bySession: "ranked",
|
|
50301
|
+
topStepsByTokens: "ranked",
|
|
50302
|
+
topStepsByDuration: "ranked",
|
|
50303
|
+
topSteps: "ranked",
|
|
50304
|
+
bottlenecks: "ranked",
|
|
50305
|
+
coverage: "set",
|
|
50306
|
+
daily: "set",
|
|
50307
|
+
loops: "set",
|
|
50308
|
+
warnings: "set",
|
|
50309
|
+
pairings: "set",
|
|
50310
|
+
ladderSnapshot: "set",
|
|
50311
|
+
stepSupport: "set",
|
|
50312
|
+
phases: "set",
|
|
50313
|
+
tools: "set",
|
|
50314
|
+
skills: "set",
|
|
50315
|
+
sources: "set",
|
|
50316
|
+
models: "set"
|
|
50317
|
+
};
|
|
50318
|
+
RANKED_ARTIFACT_KEYS = new Set(Object.entries(ARTIFACT_ARRAY_CLASSIFICATION).filter(([, kind]) => kind === "ranked").map(([key]) => key));
|
|
50319
|
+
});
|
|
50320
|
+
|
|
50255
50321
|
// ../../packages/domain/src/analytics/models.ts
|
|
50256
50322
|
function resolvePricing(model) {
|
|
50257
50323
|
if (model === undefined || model.length === 0)
|
|
@@ -50868,6 +50934,22 @@ async function bySession(db2, sel, top, opts) {
|
|
|
50868
50934
|
};
|
|
50869
50935
|
});
|
|
50870
50936
|
}
|
|
50937
|
+
async function selectionPopulation(db2, sel, opts) {
|
|
50938
|
+
const { where, params } = buildMessageWhere(sel);
|
|
50939
|
+
const folded = withMessageDedup(where);
|
|
50940
|
+
const sessionScoped = `${folded} AND m.session_id NOT IN ('', 'unknown', 'session')`;
|
|
50941
|
+
const wm = applyWatermarkToWhere(where, opts?.watermark);
|
|
50942
|
+
const wmSession = applyWatermarkToWhere(sessionScoped, opts?.watermark);
|
|
50943
|
+
const [sessionRow, toolRow] = await Promise.all([
|
|
50944
|
+
db2.queryFirst(`SELECT COUNT(DISTINCT m.session_id) AS n FROM history_message m ${wmSession.where} LIMIT ?`, ...params, ...wmSession.params, 1),
|
|
50945
|
+
db2.queryFirst(`SELECT COUNT(DISTINCT tc.tool_name) AS n
|
|
50946
|
+
FROM history_tool_call tc
|
|
50947
|
+
JOIN history_message m ON m.record_hash = tc.message_hash
|
|
50948
|
+
${wm.where}
|
|
50949
|
+
LIMIT ?`, ...params, ...wm.params, 1)
|
|
50950
|
+
]);
|
|
50951
|
+
return { sessions: sessionRow?.n ?? 0, tools: toolRow?.n ?? 0 };
|
|
50952
|
+
}
|
|
50871
50953
|
async function loops(db2, sel, opts) {
|
|
50872
50954
|
const { where, params } = buildMessageWhere(sel);
|
|
50873
50955
|
const wm = applyWatermarkToWhere(where, opts?.watermark);
|
|
@@ -52013,7 +52095,11 @@ function narrowArtifact(artifact, opts, artifactPath) {
|
|
|
52013
52095
|
narrowed = {
|
|
52014
52096
|
...artifact,
|
|
52015
52097
|
byTool: artifact.byTool.slice(0, top),
|
|
52016
|
-
bySession: artifact.bySession.slice(0, top)
|
|
52098
|
+
bySession: artifact.bySession.slice(0, top),
|
|
52099
|
+
population: artifact.population ? {
|
|
52100
|
+
...artifact.population,
|
|
52101
|
+
appliedTop: Math.min(top, artifact.population.appliedTop)
|
|
52102
|
+
} : undefined
|
|
52017
52103
|
};
|
|
52018
52104
|
}
|
|
52019
52105
|
parts.push(`top ${top}`);
|
|
@@ -52408,7 +52494,7 @@ function renderSessionSummary(artifact, derived) {
|
|
|
52408
52494
|
"",
|
|
52409
52495
|
"| Metric | Value |",
|
|
52410
52496
|
"| --- | --- |",
|
|
52411
|
-
`| Sessions | ${artifact.
|
|
52497
|
+
`| Sessions | ${fmtTopOf(artifact.population?.sessions, artifact.population?.appliedTop)} |`,
|
|
52412
52498
|
`| Wall-clock span | ${wall} |`,
|
|
52413
52499
|
`| Messages | ${t.messages.toLocaleString("en-US")} |`,
|
|
52414
52500
|
`| Tool calls | ${t.toolCalls.toLocaleString("en-US")} |`,
|
|
@@ -52633,23 +52719,38 @@ function renderBottlenecks(derived) {
|
|
|
52633
52719
|
}
|
|
52634
52720
|
function renderRawData(artifact) {
|
|
52635
52721
|
const s = artifact.selector;
|
|
52722
|
+
const p = artifact.population;
|
|
52636
52723
|
const lines = [
|
|
52637
52724
|
"## Raw Data",
|
|
52638
52725
|
"",
|
|
52639
52726
|
`- Selector: since=${s.since ?? "-"} until=${s.until ?? "-"} sources=${s.sources ? s.sources.join(",") : "all"} session=${s.sessionId ?? "-"} run=${s.runId ?? "-"} task=${s.taskWbs ?? "-"}`,
|
|
52640
|
-
`- Counts: ${
|
|
52727
|
+
`- Counts: ${fmtTopOf(p?.sessions, p?.appliedTop)} sessions \xB7 ${fmtTopOf(p?.tools, p?.appliedTop)} tools \xB7 ${p?.loops ?? artifact.loops.length} loops \xB7 ${p?.warnings ?? artifact.warnings.length} warnings`
|
|
52641
52728
|
];
|
|
52642
52729
|
if (artifact.warnings.length > 0) {
|
|
52643
|
-
lines.push(
|
|
52730
|
+
lines.push("- Warnings:");
|
|
52731
|
+
for (const w of artifact.warnings) {
|
|
52732
|
+
lines.push(` - ${w.code}${w.source !== undefined ? ` (${w.source})` : ""} \u2014 ${w.detail}`);
|
|
52733
|
+
}
|
|
52644
52734
|
}
|
|
52645
52735
|
if (artifact.coverage.length > 0) {
|
|
52646
|
-
lines.push("", "| Source | Status | Files | Messages | Tool calls | Unknown |", "| --- | --- | ---: | ---: | ---: | ---: |");
|
|
52736
|
+
lines.push("", "| Source | Status | Files | Messages | Tool calls | Unknown | Last imported | Parse err | Validation err |", "| --- | --- | ---: | ---: | ---: | ---: | --- | ---: | ---: |");
|
|
52647
52737
|
for (const c3 of artifact.coverage) {
|
|
52648
|
-
|
|
52738
|
+
const parseTrunc = c3.parseErrorSamples.length >= MAX_ERROR_SAMPLES ? " (truncated)" : "";
|
|
52739
|
+
const validationTrunc = c3.validationErrorSamples.length >= MAX_ERROR_SAMPLES ? " (truncated)" : "";
|
|
52740
|
+
lines.push(`| ${c3.source} | ${c3.status} | ${c3.files} | ${c3.messages} | ${c3.toolCalls} | ${c3.unknownRecords} | ${c3.lastImportedAt ?? "not available"} | ${c3.parseErrors}${parseTrunc} | ${c3.validationErrors}${validationTrunc} |`);
|
|
52649
52741
|
}
|
|
52650
52742
|
}
|
|
52651
52743
|
return lines;
|
|
52652
52744
|
}
|
|
52745
|
+
function fmtTopOf(population, appliedTop) {
|
|
52746
|
+
if (population === undefined) {
|
|
52747
|
+
return "not available";
|
|
52748
|
+
}
|
|
52749
|
+
if (appliedTop !== undefined && appliedTop < population) {
|
|
52750
|
+
return `top ${appliedTop} of ${population.toLocaleString("en-US")}`;
|
|
52751
|
+
}
|
|
52752
|
+
return population.toLocaleString("en-US");
|
|
52753
|
+
}
|
|
52653
52754
|
function fmtWall(ms) {
|
|
52654
52755
|
if (ms < 1000)
|
|
52655
52756
|
return `${Math.round(ms)}ms`;
|
|
@@ -52678,7 +52779,7 @@ function fmtToolDur(ms, bucket) {
|
|
|
52678
52779
|
const allUnmeasured = bucket.calls > 0 && bucket.durationUnmeasured === bucket.calls;
|
|
52679
52780
|
return allUnmeasured ? "n/a" : fmtDur(ms);
|
|
52680
52781
|
}
|
|
52681
|
-
var NOT_AVAILABLE_PER_STEP = "> not available - artifact predates the per-step sections (rerun `spur history analyze`)", NOT_AVAILABLE_DERIVED = "> not available \u2014 artifact has no derived block (rerun `spur history analyze`)";
|
|
52782
|
+
var NOT_AVAILABLE_PER_STEP = "> not available - artifact predates the per-step sections (rerun `spur history analyze`)", NOT_AVAILABLE_DERIVED = "> not available \u2014 artifact has no derived block (rerun `spur history analyze`)", MAX_ERROR_SAMPLES = 20;
|
|
52682
52783
|
var init_render_forensics = __esm(() => {
|
|
52683
52784
|
init_artifact();
|
|
52684
52785
|
init_render_report();
|
|
@@ -53477,6 +53578,7 @@ var init_run_cost = __esm(() => {
|
|
|
53477
53578
|
// ../../packages/domain/src/analytics/index.ts
|
|
53478
53579
|
var init_analytics = __esm(() => {
|
|
53479
53580
|
init_artifact();
|
|
53581
|
+
init_artifact_digest();
|
|
53480
53582
|
init_costs();
|
|
53481
53583
|
init_forensic_query();
|
|
53482
53584
|
init_models();
|
|
@@ -57396,7 +57498,7 @@ var init_dist7 = __esm(() => {
|
|
|
57396
57498
|
});
|
|
57397
57499
|
|
|
57398
57500
|
// ../../node_modules/.bun/@gobing-ai+ts-llm-jsonl-importer@0.4.42+f66f1d7f0d37c145/node_modules/@gobing-ai/ts-llm-jsonl-importer/dist/hash.js
|
|
57399
|
-
import { createHash as
|
|
57501
|
+
import { createHash as createHash3 } from "crypto";
|
|
57400
57502
|
function stableJson(value) {
|
|
57401
57503
|
if (Array.isArray(value)) {
|
|
57402
57504
|
return `[${value.map((entry) => entry === undefined ? "null" : stableJson(entry)).join(",")}]`;
|
|
@@ -57408,7 +57510,7 @@ function stableJson(value) {
|
|
|
57408
57510
|
return JSON.stringify(value) ?? "null";
|
|
57409
57511
|
}
|
|
57410
57512
|
function sha256(value) {
|
|
57411
|
-
return
|
|
57513
|
+
return createHash3("sha256").update(stableJson(value)).digest("hex");
|
|
57412
57514
|
}
|
|
57413
57515
|
var init_hash = () => {};
|
|
57414
57516
|
|
|
@@ -64434,9 +64536,9 @@ var init_db2 = __esm(() => {
|
|
|
64434
64536
|
});
|
|
64435
64537
|
|
|
64436
64538
|
// ../../packages/domain/src/envelope/fingerprint.ts
|
|
64437
|
-
import { createHash as
|
|
64539
|
+
import { createHash as createHash4 } from "crypto";
|
|
64438
64540
|
function computeContentHash(content) {
|
|
64439
|
-
return
|
|
64541
|
+
return createHash4("sha256").update(content, "utf-8").digest("hex");
|
|
64440
64542
|
}
|
|
64441
64543
|
var init_fingerprint = () => {};
|
|
64442
64544
|
|
|
@@ -65256,7 +65358,7 @@ function attributeWithoutTelemetry(layers, capturedLayers) {
|
|
|
65256
65358
|
}
|
|
65257
65359
|
|
|
65258
65360
|
// ../../packages/domain/src/envelope/invalidation.ts
|
|
65259
|
-
import { createHash as
|
|
65361
|
+
import { createHash as createHash5 } from "crypto";
|
|
65260
65362
|
function computeInvalidationFingerprint(trigger) {
|
|
65261
65363
|
if (trigger.kind === "tool-output")
|
|
65262
65364
|
return null;
|
|
@@ -65280,7 +65382,7 @@ function computeInvalidationFingerprint(trigger) {
|
|
|
65280
65382
|
default:
|
|
65281
65383
|
return null;
|
|
65282
65384
|
}
|
|
65283
|
-
return
|
|
65385
|
+
return createHash5("sha256").update(raw, "utf-8").digest("hex");
|
|
65284
65386
|
}
|
|
65285
65387
|
function checkLayerStale(layer, freshFingerprint) {
|
|
65286
65388
|
if (freshFingerprint === null) {
|
|
@@ -66588,7 +66690,9 @@ __export(exports_src, {
|
|
|
66588
66690
|
serializeStablePrefix: () => serializeStablePrefix,
|
|
66589
66691
|
serializeLayer: () => serializeLayer,
|
|
66590
66692
|
serializeEnvelope: () => serializeEnvelope,
|
|
66693
|
+
semanticArtifactDigest: () => semanticArtifactDigest,
|
|
66591
66694
|
selectorDigest: () => selectorDigest,
|
|
66695
|
+
selectionPopulation: () => selectionPopulation,
|
|
66592
66696
|
sectionMatrixSchema: () => sectionMatrixSchema,
|
|
66593
66697
|
scaffoldFeatureScenarios: () => scaffoldFeatureScenarios,
|
|
66594
66698
|
runRetention: () => runRetention,
|
|
@@ -66763,6 +66867,7 @@ __export(exports_src, {
|
|
|
66763
66867
|
ROUTING_SUMMARY_DEFAULT_WINDOW_MS: () => ROUTING_SUMMARY_DEFAULT_WINDOW_MS,
|
|
66764
66868
|
REPORT_MODES: () => REPORT_MODES,
|
|
66765
66869
|
REGISTERED_CANONICAL_STAGES: () => REGISTERED_CANONICAL_STAGES,
|
|
66870
|
+
RANKED_ARTIFACT_KEYS: () => RANKED_ARTIFACT_KEYS,
|
|
66766
66871
|
QUEUE_JOBS_SCHEMA_SQL: () => QUEUE_JOBS_SCHEMA_SQL,
|
|
66767
66872
|
PlanningEventDao: () => PlanningEventDao,
|
|
66768
66873
|
PhaseRunDao: () => PhaseRunDao,
|
|
@@ -66803,7 +66908,8 @@ __export(exports_src, {
|
|
|
66803
66908
|
ArtifactDao: () => ArtifactDao,
|
|
66804
66909
|
ActionRunDao: () => ActionRunDao,
|
|
66805
66910
|
AUTHORITY_LANES: () => AUTHORITY_LANES,
|
|
66806
|
-
ARTIFACT_DIRECTIONS: () => ARTIFACT_DIRECTIONS
|
|
66911
|
+
ARTIFACT_DIRECTIONS: () => ARTIFACT_DIRECTIONS,
|
|
66912
|
+
ARTIFACT_ARRAY_CLASSIFICATION: () => ARTIFACT_ARRAY_CLASSIFICATION
|
|
66807
66913
|
});
|
|
66808
66914
|
var init_src2 = __esm(() => {
|
|
66809
66915
|
init_db2();
|
|
@@ -67884,6 +67990,9 @@ class AgentService {
|
|
|
67884
67990
|
async doctor(args, deps) {
|
|
67885
67991
|
const executors = this.ctx.agentConfig?.executors;
|
|
67886
67992
|
const doctorRunner = deps?.doctorRunner ?? new DoctorRunner({ env: this.ctx.env, executors });
|
|
67993
|
+
if (this.ctx.rolesSource === "fallback" && !args.json) {
|
|
67994
|
+
this.ctx.output.error("agent.roles: no config layer defines a table \u2014 built-in DEFAULT_AGENT_ROLES fallback in effect");
|
|
67995
|
+
}
|
|
67887
67996
|
if (args.agent === undefined) {
|
|
67888
67997
|
const results2 = await doctorRunner.runAll();
|
|
67889
67998
|
return this.renderDoctor(results2, executors, args.json, args.agent);
|
|
@@ -67892,7 +68001,11 @@ class AgentService {
|
|
|
67892
68001
|
if (roleDef !== undefined) {
|
|
67893
68002
|
const resolved = await this.resolveRole(args.agent, roleDef.tier, doctorRunner);
|
|
67894
68003
|
if (!resolved.ok) {
|
|
67895
|
-
|
|
68004
|
+
if (args.json) {
|
|
68005
|
+
this.ctx.output.write(toJson({ error: { code: "agent-resolution", message: resolved.message } }));
|
|
68006
|
+
} else {
|
|
68007
|
+
this.ctx.output.error(resolved.message);
|
|
68008
|
+
}
|
|
67896
68009
|
return resolved.exitCode;
|
|
67897
68010
|
}
|
|
67898
68011
|
const results2 = [await doctorRunner.runOne(resolved.executor ?? resolved.agent)];
|
|
@@ -67915,7 +68028,7 @@ class AgentService {
|
|
|
67915
68028
|
const executor = executorByName.get(result.agent) ?? { name: result.agent, agent: result.agent };
|
|
67916
68029
|
return { ...result, capabilityTier: getExecutorTier(executor) };
|
|
67917
68030
|
});
|
|
67918
|
-
this.ctx.output.write(toJson({ agents: rows }));
|
|
68031
|
+
this.ctx.output.write(toJson({ agents: rows, rolesSource: this.ctx.rolesSource ?? "config" }));
|
|
67919
68032
|
} else if (agent !== undefined) {
|
|
67920
68033
|
this.ctx.output.write(renderDoctorDetail(results[0] ?? null));
|
|
67921
68034
|
} else {
|
|
@@ -67929,7 +68042,11 @@ class AgentService {
|
|
|
67929
68042
|
execution: this.defaultExecutionOptions(flags)
|
|
67930
68043
|
});
|
|
67931
68044
|
if (!outcome.ok) {
|
|
67932
|
-
|
|
68045
|
+
if (booleanFlag(flags, "json")) {
|
|
68046
|
+
this.ctx.output.write(toJson({ error: { code: "agent-resolution", message: outcome.message } }));
|
|
68047
|
+
} else {
|
|
68048
|
+
this.ctx.output.error(outcome.message);
|
|
68049
|
+
}
|
|
67933
68050
|
return outcome.exitCode;
|
|
67934
68051
|
}
|
|
67935
68052
|
const result = outcome.result;
|
|
@@ -69847,6 +69964,294 @@ var init_planning_check_base = __esm(() => {
|
|
|
69847
69964
|
init_structural_repair();
|
|
69848
69965
|
});
|
|
69849
69966
|
|
|
69967
|
+
// ../../packages/app/src/services/task-record.ts
|
|
69968
|
+
function escapeTablePipe(s2) {
|
|
69969
|
+
return s2.replace(/\|/g, "\\|");
|
|
69970
|
+
}
|
|
69971
|
+
function parseVerdict(raw, fallbackWbs) {
|
|
69972
|
+
const parsed = parseVerifyVerdict(raw, fallbackWbs);
|
|
69973
|
+
if (parsed.kind === "valid")
|
|
69974
|
+
return parsed.verdict;
|
|
69975
|
+
return { wbs: fallbackWbs ?? "", verdict: "UNKNOWN", requirements: [], acceptanceCriteria: [], checks: [] };
|
|
69976
|
+
}
|
|
69977
|
+
async function readVerdict(fs3, path9, fallbackWbs) {
|
|
69978
|
+
let raw;
|
|
69979
|
+
try {
|
|
69980
|
+
raw = await fs3.readFile(path9);
|
|
69981
|
+
} catch {
|
|
69982
|
+
return { wbs: fallbackWbs ?? "", verdict: "UNKNOWN", requirements: [], acceptanceCriteria: [], checks: [] };
|
|
69983
|
+
}
|
|
69984
|
+
return parseVerdict(raw, fallbackWbs);
|
|
69985
|
+
}
|
|
69986
|
+
function renderTesting(v) {
|
|
69987
|
+
const lines = [];
|
|
69988
|
+
lines.push("**Pipeline verify results**");
|
|
69989
|
+
lines.push("");
|
|
69990
|
+
lines.push(`- Verdict: ${v.verdict} (from verdict artifact)`);
|
|
69991
|
+
lines.push("");
|
|
69992
|
+
if (v.requirements.length === 0) {
|
|
69993
|
+
lines.push("| Requirement | Status | Evidence |");
|
|
69994
|
+
lines.push("|-------------|--------|----------|");
|
|
69995
|
+
lines.push(`| \u2014 | \u2014 | No requirements recorded; verify verdict ${v.verdict} |`);
|
|
69996
|
+
} else {
|
|
69997
|
+
lines.push("| Requirement | Status | Evidence |");
|
|
69998
|
+
lines.push("|-------------|--------|----------|");
|
|
69999
|
+
for (const req of v.requirements) {
|
|
70000
|
+
const evidence = escapeTablePipe(req.evidence.replace(/\n/g, " "));
|
|
70001
|
+
lines.push(`| ${req.id} | ${req.status} | ${evidence} |`);
|
|
70002
|
+
}
|
|
70003
|
+
}
|
|
70004
|
+
if (v.acceptanceCriteria.length > 0) {
|
|
70005
|
+
lines.push("");
|
|
70006
|
+
lines.push("| Acceptance Criteria | Status | Evidence Type | Evidence |");
|
|
70007
|
+
lines.push("|---------------------|--------|---------------|----------|");
|
|
70008
|
+
for (const ac of v.acceptanceCriteria) {
|
|
70009
|
+
const evidence = escapeTablePipe(ac.evidence.replace(/\n/g, " "));
|
|
70010
|
+
lines.push(`| ${ac.id} | ${ac.status} | ${ac.evidenceType} | ${evidence} |`);
|
|
70011
|
+
}
|
|
70012
|
+
}
|
|
70013
|
+
lines.push("- Coverage: N/A (verdict-based; verify pipeline does not measure code coverage)");
|
|
70014
|
+
return lines.join(`
|
|
70015
|
+
`);
|
|
70016
|
+
}
|
|
70017
|
+
function parseTesting(markdown, wbs) {
|
|
70018
|
+
const section = extractTestingSection(markdown);
|
|
70019
|
+
if (section === null || section.trim() === "")
|
|
70020
|
+
return { kind: "missing", wbs };
|
|
70021
|
+
return parseTestingBody(section, wbs);
|
|
70022
|
+
}
|
|
70023
|
+
function extractTestingSection(markdown) {
|
|
70024
|
+
const heading = /^#{1,6}\s+Testing\s*$/m.exec(markdown);
|
|
70025
|
+
if (!heading || heading.index === undefined) {
|
|
70026
|
+
const taskDocument = /^##\s+\d+\.\s+|^###\s+(?:Background|Requirements|Acceptance Criteria|Q&A|Design|Plan|Solution|Review|References|History|Notes)\s*$/m.test(markdown);
|
|
70027
|
+
return taskDocument ? null : markdown;
|
|
70028
|
+
}
|
|
70029
|
+
const level = heading[0].match(/^#+/)?.[0]?.length ?? 2;
|
|
70030
|
+
const bodyStart = heading.index + heading[0].length;
|
|
70031
|
+
const rest = markdown.slice(bodyStart);
|
|
70032
|
+
const next = new RegExp(`^#{1,${level}}\\s+\\S`, "m").exec(rest);
|
|
70033
|
+
return next && next.index !== undefined ? rest.slice(0, next.index) : rest;
|
|
70034
|
+
}
|
|
70035
|
+
function parseTestingBody(body, wbs) {
|
|
70036
|
+
const lines = body.split(`
|
|
70037
|
+
`);
|
|
70038
|
+
const verdict = parseVerdictLine(lines);
|
|
70039
|
+
const requirements = parseCoverageTable(lines, "requirement");
|
|
70040
|
+
const acceptanceCriteria = parseCoverageTable(lines, "acceptance");
|
|
70041
|
+
if (requirements.kind === "malformed" || acceptanceCriteria.kind === "malformed") {
|
|
70042
|
+
return {
|
|
70043
|
+
kind: "malformed",
|
|
70044
|
+
wbs,
|
|
70045
|
+
message: `${requirements.kind === "malformed" ? "requirement" : "acceptance-criteria"} table is truncated or malformed`
|
|
70046
|
+
};
|
|
70047
|
+
}
|
|
70048
|
+
const rows = requirements.rows.length + acceptanceCriteria.rows.length;
|
|
70049
|
+
if (rows === 0) {
|
|
70050
|
+
const reason = verdict !== null ? "Verdict line present but no parseable coverage rows" : "no recognisable coverage rows";
|
|
70051
|
+
return { kind: "invalid", wbs, reason };
|
|
70052
|
+
}
|
|
70053
|
+
const aggregate2 = verdict ?? aggregateVerifyVerdict({ requirements: requirements.rows, acceptanceCriteria: acceptanceCriteria.rows });
|
|
70054
|
+
return {
|
|
70055
|
+
kind: "valid",
|
|
70056
|
+
wbs,
|
|
70057
|
+
verdict: {
|
|
70058
|
+
wbs,
|
|
70059
|
+
verdict: aggregate2,
|
|
70060
|
+
requirements: requirements.rows,
|
|
70061
|
+
acceptanceCriteria: acceptanceCriteria.rows,
|
|
70062
|
+
checks: []
|
|
70063
|
+
}
|
|
70064
|
+
};
|
|
70065
|
+
}
|
|
70066
|
+
function parseVerdictLine(lines) {
|
|
70067
|
+
for (const line of lines) {
|
|
70068
|
+
const m = /^(?:-\s*|\*\*)?Verdict:\s*(PASS|PARTIAL|FAIL|UNKNOWN)\b/i.exec(line.trim());
|
|
70069
|
+
if (m) {
|
|
70070
|
+
const v = m[1]?.toUpperCase();
|
|
70071
|
+
if (v === "PASS" || v === "PARTIAL" || v === "FAIL" || v === "UNKNOWN")
|
|
70072
|
+
return v;
|
|
70073
|
+
}
|
|
70074
|
+
}
|
|
70075
|
+
return null;
|
|
70076
|
+
}
|
|
70077
|
+
function parseCoverageTable(lines, kind) {
|
|
70078
|
+
const rows = [];
|
|
70079
|
+
const headerRe = kind === "requirement" ? /^\|\s*(Requirement|Req|R#)\s*\|/i : /^\|\s*(Acceptance Criteria|AC)\s*\|/i;
|
|
70080
|
+
let colStatus = -1;
|
|
70081
|
+
let colEvidence = -1;
|
|
70082
|
+
let colEvidenceType = -1;
|
|
70083
|
+
let columnCount = -1;
|
|
70084
|
+
let inTable = false;
|
|
70085
|
+
for (const rawLine of lines) {
|
|
70086
|
+
const line = rawLine.trim();
|
|
70087
|
+
if (!line.startsWith("|")) {
|
|
70088
|
+
inTable = false;
|
|
70089
|
+
continue;
|
|
70090
|
+
}
|
|
70091
|
+
const cells = splitTableRow(line);
|
|
70092
|
+
if (cells.length === 0)
|
|
70093
|
+
continue;
|
|
70094
|
+
if (cells.every((c3) => /^[-: ]*$/.test(c3))) {
|
|
70095
|
+
if (inTable && cells.length !== columnCount) {
|
|
70096
|
+
return { kind: "malformed", rows };
|
|
70097
|
+
}
|
|
70098
|
+
continue;
|
|
70099
|
+
}
|
|
70100
|
+
if (!inTable) {
|
|
70101
|
+
if (headerRe.test(line)) {
|
|
70102
|
+
inTable = true;
|
|
70103
|
+
colStatus = cells.findIndex((c3) => /status/i.test(c3));
|
|
70104
|
+
colEvidenceType = cells.findIndex((c3) => /evidence type/i.test(c3));
|
|
70105
|
+
colEvidence = cells.findIndex((c3) => /evidence/i.test(c3) && !/type/i.test(c3));
|
|
70106
|
+
columnCount = cells.length;
|
|
70107
|
+
if (colStatus < 0 || colEvidence < 0 || kind === "acceptance" && colEvidenceType < 0) {
|
|
70108
|
+
return { kind: "malformed", rows };
|
|
70109
|
+
}
|
|
70110
|
+
}
|
|
70111
|
+
continue;
|
|
70112
|
+
}
|
|
70113
|
+
if (cells.length < columnCount) {
|
|
70114
|
+
return { kind: "malformed", rows };
|
|
70115
|
+
}
|
|
70116
|
+
const extraIdCells = cells.length - columnCount;
|
|
70117
|
+
const shifted = (column2) => column2 + extraIdCells;
|
|
70118
|
+
const id = cells.slice(0, extraIdCells + 1).join("|").trim();
|
|
70119
|
+
const statusCell = (cells[shifted(colStatus)] ?? "").trim();
|
|
70120
|
+
if (id === "\u2014" && statusCell === "\u2014")
|
|
70121
|
+
continue;
|
|
70122
|
+
const status = parseRowStatus(statusCell);
|
|
70123
|
+
if (id === "" || status === null)
|
|
70124
|
+
return { kind: "malformed", rows };
|
|
70125
|
+
const evidence = unescapeTablePipe((cells[shifted(colEvidence)] ?? "").trim());
|
|
70126
|
+
rows.push({
|
|
70127
|
+
id,
|
|
70128
|
+
status,
|
|
70129
|
+
evidenceType: kind === "acceptance" ? (cells[shifted(colEvidenceType)] ?? "").trim() : "",
|
|
70130
|
+
evidence
|
|
70131
|
+
});
|
|
70132
|
+
}
|
|
70133
|
+
return { kind: "ok", rows };
|
|
70134
|
+
}
|
|
70135
|
+
function parseRowStatus(raw) {
|
|
70136
|
+
const status = raw.toUpperCase().trim();
|
|
70137
|
+
return ROW_STATUSES.includes(status) ? status : null;
|
|
70138
|
+
}
|
|
70139
|
+
function splitTableRow(line) {
|
|
70140
|
+
const body = line.replace(/^\|/, "").replace(/\|$/, "");
|
|
70141
|
+
const cells = [];
|
|
70142
|
+
let cur = "";
|
|
70143
|
+
for (const ch of body) {
|
|
70144
|
+
if (ch === "|" && !cur.endsWith("\\")) {
|
|
70145
|
+
cells.push(cur);
|
|
70146
|
+
cur = "";
|
|
70147
|
+
continue;
|
|
70148
|
+
}
|
|
70149
|
+
cur += ch;
|
|
70150
|
+
}
|
|
70151
|
+
cells.push(cur);
|
|
70152
|
+
return cells;
|
|
70153
|
+
}
|
|
70154
|
+
function unescapeTablePipe(s2) {
|
|
70155
|
+
return s2.replace(/\\\|/g, "|");
|
|
70156
|
+
}
|
|
70157
|
+
function renderReview(v) {
|
|
70158
|
+
const lines = [];
|
|
70159
|
+
lines.push(`**SECU findings** (pipeline verify step \u2014 verdict: ${v.verdict})`);
|
|
70160
|
+
lines.push("");
|
|
70161
|
+
lines.push("| Priority | Dimension | Location | Finding |");
|
|
70162
|
+
lines.push("|----------|-----------|----------|----------|");
|
|
70163
|
+
if (v.checks.length === 0) {
|
|
70164
|
+
lines.push(`| P4 | \u2014 | \u2014 | No P1\u2013P3 findings; verify verdict ${v.verdict} |`);
|
|
70165
|
+
} else {
|
|
70166
|
+
for (const check2 of v.checks) {
|
|
70167
|
+
const finding = escapeTablePipe(check2.evidence.replace(/\n/g, " "));
|
|
70168
|
+
const priority = /^P[1-4]$/.test(check2.status) ? check2.status : check2.status === "fail" ? "P1" : "P4";
|
|
70169
|
+
lines.push(`| ${priority} | ${check2.name} | \u2014 | ${finding} |`);
|
|
70170
|
+
}
|
|
70171
|
+
}
|
|
70172
|
+
lines.push("");
|
|
70173
|
+
return lines.join(`
|
|
70174
|
+
`);
|
|
70175
|
+
}
|
|
70176
|
+
function renderSolutionFromDiff(diffText) {
|
|
70177
|
+
const lines = [];
|
|
70178
|
+
lines.push("Change-map (auto-generated \u2014 implement step did not record a Solution).");
|
|
70179
|
+
lines.push("Each entry cites the first changed line per file (`file:line`).");
|
|
70180
|
+
lines.push("");
|
|
70181
|
+
lines.push("| Change (`file:line`) |");
|
|
70182
|
+
lines.push("|----------------------|");
|
|
70183
|
+
const citations = extractFileLineCitations(diffText);
|
|
70184
|
+
if (citations.length === 0) {
|
|
70185
|
+
const files = extractChangedFiles(diffText);
|
|
70186
|
+
if (files.length === 0) {
|
|
70187
|
+
lines.push("| `(no changes detected)` |");
|
|
70188
|
+
} else {
|
|
70189
|
+
for (const f of files) {
|
|
70190
|
+
lines.push(`| \`${f}:1\` |`);
|
|
70191
|
+
}
|
|
70192
|
+
}
|
|
70193
|
+
} else {
|
|
70194
|
+
for (const citation of citations) {
|
|
70195
|
+
lines.push(`| \`${citation}\` |`);
|
|
70196
|
+
}
|
|
70197
|
+
}
|
|
70198
|
+
lines.push("");
|
|
70199
|
+
return lines.join(`
|
|
70200
|
+
`);
|
|
70201
|
+
}
|
|
70202
|
+
function extractFileLineCitations(diffText) {
|
|
70203
|
+
const citations = new Set;
|
|
70204
|
+
let currentFile = null;
|
|
70205
|
+
for (const line of diffText.split(`
|
|
70206
|
+
`)) {
|
|
70207
|
+
const fileMatch = /^\+\+\+ b\/(.+)$/.exec(line);
|
|
70208
|
+
if (fileMatch) {
|
|
70209
|
+
currentFile = fileMatch[1] ?? null;
|
|
70210
|
+
continue;
|
|
70211
|
+
}
|
|
70212
|
+
if (currentFile === null)
|
|
70213
|
+
continue;
|
|
70214
|
+
const hunkMatch = /^@@ -\d+(?:,\d+)? \+(\d+)(?:,\d+)? @@/.exec(line);
|
|
70215
|
+
if (hunkMatch) {
|
|
70216
|
+
const newLine = hunkMatch[1];
|
|
70217
|
+
if (newLine !== undefined) {
|
|
70218
|
+
citations.add(`${currentFile}:${newLine}`);
|
|
70219
|
+
}
|
|
70220
|
+
}
|
|
70221
|
+
}
|
|
70222
|
+
return [...citations].sort();
|
|
70223
|
+
}
|
|
70224
|
+
function extractChangedFiles(diffText) {
|
|
70225
|
+
const files = new Set;
|
|
70226
|
+
for (const line of diffText.split(`
|
|
70227
|
+
`)) {
|
|
70228
|
+
const match = /^\+\+\+ b\/(.+)$/.exec(line);
|
|
70229
|
+
if (match) {
|
|
70230
|
+
const filePath = match[1];
|
|
70231
|
+
if (filePath !== undefined)
|
|
70232
|
+
files.add(filePath);
|
|
70233
|
+
}
|
|
70234
|
+
}
|
|
70235
|
+
return [...files].sort();
|
|
70236
|
+
}
|
|
70237
|
+
function gitDiffU0(cwd) {
|
|
70238
|
+
try {
|
|
70239
|
+
const result = new BunSyncProcessExecutor2().runSync({
|
|
70240
|
+
command: "git",
|
|
70241
|
+
args: ["diff", "-U0", "HEAD", "--", "*.ts", "*.tsx", "*.js"],
|
|
70242
|
+
...cwd !== undefined ? { cwd } : {},
|
|
70243
|
+
rejectOnError: false
|
|
70244
|
+
});
|
|
70245
|
+
return result.exitCode === 0 ? result.stdout : "";
|
|
70246
|
+
} catch {
|
|
70247
|
+
return "";
|
|
70248
|
+
}
|
|
70249
|
+
}
|
|
70250
|
+
var init_task_record = __esm(() => {
|
|
70251
|
+
init_dist5();
|
|
70252
|
+
init_verify_verdict();
|
|
70253
|
+
});
|
|
70254
|
+
|
|
69850
70255
|
// ../../packages/app/src/services/feature-check.ts
|
|
69851
70256
|
var exports_feature_check = {};
|
|
69852
70257
|
__export(exports_feature_check, {
|
|
@@ -69979,6 +70384,8 @@ var init_feature_check = __esm(() => {
|
|
|
69979
70384
|
init_done_transition_guard();
|
|
69980
70385
|
init_planning_check_base();
|
|
69981
70386
|
init_structural_repair();
|
|
70387
|
+
init_task_record();
|
|
70388
|
+
init_verify_verdict();
|
|
69982
70389
|
DEFAULT_FEATURE_MATRIX = {
|
|
69983
70390
|
variants: {
|
|
69984
70391
|
standard: {
|
|
@@ -70238,7 +70645,12 @@ var init_feature_check = __esm(() => {
|
|
|
70238
70645
|
if (tac.trim().length > 0)
|
|
70239
70646
|
linkedTaskAc.push(tac);
|
|
70240
70647
|
linkedTaskSolutions.push(taskDoc.getSection("Solution") ?? "");
|
|
70241
|
-
linkedTaskRecords.push({
|
|
70648
|
+
linkedTaskRecords.push({
|
|
70649
|
+
wbs,
|
|
70650
|
+
status: tStatus,
|
|
70651
|
+
ac: tac,
|
|
70652
|
+
testing: taskDoc.getSection("Testing") ?? ""
|
|
70653
|
+
});
|
|
70242
70654
|
} catch {
|
|
70243
70655
|
findings.push({
|
|
70244
70656
|
layer: "L4",
|
|
@@ -70350,9 +70762,42 @@ var init_feature_check = __esm(() => {
|
|
|
70350
70762
|
}
|
|
70351
70763
|
}
|
|
70352
70764
|
const artifacts2 = new Map;
|
|
70765
|
+
const testingByWbs = new Map(linkedTasks.map((t) => [t.wbs, t.testing]));
|
|
70353
70766
|
for (const wbs of doneWbs) {
|
|
70354
70767
|
const artifact = await this.readVerdictArtifact(runDir, wbs);
|
|
70355
70768
|
artifacts2.set(wbs, artifact);
|
|
70769
|
+
const missing = artifact.diagnostics.artifactError === "artifact is missing";
|
|
70770
|
+
if (missing) {
|
|
70771
|
+
const parsed2 = parseTesting(testingByWbs.get(wbs) ?? "", wbs);
|
|
70772
|
+
if (parsed2.kind === "valid") {
|
|
70773
|
+
artifacts2.set(wbs, {
|
|
70774
|
+
path: "tracked ## Testing section",
|
|
70775
|
+
verdict: parsed2.verdict.verdict,
|
|
70776
|
+
computedVerdict: aggregateVerifyVerdict({
|
|
70777
|
+
requirements: parsed2.verdict.requirements,
|
|
70778
|
+
acceptanceCriteria: parsed2.verdict.acceptanceCriteria
|
|
70779
|
+
}),
|
|
70780
|
+
requirements: parsed2.verdict.requirements.map((r) => ({ id: r.id, status: r.status })),
|
|
70781
|
+
acceptanceCriteria: parsed2.verdict.acceptanceCriteria.map((r) => ({
|
|
70782
|
+
id: r.id,
|
|
70783
|
+
status: r.status
|
|
70784
|
+
})),
|
|
70785
|
+
diagnostics: {
|
|
70786
|
+
rejectedRowCount: 0,
|
|
70787
|
+
invalidFields: [],
|
|
70788
|
+
arrayStates: { requirements: "populated", acceptanceCriteria: "populated" }
|
|
70789
|
+
}
|
|
70790
|
+
});
|
|
70791
|
+
} else {
|
|
70792
|
+
findings.push({
|
|
70793
|
+
layer: "L4",
|
|
70794
|
+
code: FINDING_CODES.L4_EVIDENCE_NOT_RECOVERABLE,
|
|
70795
|
+
severity: "warning",
|
|
70796
|
+
section: "Acceptance Criteria",
|
|
70797
|
+
message: `Task ${wbs} has no verdict artifact and its tracked ## Testing section ` + `carries no recoverable coverage evidence (${parsed2.kind}); its evidence ` + "predates durable recording, so it is neither verified nor failed."
|
|
70798
|
+
});
|
|
70799
|
+
}
|
|
70800
|
+
}
|
|
70356
70801
|
const diagnosticParts = [];
|
|
70357
70802
|
if (artifact.diagnostics.artifactError !== undefined) {
|
|
70358
70803
|
if (artifact.diagnostics.artifactError !== "artifact is missing") {
|
|
@@ -70398,7 +70843,7 @@ var init_feature_check = __esm(() => {
|
|
|
70398
70843
|
const artifact = artifacts2.get(task.wbs);
|
|
70399
70844
|
if (artifact === undefined)
|
|
70400
70845
|
continue;
|
|
70401
|
-
if (artifact.verdict !== "PASS")
|
|
70846
|
+
if (artifact.verdict !== "PASS" || artifact.computedVerdict !== "PASS")
|
|
70402
70847
|
continue;
|
|
70403
70848
|
const rows = [...artifact.requirements, ...artifact.acceptanceCriteria];
|
|
70404
70849
|
const matched = rows.find((r) => rowMatchesScenario(r.id, sc));
|
|
@@ -70428,6 +70873,7 @@ var init_feature_check = __esm(() => {
|
|
|
70428
70873
|
return {
|
|
70429
70874
|
path: loaded.path,
|
|
70430
70875
|
verdict: typeof parsed.verdict === "string" ? parsed.verdict : undefined,
|
|
70876
|
+
computedVerdict: computeAggregate(loaded.artifact),
|
|
70431
70877
|
requirements: req.rows,
|
|
70432
70878
|
acceptanceCriteria: ac.rows,
|
|
70433
70879
|
diagnostics: {
|
|
@@ -77032,7 +77478,8 @@ class HistoryService {
|
|
|
77032
77478
|
stepDurationRows,
|
|
77033
77479
|
cacheWasteAggRow,
|
|
77034
77480
|
cacheWasteRows,
|
|
77035
|
-
stepSupportRows
|
|
77481
|
+
stepSupportRows,
|
|
77482
|
+
population
|
|
77036
77483
|
] = await Promise.all([
|
|
77037
77484
|
messageRollup(db2, selector, queryOpts),
|
|
77038
77485
|
toolRollup(db2, selector, queryOpts),
|
|
@@ -77049,7 +77496,8 @@ class HistoryService {
|
|
|
77049
77496
|
topStepsByDuration(db2, selector, top, queryOpts),
|
|
77050
77497
|
cacheWasteAggregate(db2, selector, queryOpts),
|
|
77051
77498
|
topCacheWasteSteps(db2, selector, top, queryOpts),
|
|
77052
|
-
stepSupport(db2, selector, queryOpts)
|
|
77499
|
+
stepSupport(db2, selector, queryOpts),
|
|
77500
|
+
selectionPopulation(db2, selector, queryOpts)
|
|
77053
77501
|
]);
|
|
77054
77502
|
await dropWatermarkExclude();
|
|
77055
77503
|
const totals = foldTotals2(mRows, tRows);
|
|
@@ -77059,6 +77507,11 @@ class HistoryService {
|
|
|
77059
77507
|
const daily = Object.entries(byDay).map(([date6, totals2]) => ({ date: date6, ...totals2 })).sort((a2, b) => a2.date.localeCompare(b.date));
|
|
77060
77508
|
const coverage = buildCoverage(sourceRows, tRows, driftRows, opts.coverageErrors, opts.importCoverage);
|
|
77061
77509
|
const derived = computeDerived(spanRows, toolDurRows, todoRows);
|
|
77510
|
+
const warnings = [
|
|
77511
|
+
...buildWarnings(driftRows, coverage),
|
|
77512
|
+
...derivedWarnings(derived),
|
|
77513
|
+
...opts.extraWarnings ?? []
|
|
77514
|
+
];
|
|
77062
77515
|
const stateByKey = new Map;
|
|
77063
77516
|
for (const w of watermarks)
|
|
77064
77517
|
stateByKey.set(`${w.sessionId}\x00${w.source}`, w.state);
|
|
@@ -77097,11 +77550,7 @@ class HistoryService {
|
|
|
77097
77550
|
sessionState: stateByKey.get(`${r.sessionId}\x00${r.source}`) ?? "complete"
|
|
77098
77551
|
})),
|
|
77099
77552
|
loops: loopRows,
|
|
77100
|
-
warnings
|
|
77101
|
-
...buildWarnings(driftRows, coverage),
|
|
77102
|
-
...derivedWarnings(derived),
|
|
77103
|
-
...opts.extraWarnings ?? []
|
|
77104
|
-
],
|
|
77553
|
+
warnings,
|
|
77105
77554
|
pairings,
|
|
77106
77555
|
ladderSnapshot,
|
|
77107
77556
|
derived,
|
|
@@ -77112,7 +77561,14 @@ class HistoryService {
|
|
|
77112
77561
|
inputTokens: cacheWasteAggRow?.inputTokens ?? 0,
|
|
77113
77562
|
topSteps: cacheWasteRows
|
|
77114
77563
|
},
|
|
77115
|
-
stepSupport: stepSupportRows
|
|
77564
|
+
stepSupport: stepSupportRows,
|
|
77565
|
+
population: {
|
|
77566
|
+
sessions: population.sessions,
|
|
77567
|
+
tools: population.tools,
|
|
77568
|
+
loops: loopRows.length,
|
|
77569
|
+
warnings: warnings.length,
|
|
77570
|
+
appliedTop: top
|
|
77571
|
+
}
|
|
77116
77572
|
};
|
|
77117
77573
|
await refreshHistoryRollups(db2);
|
|
77118
77574
|
if (opts.out !== undefined || opts.cwd !== undefined) {
|
|
@@ -77217,8 +77673,8 @@ class HistoryService {
|
|
|
77217
77673
|
lastImportedAt: null,
|
|
77218
77674
|
parseErrors: result.parseErrors.length,
|
|
77219
77675
|
validationErrors: result.validationErrors.length,
|
|
77220
|
-
parseErrorSamples: result.parseErrors.slice(0,
|
|
77221
|
-
validationErrorSamples: result.validationErrors.slice(0,
|
|
77676
|
+
parseErrorSamples: result.parseErrors.slice(0, MAX_ERROR_SAMPLES2).map(formatIssue),
|
|
77677
|
+
validationErrorSamples: result.validationErrors.slice(0, MAX_ERROR_SAMPLES2).map(formatIssue),
|
|
77222
77678
|
...result.reconciliation ? { reconciliation: result.reconciliation } : {}
|
|
77223
77679
|
};
|
|
77224
77680
|
return { coverageEntry, sourceWarnings };
|
|
@@ -77421,16 +77877,16 @@ function boundCoverage(coverage) {
|
|
|
77421
77877
|
const bounded2 = coverage.map((entry) => {
|
|
77422
77878
|
const pe = entry.parseErrorSamples;
|
|
77423
77879
|
const ve = entry.validationErrorSamples;
|
|
77424
|
-
for (const sample of pe.slice(
|
|
77880
|
+
for (const sample of pe.slice(MAX_ERROR_SAMPLES2)) {
|
|
77425
77881
|
overflow.push({ source: entry.source, kind: "parse", sample });
|
|
77426
77882
|
}
|
|
77427
|
-
for (const sample of ve.slice(
|
|
77883
|
+
for (const sample of ve.slice(MAX_ERROR_SAMPLES2)) {
|
|
77428
77884
|
overflow.push({ source: entry.source, kind: "validation", sample });
|
|
77429
77885
|
}
|
|
77430
77886
|
return {
|
|
77431
77887
|
...entry,
|
|
77432
|
-
parseErrorSamples: pe.slice(0,
|
|
77433
|
-
validationErrorSamples: ve.slice(0,
|
|
77888
|
+
parseErrorSamples: pe.slice(0, MAX_ERROR_SAMPLES2),
|
|
77889
|
+
validationErrorSamples: ve.slice(0, MAX_ERROR_SAMPLES2)
|
|
77434
77890
|
};
|
|
77435
77891
|
});
|
|
77436
77892
|
return { bounded: bounded2, overflow };
|
|
@@ -77527,7 +77983,7 @@ function pruneReports(cwd, retentionDays = REPORT_RETENTION_DAYS, now2 = new Dat
|
|
|
77527
77983
|
}
|
|
77528
77984
|
return pruned.sort((a2, b) => a2.localeCompare(b));
|
|
77529
77985
|
}
|
|
77530
|
-
var SOURCES, FULL_FIDELITY_SOURCES, DEFERRED_SOURCES, MODES,
|
|
77986
|
+
var SOURCES, FULL_FIDELITY_SOURCES, DEFERRED_SOURCES, MODES, MAX_ERROR_SAMPLES2 = 20, DEFAULT_SOURCE_TIMEOUT_MS = 600000, REPORT_RETENTION_DAYS = 90;
|
|
77531
77987
|
var init_history_service = __esm(() => {
|
|
77532
77988
|
init_src2();
|
|
77533
77989
|
init_dist8();
|
|
@@ -80177,205 +80633,6 @@ var init_system_event_follow = __esm(() => {
|
|
|
80177
80633
|
init_src2();
|
|
80178
80634
|
});
|
|
80179
80635
|
|
|
80180
|
-
// ../../packages/app/src/services/task-record.ts
|
|
80181
|
-
function escapeTablePipe(s3) {
|
|
80182
|
-
return s3.replace(/\|/g, "\\|");
|
|
80183
|
-
}
|
|
80184
|
-
function parseVerdict(raw, fallbackWbs) {
|
|
80185
|
-
if (raw.trim() === "") {
|
|
80186
|
-
return { wbs: fallbackWbs ?? "", verdict: "UNKNOWN", requirements: [], checks: [] };
|
|
80187
|
-
}
|
|
80188
|
-
try {
|
|
80189
|
-
const parsed = JSON.parse(raw);
|
|
80190
|
-
if (parsed !== null && typeof parsed === "object") {
|
|
80191
|
-
const obj = parsed;
|
|
80192
|
-
const wbs = typeof obj.wbs === "string" ? obj.wbs : fallbackWbs ?? "";
|
|
80193
|
-
const verdict = normalizeVerdict(obj.verdict);
|
|
80194
|
-
const requirements = normalizeRequirements(obj.requirements);
|
|
80195
|
-
const acceptanceCriteria = normalizeAcceptanceCriteria(obj.acceptanceCriteria);
|
|
80196
|
-
const checks4 = normalizeChecks(obj.checks);
|
|
80197
|
-
return { wbs, verdict, requirements, acceptanceCriteria, checks: checks4 };
|
|
80198
|
-
}
|
|
80199
|
-
} catch {}
|
|
80200
|
-
return { wbs: fallbackWbs ?? "", verdict: "UNKNOWN", requirements: [], checks: [] };
|
|
80201
|
-
}
|
|
80202
|
-
async function readVerdict(fs3, path9, fallbackWbs) {
|
|
80203
|
-
let raw;
|
|
80204
|
-
try {
|
|
80205
|
-
raw = await fs3.readFile(path9);
|
|
80206
|
-
} catch {
|
|
80207
|
-
return { wbs: fallbackWbs ?? "", verdict: "UNKNOWN", requirements: [], checks: [] };
|
|
80208
|
-
}
|
|
80209
|
-
return parseVerdict(raw, fallbackWbs);
|
|
80210
|
-
}
|
|
80211
|
-
function normalizeVerdict(raw) {
|
|
80212
|
-
if (typeof raw !== "string")
|
|
80213
|
-
return "UNKNOWN";
|
|
80214
|
-
const upper = raw.toUpperCase();
|
|
80215
|
-
if (upper === "PASS")
|
|
80216
|
-
return "PASS";
|
|
80217
|
-
if (upper === "PARTIAL")
|
|
80218
|
-
return "PARTIAL";
|
|
80219
|
-
if (upper === "FAIL")
|
|
80220
|
-
return "FAIL";
|
|
80221
|
-
return "UNKNOWN";
|
|
80222
|
-
}
|
|
80223
|
-
function normalizeRequirements(raw) {
|
|
80224
|
-
if (!Array.isArray(raw))
|
|
80225
|
-
return [];
|
|
80226
|
-
return raw.filter((r) => r !== null && typeof r === "object").map((r) => ({
|
|
80227
|
-
id: typeof r.id === "string" ? r.id : "",
|
|
80228
|
-
status: typeof r.status === "string" ? r.status : "",
|
|
80229
|
-
evidence: typeof r.evidence === "string" ? r.evidence : ""
|
|
80230
|
-
}));
|
|
80231
|
-
}
|
|
80232
|
-
function normalizeAcceptanceCriteria(raw) {
|
|
80233
|
-
if (!Array.isArray(raw))
|
|
80234
|
-
return [];
|
|
80235
|
-
return raw.filter((ac) => ac !== null && typeof ac === "object").map((ac) => ({
|
|
80236
|
-
id: typeof ac.id === "string" ? ac.id : "",
|
|
80237
|
-
status: typeof ac.status === "string" ? ac.status : "",
|
|
80238
|
-
evidenceType: typeof ac.evidenceType === "string" ? ac.evidenceType : "",
|
|
80239
|
-
evidence: typeof ac.evidence === "string" ? ac.evidence : ""
|
|
80240
|
-
}));
|
|
80241
|
-
}
|
|
80242
|
-
function normalizeChecks(raw) {
|
|
80243
|
-
if (!Array.isArray(raw))
|
|
80244
|
-
return [];
|
|
80245
|
-
return raw.filter((c3) => c3 !== null && typeof c3 === "object").map((c3) => ({
|
|
80246
|
-
name: typeof c3.name === "string" ? c3.name : "",
|
|
80247
|
-
status: typeof c3.status === "string" ? c3.status : "",
|
|
80248
|
-
evidence: typeof c3.evidence === "string" ? c3.evidence : ""
|
|
80249
|
-
}));
|
|
80250
|
-
}
|
|
80251
|
-
function renderTesting(v) {
|
|
80252
|
-
const lines = [];
|
|
80253
|
-
lines.push("**Pipeline verify results**");
|
|
80254
|
-
lines.push("");
|
|
80255
|
-
lines.push(`- Verdict: ${v.verdict} (from verdict artifact)`);
|
|
80256
|
-
lines.push("");
|
|
80257
|
-
if (v.requirements.length === 0) {
|
|
80258
|
-
lines.push("| Requirement | Status | Evidence |");
|
|
80259
|
-
lines.push("|-------------|--------|----------|");
|
|
80260
|
-
lines.push(`| \u2014 | \u2014 | No requirements recorded; verify verdict ${v.verdict} |`);
|
|
80261
|
-
} else {
|
|
80262
|
-
lines.push("| Requirement | Status | Evidence |");
|
|
80263
|
-
lines.push("|-------------|--------|----------|");
|
|
80264
|
-
for (const req of v.requirements) {
|
|
80265
|
-
const evidence = escapeTablePipe(req.evidence.replace(/\n/g, " "));
|
|
80266
|
-
lines.push(`| ${req.id} | ${req.status} | ${evidence} |`);
|
|
80267
|
-
}
|
|
80268
|
-
}
|
|
80269
|
-
if ((v.acceptanceCriteria ?? []).length > 0) {
|
|
80270
|
-
lines.push("");
|
|
80271
|
-
lines.push("| Acceptance Criteria | Status | Evidence Type | Evidence |");
|
|
80272
|
-
lines.push("|---------------------|--------|---------------|----------|");
|
|
80273
|
-
for (const ac of v.acceptanceCriteria ?? []) {
|
|
80274
|
-
const evidence = escapeTablePipe(ac.evidence.replace(/\n/g, " "));
|
|
80275
|
-
lines.push(`| ${ac.id} | ${ac.status} | ${ac.evidenceType} | ${evidence} |`);
|
|
80276
|
-
}
|
|
80277
|
-
}
|
|
80278
|
-
lines.push("- Coverage: N/A (verdict-based; verify pipeline does not measure code coverage)");
|
|
80279
|
-
return lines.join(`
|
|
80280
|
-
`);
|
|
80281
|
-
}
|
|
80282
|
-
function renderReview(v) {
|
|
80283
|
-
const lines = [];
|
|
80284
|
-
lines.push(`**SECU findings** (pipeline verify step \u2014 verdict: ${v.verdict})`);
|
|
80285
|
-
lines.push("");
|
|
80286
|
-
lines.push("| Priority | Dimension | Location | Finding |");
|
|
80287
|
-
lines.push("|----------|-----------|----------|----------|");
|
|
80288
|
-
if (v.checks.length === 0) {
|
|
80289
|
-
lines.push(`| P4 | \u2014 | \u2014 | No P1\u2013P3 findings; verify verdict ${v.verdict} |`);
|
|
80290
|
-
} else {
|
|
80291
|
-
for (const check2 of v.checks) {
|
|
80292
|
-
const finding = escapeTablePipe(check2.evidence.replace(/\n/g, " "));
|
|
80293
|
-
const priority = /^P[1-4]$/.test(check2.status) ? check2.status : check2.status === "fail" ? "P1" : "P4";
|
|
80294
|
-
lines.push(`| ${priority} | ${check2.name} | \u2014 | ${finding} |`);
|
|
80295
|
-
}
|
|
80296
|
-
}
|
|
80297
|
-
lines.push("");
|
|
80298
|
-
return lines.join(`
|
|
80299
|
-
`);
|
|
80300
|
-
}
|
|
80301
|
-
function renderSolutionFromDiff(diffText) {
|
|
80302
|
-
const lines = [];
|
|
80303
|
-
lines.push("Change-map (auto-generated \u2014 implement step did not record a Solution).");
|
|
80304
|
-
lines.push("Each entry cites the first changed line per file (`file:line`).");
|
|
80305
|
-
lines.push("");
|
|
80306
|
-
lines.push("| Change (`file:line`) |");
|
|
80307
|
-
lines.push("|----------------------|");
|
|
80308
|
-
const citations = extractFileLineCitations(diffText);
|
|
80309
|
-
if (citations.length === 0) {
|
|
80310
|
-
const files = extractChangedFiles(diffText);
|
|
80311
|
-
if (files.length === 0) {
|
|
80312
|
-
lines.push("| `(no changes detected)` |");
|
|
80313
|
-
} else {
|
|
80314
|
-
for (const f of files) {
|
|
80315
|
-
lines.push(`| \`${f}:1\` |`);
|
|
80316
|
-
}
|
|
80317
|
-
}
|
|
80318
|
-
} else {
|
|
80319
|
-
for (const citation of citations) {
|
|
80320
|
-
lines.push(`| \`${citation}\` |`);
|
|
80321
|
-
}
|
|
80322
|
-
}
|
|
80323
|
-
lines.push("");
|
|
80324
|
-
return lines.join(`
|
|
80325
|
-
`);
|
|
80326
|
-
}
|
|
80327
|
-
function extractFileLineCitations(diffText) {
|
|
80328
|
-
const citations = new Set;
|
|
80329
|
-
let currentFile = null;
|
|
80330
|
-
for (const line of diffText.split(`
|
|
80331
|
-
`)) {
|
|
80332
|
-
const fileMatch = /^\+\+\+ b\/(.+)$/.exec(line);
|
|
80333
|
-
if (fileMatch) {
|
|
80334
|
-
currentFile = fileMatch[1] ?? null;
|
|
80335
|
-
continue;
|
|
80336
|
-
}
|
|
80337
|
-
if (currentFile === null)
|
|
80338
|
-
continue;
|
|
80339
|
-
const hunkMatch = /^@@ -\d+(?:,\d+)? \+(\d+)(?:,\d+)? @@/.exec(line);
|
|
80340
|
-
if (hunkMatch) {
|
|
80341
|
-
const newLine = hunkMatch[1];
|
|
80342
|
-
if (newLine !== undefined) {
|
|
80343
|
-
citations.add(`${currentFile}:${newLine}`);
|
|
80344
|
-
}
|
|
80345
|
-
}
|
|
80346
|
-
}
|
|
80347
|
-
return [...citations].sort();
|
|
80348
|
-
}
|
|
80349
|
-
function extractChangedFiles(diffText) {
|
|
80350
|
-
const files = new Set;
|
|
80351
|
-
for (const line of diffText.split(`
|
|
80352
|
-
`)) {
|
|
80353
|
-
const match = /^\+\+\+ b\/(.+)$/.exec(line);
|
|
80354
|
-
if (match) {
|
|
80355
|
-
const filePath = match[1];
|
|
80356
|
-
if (filePath !== undefined)
|
|
80357
|
-
files.add(filePath);
|
|
80358
|
-
}
|
|
80359
|
-
}
|
|
80360
|
-
return [...files].sort();
|
|
80361
|
-
}
|
|
80362
|
-
function gitDiffU0(cwd) {
|
|
80363
|
-
try {
|
|
80364
|
-
const result = new BunSyncProcessExecutor2().runSync({
|
|
80365
|
-
command: "git",
|
|
80366
|
-
args: ["diff", "-U0", "HEAD", "--", "*.ts", "*.tsx", "*.js"],
|
|
80367
|
-
...cwd !== undefined ? { cwd } : {},
|
|
80368
|
-
rejectOnError: false
|
|
80369
|
-
});
|
|
80370
|
-
return result.exitCode === 0 ? result.stdout : "";
|
|
80371
|
-
} catch {
|
|
80372
|
-
return "";
|
|
80373
|
-
}
|
|
80374
|
-
}
|
|
80375
|
-
var init_task_record = __esm(() => {
|
|
80376
|
-
init_dist5();
|
|
80377
|
-
});
|
|
80378
|
-
|
|
80379
80636
|
// ../../packages/app/src/services/task-scaffold.ts
|
|
80380
80637
|
import { dirname as dirname13 } from "path";
|
|
80381
80638
|
|
|
@@ -81885,7 +82142,7 @@ class TeamService {
|
|
|
81885
82142
|
}
|
|
81886
82143
|
async listTeams() {
|
|
81887
82144
|
const specs = await loadAgentSpecs(this.configDir);
|
|
81888
|
-
const config4 =
|
|
82145
|
+
const config4 = this.ctx.spurConfig ?? null;
|
|
81889
82146
|
const teams = new Map;
|
|
81890
82147
|
const configTeamIds = new Set;
|
|
81891
82148
|
if (config4?.agent?.team) {
|
|
@@ -81944,7 +82201,7 @@ class TeamService {
|
|
|
81944
82201
|
return Array.from(teams.values());
|
|
81945
82202
|
}
|
|
81946
82203
|
async materializeTeam(teamId, opts) {
|
|
81947
|
-
const config4 =
|
|
82204
|
+
const config4 = this.ctx.spurConfig ?? null;
|
|
81948
82205
|
const teamConfig = config4?.agent?.team?.[teamId];
|
|
81949
82206
|
if (!teamConfig) {
|
|
81950
82207
|
throw new Error(`Team "${teamId}" not found in agent.team config`);
|
|
@@ -82069,13 +82326,6 @@ class TeamService {
|
|
|
82069
82326
|
const workDir = this.resolveWorkspaceDir(first);
|
|
82070
82327
|
return { workDir, isCurrentProject: this.isCurrentProject(workDir) };
|
|
82071
82328
|
}
|
|
82072
|
-
async loadTeamConfig() {
|
|
82073
|
-
try {
|
|
82074
|
-
return await loadSpurConfig(this.ctx.cwd);
|
|
82075
|
-
} catch {
|
|
82076
|
-
return null;
|
|
82077
|
-
}
|
|
82078
|
-
}
|
|
82079
82329
|
async inboxDao() {
|
|
82080
82330
|
const db2 = await this.ctx.getDb();
|
|
82081
82331
|
return new InboxMessageDao(db2);
|
|
@@ -82181,7 +82431,6 @@ function resolveAutostartSet(config4, envAutostart) {
|
|
|
82181
82431
|
}
|
|
82182
82432
|
var init_team_service = __esm(() => {
|
|
82183
82433
|
init_src();
|
|
82184
|
-
init_loader();
|
|
82185
82434
|
init_src2();
|
|
82186
82435
|
init_dist9();
|
|
82187
82436
|
init_planning_folders();
|
|
@@ -83307,21 +83556,26 @@ var init_agent_run = __esm(() => {
|
|
|
83307
83556
|
init_steering();
|
|
83308
83557
|
});
|
|
83309
83558
|
|
|
83310
|
-
// ../../packages/app/src/workflow/
|
|
83311
|
-
|
|
83312
|
-
|
|
83313
|
-
|
|
83314
|
-
return {
|
|
83315
|
-
error: `command.gate "executable" must not contain shell metacharacters (got ${executable})`
|
|
83316
|
-
};
|
|
83559
|
+
// ../../packages/app/src/workflow/split-launch-command.ts
|
|
83560
|
+
function splitLaunchCommand(value, label) {
|
|
83561
|
+
if (SHELL_METACHARACTERS.test(value)) {
|
|
83562
|
+
return { error: `${label} must not contain shell metacharacters (got ${value})` };
|
|
83317
83563
|
}
|
|
83318
|
-
const tokens =
|
|
83564
|
+
const tokens = value.trim().split(/\s+/).filter((t) => t.length > 0);
|
|
83319
83565
|
const command = tokens[0];
|
|
83320
83566
|
if (command === undefined) {
|
|
83321
|
-
|
|
83567
|
+
const key2 = label.slice(label.indexOf('"'));
|
|
83568
|
+
return { error: `Action option ${key2} must be a non-empty string` };
|
|
83322
83569
|
}
|
|
83323
83570
|
return { command, leadingArgs: tokens.slice(1) };
|
|
83324
83571
|
}
|
|
83572
|
+
var SHELL_METACHARACTERS;
|
|
83573
|
+
var init_split_launch_command = __esm(() => {
|
|
83574
|
+
SHELL_METACHARACTERS = /[;&|<>$`(){}[\]!*?~#\n\r"']/;
|
|
83575
|
+
});
|
|
83576
|
+
|
|
83577
|
+
// ../../packages/app/src/workflow/actions/command-gate.ts
|
|
83578
|
+
import { normalize, resolve as resolve9 } from "path";
|
|
83325
83579
|
function sleep3(ms) {
|
|
83326
83580
|
return new Promise((resolve10) => setTimeout(resolve10, ms));
|
|
83327
83581
|
}
|
|
@@ -83382,7 +83636,7 @@ class CommandGateActionRunner {
|
|
|
83382
83636
|
error: `resultFile must resolve beneath .spur/run/ (got ${resultFileRaw})`
|
|
83383
83637
|
};
|
|
83384
83638
|
}
|
|
83385
|
-
const split =
|
|
83639
|
+
const split = splitLaunchCommand(executable, 'command.gate "executable"');
|
|
83386
83640
|
if ("error" in split) {
|
|
83387
83641
|
return { ok: false, error: split.error };
|
|
83388
83642
|
}
|
|
@@ -83462,25 +83716,14 @@ ${lastStderr}`;
|
|
|
83462
83716
|
};
|
|
83463
83717
|
}
|
|
83464
83718
|
}
|
|
83465
|
-
var KIND2 = "command.gate"
|
|
83719
|
+
var KIND2 = "command.gate";
|
|
83466
83720
|
var init_command_gate = __esm(() => {
|
|
83467
83721
|
init_dist5();
|
|
83468
|
-
|
|
83722
|
+
init_split_launch_command();
|
|
83469
83723
|
});
|
|
83470
83724
|
|
|
83471
83725
|
// ../../packages/app/src/workflow/actions/doctor-probe.ts
|
|
83472
83726
|
import { normalize as normalize2, resolve as resolve10, sep as sep2 } from "path";
|
|
83473
|
-
function splitSpurBin(spurBin) {
|
|
83474
|
-
if (SHELL_METACHARACTERS2.test(spurBin)) {
|
|
83475
|
-
return { error: `doctor.probe "spurBin" must not contain shell metacharacters (got ${spurBin})` };
|
|
83476
|
-
}
|
|
83477
|
-
const tokens = spurBin.trim().split(/\s+/).filter((t) => t.length > 0);
|
|
83478
|
-
const command = tokens[0];
|
|
83479
|
-
if (command === undefined) {
|
|
83480
|
-
return { error: 'Action option "spurBin" must be a non-empty string' };
|
|
83481
|
-
}
|
|
83482
|
-
return { command, leadingArgs: tokens.slice(1) };
|
|
83483
|
-
}
|
|
83484
83727
|
function stringOption2(options, key2, fallback) {
|
|
83485
83728
|
const value = options[key2];
|
|
83486
83729
|
if (typeof value === "string")
|
|
@@ -83540,7 +83783,7 @@ class DoctorProbeActionRunner {
|
|
|
83540
83783
|
error: `resultFile must resolve beneath .spur/run/ (got ${resultFileRaw})`
|
|
83541
83784
|
};
|
|
83542
83785
|
}
|
|
83543
|
-
const split =
|
|
83786
|
+
const split = splitLaunchCommand(spurBin, 'doctor.probe "spurBin"');
|
|
83544
83787
|
if ("error" in split) {
|
|
83545
83788
|
return { ok: false, error: split.error };
|
|
83546
83789
|
}
|
|
@@ -83616,11 +83859,11 @@ ${res.stderr}`.trim();
|
|
|
83616
83859
|
return { ok: true, data: { status, resultFile: normalized, output: lines } };
|
|
83617
83860
|
}
|
|
83618
83861
|
}
|
|
83619
|
-
var KIND3 = "doctor.probe",
|
|
83862
|
+
var KIND3 = "doctor.probe", RELAY_FAMILY, ENV_MISS_PATTERN, AUTH_FAIL_PATTERN;
|
|
83620
83863
|
var init_doctor_probe = __esm(() => {
|
|
83621
83864
|
init_dist5();
|
|
83622
83865
|
init_observability();
|
|
83623
|
-
|
|
83866
|
+
init_split_launch_command();
|
|
83624
83867
|
RELAY_FAMILY = /^(omp|pi)(-.*)?$/;
|
|
83625
83868
|
ENV_MISS_PATTERN = /API key not found for provider|no probe registered/i;
|
|
83626
83869
|
AUTH_FAIL_PATTERN = /invalid (API )?key|unauthori[sz]ed|forbidden|authentication failed|credential(s)? rejected/i;
|
|
@@ -84907,10 +85150,19 @@ class WorkflowAppService {
|
|
|
84907
85150
|
};
|
|
84908
85151
|
}
|
|
84909
85152
|
async validate(file2, opts = {}) {
|
|
84910
|
-
const
|
|
84911
|
-
if (
|
|
84912
|
-
|
|
85153
|
+
const resolved = resolveWorkflowFile(this.ctx.cwd, file2);
|
|
85154
|
+
if (resolved.path === null) {
|
|
85155
|
+
const [probedProject, probedBundled] = resolved.probed;
|
|
85156
|
+
return {
|
|
85157
|
+
ok: false,
|
|
85158
|
+
valid: false,
|
|
85159
|
+
file: file2,
|
|
85160
|
+
errors: [
|
|
85161
|
+
`File not found: ${probedProject}${probedBundled !== null ? ` (bundled: ${probedBundled})` : ""}`
|
|
85162
|
+
]
|
|
85163
|
+
};
|
|
84913
85164
|
}
|
|
85165
|
+
const absolute = resolved.path;
|
|
84914
85166
|
try {
|
|
84915
85167
|
const embedded = this.embeddedSchemaOptions();
|
|
84916
85168
|
const workflow = await loadWorkflowDef(absolute, {
|
|
@@ -84959,7 +85211,12 @@ class WorkflowAppService {
|
|
|
84959
85211
|
}
|
|
84960
85212
|
async run(file2, opts = {}) {
|
|
84961
85213
|
const eventsBus = this.ctx.events?.();
|
|
84962
|
-
const
|
|
85214
|
+
const resolved = resolveWorkflowFile(this.ctx.cwd, file2);
|
|
85215
|
+
if (resolved.path === null) {
|
|
85216
|
+
const [probedProject, probedBundled] = resolved.probed;
|
|
85217
|
+
throw new Error(`Workflow not found: ${probedProject}${probedBundled !== null ? ` (bundled: ${probedBundled})` : ""}`);
|
|
85218
|
+
}
|
|
85219
|
+
const absolute = resolved.path;
|
|
84963
85220
|
const embedded = this.embeddedSchemaOptions();
|
|
84964
85221
|
const workflow = await loadWorkflowDef(absolute, {
|
|
84965
85222
|
validateSchema: true,
|
|
@@ -84975,7 +85232,7 @@ class WorkflowAppService {
|
|
|
84975
85232
|
const isDry = opts.dryRun === true;
|
|
84976
85233
|
const warnings = [];
|
|
84977
85234
|
const runVars = {
|
|
84978
|
-
...
|
|
85235
|
+
...resolveDefaultAgentVar(this.ctx.spurConfig ?? null, opts.vars, (m) => warnings.push(m)),
|
|
84979
85236
|
...opts.vars ?? {},
|
|
84980
85237
|
__runId: runId
|
|
84981
85238
|
};
|
|
@@ -85019,7 +85276,10 @@ class WorkflowAppService {
|
|
|
85019
85276
|
return;
|
|
85020
85277
|
let workflowName;
|
|
85021
85278
|
try {
|
|
85022
|
-
const
|
|
85279
|
+
const resolved = resolveWorkflowFile(this.ctx.cwd, file2);
|
|
85280
|
+
if (resolved.path === null)
|
|
85281
|
+
return;
|
|
85282
|
+
const def = await loadWorkflowDef(resolved.path, { validateSchema: false });
|
|
85023
85283
|
workflowName = def.name;
|
|
85024
85284
|
} catch {
|
|
85025
85285
|
return;
|
|
@@ -85295,14 +85555,12 @@ class WorkflowAppService {
|
|
|
85295
85555
|
let agentSlice = {
|
|
85296
85556
|
...this.ctx.secretValues !== undefined ? { secretValues: this.ctx.secretValues } : {}
|
|
85297
85557
|
};
|
|
85298
|
-
|
|
85299
|
-
|
|
85300
|
-
agentSlice
|
|
85301
|
-
|
|
85302
|
-
|
|
85303
|
-
|
|
85304
|
-
};
|
|
85305
|
-
} catch {}
|
|
85558
|
+
const agent = this.ctx.spurConfig?.agent;
|
|
85559
|
+
agentSlice = {
|
|
85560
|
+
...agentSlice,
|
|
85561
|
+
...agent?.default !== undefined ? { default: agent.default } : {},
|
|
85562
|
+
...agent?.sessionAffinity !== undefined ? { sessionAffinity: agent.sessionAffinity } : {}
|
|
85563
|
+
};
|
|
85306
85564
|
try {
|
|
85307
85565
|
const fs3 = createNodeFileSystem3(this.ctx.cwd);
|
|
85308
85566
|
const { foldersConfig, featuresDir } = await resolvePlanningFolders(fs3);
|
|
@@ -85532,22 +85790,31 @@ async function fileExists(path9) {
|
|
|
85532
85790
|
const fs3 = createNodeFileSystem3();
|
|
85533
85791
|
return await fs3.exists(path9);
|
|
85534
85792
|
}
|
|
85535
|
-
|
|
85793
|
+
function resolveWorkflowFile(cwd, file2) {
|
|
85794
|
+
const projectPath = resolve13(cwd, file2);
|
|
85795
|
+
if (existsSync10(projectPath)) {
|
|
85796
|
+
return { path: projectPath, source: "project" };
|
|
85797
|
+
}
|
|
85798
|
+
const bundledRoot = bundledConfigRoot();
|
|
85799
|
+
if (bundledRoot !== null) {
|
|
85800
|
+
const bundledPath = join22(bundledRoot, "workflows", basename7(file2));
|
|
85801
|
+
if (existsSync10(bundledPath)) {
|
|
85802
|
+
return { path: bundledPath, source: "bundled" };
|
|
85803
|
+
}
|
|
85804
|
+
return { path: null, probed: [projectPath, bundledPath] };
|
|
85805
|
+
}
|
|
85806
|
+
return { path: null, probed: [projectPath, null] };
|
|
85807
|
+
}
|
|
85808
|
+
function resolveDefaultAgentVar(config4, callerVars, warn) {
|
|
85536
85809
|
const result = {};
|
|
85537
85810
|
if (callerVars?.implementAgent === undefined && callerVars?.agent !== undefined) {
|
|
85538
85811
|
result.implementAgent = callerVars.agent;
|
|
85539
85812
|
}
|
|
85540
|
-
|
|
85541
|
-
try {
|
|
85542
|
-
config4 = await loadSpurConfig(cwd);
|
|
85543
|
-
} catch {
|
|
85544
|
-
return result;
|
|
85545
|
-
}
|
|
85546
|
-
const configured = config4.agent?.default;
|
|
85813
|
+
const configured = config4?.agent?.default;
|
|
85547
85814
|
if (typeof configured !== "string" || configured.length === 0) {
|
|
85548
85815
|
return result;
|
|
85549
85816
|
}
|
|
85550
|
-
const valid = AGENT_ROLE_NAMES.includes(configured) || config4
|
|
85817
|
+
const valid = AGENT_ROLE_NAMES.includes(configured) || config4?.agent?.executors?.some((e) => e.name === configured) === true || resolveAgentName(configured) !== undefined;
|
|
85551
85818
|
if (!valid) {
|
|
85552
85819
|
warn(`agent.default "${configured}" does not name a Layer-1 role, a configured executor, or an agent binary; leaving the pipeline's literal agent in force`);
|
|
85553
85820
|
return result;
|
|
@@ -85559,25 +85826,17 @@ async function resolveDefaultAgentVar(cwd, callerVars, warn) {
|
|
|
85559
85826
|
}
|
|
85560
85827
|
return result;
|
|
85561
85828
|
}
|
|
85562
|
-
|
|
85563
|
-
|
|
85564
|
-
return (await loadSpurConfig(cwd)).workflow?.logRetentionDays ?? 30;
|
|
85565
|
-
} catch {
|
|
85566
|
-
return 30;
|
|
85567
|
-
}
|
|
85829
|
+
function resolveWorkflowLogRetentionDays(config4) {
|
|
85830
|
+
return config4?.workflow?.logRetentionDays ?? 30;
|
|
85568
85831
|
}
|
|
85569
|
-
|
|
85570
|
-
|
|
85571
|
-
|
|
85572
|
-
if (output2 === undefined)
|
|
85573
|
-
return {};
|
|
85574
|
-
return {
|
|
85575
|
-
...output2["max-bytes"] !== undefined ? { maxBytes: output2["max-bytes"] } : {},
|
|
85576
|
-
...output2["max-lines"] !== undefined ? { maxLines: output2["max-lines"] } : {}
|
|
85577
|
-
};
|
|
85578
|
-
} catch {
|
|
85832
|
+
function resolveOutputLogConfig(config4) {
|
|
85833
|
+
const output2 = config4?.agent?.output;
|
|
85834
|
+
if (output2 === undefined)
|
|
85579
85835
|
return {};
|
|
85580
|
-
|
|
85836
|
+
return {
|
|
85837
|
+
...output2["max-bytes"] !== undefined ? { maxBytes: output2["max-bytes"] } : {},
|
|
85838
|
+
...output2["max-lines"] !== undefined ? { maxLines: output2["max-lines"] } : {}
|
|
85839
|
+
};
|
|
85581
85840
|
}
|
|
85582
85841
|
async function outputArtifactForRun(cwd, runId) {
|
|
85583
85842
|
const relative5 = join22(".spur", "run", `${runId}.log`);
|
|
@@ -85793,6 +86052,9 @@ var init_workflow_service = __esm(() => {
|
|
|
85793
86052
|
|
|
85794
86053
|
// ../../packages/app/src/workflow/idea-handoff.ts
|
|
85795
86054
|
import { resolve as resolve14 } from "path";
|
|
86055
|
+
function processEvidence(r) {
|
|
86056
|
+
return `exit=${r.exitCode ?? "null"}${r.signal ? ` signal=${r.signal}` : ""}: ${r.stderr.trim() || "no stderr"}`;
|
|
86057
|
+
}
|
|
85796
86058
|
async function finalizeIdeaHandoff(options) {
|
|
85797
86059
|
const root = options.projectRoot ?? process.cwd();
|
|
85798
86060
|
const fs3 = options.fileSystem ?? createNodeFileSystem3();
|
|
@@ -85804,6 +86066,18 @@ async function finalizeIdeaHandoff(options) {
|
|
|
85804
86066
|
const resultPath = resolve14(runDir, `${runId}-idea-batch-create-result.json`);
|
|
85805
86067
|
const orderPath = resolve14(runDir, `${runId}-idea-task-order.json`);
|
|
85806
86068
|
const reportPath = resolve14(runDir, `${runId}-idea-handoff.md`);
|
|
86069
|
+
const spurSplit = splitLaunchCommand(spurBin, 'idea-handoff "spurBin"');
|
|
86070
|
+
if ("error" in spurSplit) {
|
|
86071
|
+
return {
|
|
86072
|
+
ok: false,
|
|
86073
|
+
wbsList: [],
|
|
86074
|
+
nextCommand: "",
|
|
86075
|
+
reportPath,
|
|
86076
|
+
error: spurSplit.error
|
|
86077
|
+
};
|
|
86078
|
+
}
|
|
86079
|
+
const spurCommand = spurSplit.command;
|
|
86080
|
+
const spurArgsPrefix = spurSplit.leadingArgs;
|
|
85807
86081
|
if (!await fs3.exists(batchPath) || !await fs3.exists(resultPath) || !await fs3.exists(orderPath)) {
|
|
85808
86082
|
return {
|
|
85809
86083
|
ok: false,
|
|
@@ -85873,8 +86147,8 @@ async function finalizeIdeaHandoff(options) {
|
|
|
85873
86147
|
}
|
|
85874
86148
|
if (deps.length > 0) {
|
|
85875
86149
|
const depRes = await executor.run({
|
|
85876
|
-
command:
|
|
85877
|
-
args: ["task", "deps", ownWbs, "set", ...deps, "--json"],
|
|
86150
|
+
command: spurCommand,
|
|
86151
|
+
args: [...spurArgsPrefix, "task", "deps", ownWbs, "set", ...deps, "--json"],
|
|
85878
86152
|
cwd: root,
|
|
85879
86153
|
forceBuffered: true,
|
|
85880
86154
|
rejectOnError: false
|
|
@@ -85885,27 +86159,45 @@ async function finalizeIdeaHandoff(options) {
|
|
|
85885
86159
|
wbsList: result.wbs,
|
|
85886
86160
|
nextCommand: "",
|
|
85887
86161
|
reportPath,
|
|
85888
|
-
error: `Failed to set dependencies for task ${ownWbs}: ${depRes
|
|
86162
|
+
error: `Failed to set dependencies for task ${ownWbs}: ${processEvidence(depRes)}`
|
|
85889
86163
|
};
|
|
85890
86164
|
}
|
|
85891
86165
|
}
|
|
85892
86166
|
}
|
|
85893
|
-
await executor.run({
|
|
85894
|
-
command:
|
|
85895
|
-
args: ["feature", "refresh", "--feature", featureId2, "--json"],
|
|
86167
|
+
const refreshRes = await executor.run({
|
|
86168
|
+
command: spurCommand,
|
|
86169
|
+
args: [...spurArgsPrefix, "feature", "refresh", "--feature", featureId2, "--json"],
|
|
85896
86170
|
cwd: root,
|
|
85897
86171
|
forceBuffered: true,
|
|
85898
86172
|
rejectOnError: false
|
|
85899
86173
|
});
|
|
86174
|
+
if (refreshRes.exitCode !== 0) {
|
|
86175
|
+
return {
|
|
86176
|
+
ok: false,
|
|
86177
|
+
wbsList: result.wbs,
|
|
86178
|
+
nextCommand: "",
|
|
86179
|
+
reportPath,
|
|
86180
|
+
error: `Feature refresh for ${featureId2} failed: ${processEvidence(refreshRes)}`
|
|
86181
|
+
};
|
|
86182
|
+
}
|
|
85900
86183
|
const checkResults = [];
|
|
85901
86184
|
for (const wbs of result.wbs) {
|
|
85902
86185
|
const checkRes = await executor.run({
|
|
85903
|
-
command:
|
|
85904
|
-
args: ["task", "check", wbs, "--json"],
|
|
86186
|
+
command: spurCommand,
|
|
86187
|
+
args: [...spurArgsPrefix, "task", "check", wbs, "--json"],
|
|
85905
86188
|
cwd: root,
|
|
85906
86189
|
forceBuffered: true,
|
|
85907
86190
|
rejectOnError: false
|
|
85908
86191
|
});
|
|
86192
|
+
if (checkRes.exitCode === null) {
|
|
86193
|
+
return {
|
|
86194
|
+
ok: false,
|
|
86195
|
+
wbsList: result.wbs,
|
|
86196
|
+
nextCommand: "",
|
|
86197
|
+
reportPath,
|
|
86198
|
+
error: `Task check for ${wbs} could not be spawned (${spurCommand}): ${processEvidence(checkRes)}`
|
|
86199
|
+
};
|
|
86200
|
+
}
|
|
85909
86201
|
checkResults.push({ wbs, pass: checkRes.exitCode === 0 });
|
|
85910
86202
|
}
|
|
85911
86203
|
const anyFailed = checkResults.some((c3) => !c3.pass);
|
|
@@ -85951,6 +86243,7 @@ async function finalizeIdeaHandoff(options) {
|
|
|
85951
86243
|
}
|
|
85952
86244
|
var init_idea_handoff = __esm(() => {
|
|
85953
86245
|
init_dist5();
|
|
86246
|
+
init_split_launch_command();
|
|
85954
86247
|
});
|
|
85955
86248
|
|
|
85956
86249
|
// ../../packages/app/src/workflow/idea-handoff-cli.ts
|
|
@@ -86534,6 +86827,7 @@ __export(exports_src2, {
|
|
|
86534
86827
|
runHistoryReport: () => runHistoryReport,
|
|
86535
86828
|
runCorpusCheck: () => runCorpusCheck,
|
|
86536
86829
|
resolveWorkflowLogRetentionDays: () => resolveWorkflowLogRetentionDays,
|
|
86830
|
+
resolveWorkflowFile: () => resolveWorkflowFile,
|
|
86537
86831
|
resolveSpurServeCommand: () => resolveSpurServeCommand,
|
|
86538
86832
|
resolveRetentionQuotas: () => resolveRetentionQuotas,
|
|
86539
86833
|
resolvePlanningFolders: () => resolvePlanningFolders,
|
|
@@ -86859,7 +87153,6 @@ var {
|
|
|
86859
87153
|
} = import__.default;
|
|
86860
87154
|
|
|
86861
87155
|
// src/index.ts
|
|
86862
|
-
init_src();
|
|
86863
87156
|
init_loader();
|
|
86864
87157
|
|
|
86865
87158
|
// ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.42+4012563f10a1cd34/node_modules/@gobing-ai/ts-infra/dist/application-node.js
|
|
@@ -95200,8 +95493,7 @@ init_loader();
|
|
|
95200
95493
|
init_src2();
|
|
95201
95494
|
await init_src3();
|
|
95202
95495
|
import { existsSync as existsSync12 } from "fs";
|
|
95203
|
-
import {
|
|
95204
|
-
import { join as join25, resolve as resolve16 } from "path";
|
|
95496
|
+
import { join as join25 } from "path";
|
|
95205
95497
|
|
|
95206
95498
|
// src/workflow/resolve-spur-bin.ts
|
|
95207
95499
|
import { basename as basename8 } from "path";
|
|
@@ -95219,11 +95511,6 @@ function resolveSpurBin() {
|
|
|
95219
95511
|
}
|
|
95220
95512
|
|
|
95221
95513
|
// src/workflow/make-lifecycle-adapter.ts
|
|
95222
|
-
var GLOBAL_CONFIG_DIR = join25(".config", "spur");
|
|
95223
|
-
function globalConfigRoot(context4) {
|
|
95224
|
-
const override = context4.env.SPUR_GLOBAL_RULES_DIR;
|
|
95225
|
-
return override !== undefined && override.length > 0 ? resolve16(context4.cwd, override) : join25(homedir9(), GLOBAL_CONFIG_DIR);
|
|
95226
|
-
}
|
|
95227
95514
|
function resolveWorkflowPath(context4, profile) {
|
|
95228
95515
|
const bundledRoot = bundledConfigRoot();
|
|
95229
95516
|
if (bundledRoot !== null) {
|
|
@@ -95234,9 +95521,6 @@ function resolveWorkflowPath(context4, profile) {
|
|
|
95234
95521
|
const projectPath = join25(context4.cwd, ".spur", "workflows", `${profile.workflowName}.yaml`);
|
|
95235
95522
|
if (existsSync12(projectPath))
|
|
95236
95523
|
return projectPath;
|
|
95237
|
-
const globalPath = join25(globalConfigRoot(context4), "workflows", `${profile.workflowName}.yaml`);
|
|
95238
|
-
if (existsSync12(globalPath))
|
|
95239
|
-
return globalPath;
|
|
95240
95524
|
return null;
|
|
95241
95525
|
}
|
|
95242
95526
|
function makeLifecycleAdapter(context4, profile) {
|
|
@@ -95652,7 +95936,7 @@ import { createRequire } from "module";
|
|
|
95652
95936
|
var CLI_CONFIG = {
|
|
95653
95937
|
binaryName: "spur",
|
|
95654
95938
|
binaryLabel: "spur",
|
|
95655
|
-
binaryVersion: "0.3.
|
|
95939
|
+
binaryVersion: "0.3.62",
|
|
95656
95940
|
configDir: ".spur",
|
|
95657
95941
|
configFile: ".spur/config.yaml",
|
|
95658
95942
|
databaseFile: ".spur/spur.db"
|
|
@@ -95926,24 +96210,17 @@ function formatDailyResult(r) {
|
|
|
95926
96210
|
}
|
|
95927
96211
|
|
|
95928
96212
|
// src/commands/init.ts
|
|
96213
|
+
init_src();
|
|
95929
96214
|
init_loader();
|
|
95930
96215
|
init_src2();
|
|
95931
96216
|
init_dist10();
|
|
95932
|
-
import { homedir as
|
|
95933
|
-
import { join as join26, resolve as
|
|
96217
|
+
import { homedir as homedir9 } from "os";
|
|
96218
|
+
import { join as join26, resolve as resolve16 } from "path";
|
|
95934
96219
|
|
|
95935
96220
|
// src/config/scaffold-manifest.ts
|
|
95936
96221
|
var SCAFFOLD_MANIFEST = [
|
|
95937
96222
|
{ source: "rules/recommended-pre-check.yaml", target: "rules/recommended-pre-check.yaml" },
|
|
95938
96223
|
{ source: "rules/recommended-post-check.yaml", target: "rules/recommended-post-check.yaml" },
|
|
95939
|
-
{ source: "workflows/basic.yaml", target: "workflows/basic.yaml" },
|
|
95940
|
-
{ source: "workflows/task-lifecycle.yaml", target: "workflows/task-lifecycle.yaml" },
|
|
95941
|
-
{ source: "workflows/feature-lifecycle.yaml", target: "workflows/feature-lifecycle.yaml" },
|
|
95942
|
-
{ source: "workflows/feature-dev.yaml", target: "workflows/feature-dev.yaml" },
|
|
95943
|
-
{ source: "workflows/task-pipeline.yaml", target: "workflows/task-pipeline.yaml" },
|
|
95944
|
-
{ source: "workflows/idea-pipeline.yaml", target: "workflows/idea-pipeline.yaml" },
|
|
95945
|
-
{ source: "workflows/wrapup-pipeline.yaml", target: "workflows/wrapup-pipeline.yaml" },
|
|
95946
|
-
{ source: "workflows/pr-review.yaml", target: "workflows/pr-review.yaml" },
|
|
95947
96224
|
{ source: "tasks/section-matrix.yaml", target: "tasks/section-matrix.yaml" },
|
|
95948
96225
|
{ source: "templates/task/standard.md", target: "tasks/templates/standard.md" },
|
|
95949
96226
|
{ source: "templates/task/feature-impl.md", target: "tasks/templates/feature-impl.md" },
|
|
@@ -95951,9 +96228,6 @@ var SCAFFOLD_MANIFEST = [
|
|
|
95951
96228
|
{ source: "templates/task/review.md", target: "tasks/templates/review.md" },
|
|
95952
96229
|
{ source: "templates/task/brainstorm.md", target: "tasks/templates/brainstorm.md" },
|
|
95953
96230
|
{ source: "templates/task/meta.md", target: "tasks/templates/meta.md" },
|
|
95954
|
-
{ source: "templates/feature/default.md", target: "templates/feature/default.md" },
|
|
95955
|
-
{ source: "templates/bdd/gherkin.md", target: "templates/bdd/gherkin.md" },
|
|
95956
|
-
{ source: "templates/bdd/checklist.md", target: "templates/bdd/checklist.md" },
|
|
95957
96231
|
{
|
|
95958
96232
|
source: "templates/docs/99_PROJECT_CONSTITUTION.md",
|
|
95959
96233
|
target: "docs/99_PROJECT_CONSTITUTION.md",
|
|
@@ -95966,19 +96240,12 @@ var SCAFFOLD_MANIFEST = [
|
|
|
95966
96240
|
{ source: "templates/docs/03_ARCHITECTURE.md", target: "docs/03_ARCHITECTURE.md", root: true, preserve: true },
|
|
95967
96241
|
{ source: "templates/docs/04_DESIGN.md", target: "docs/04_DESIGN.md", root: true, preserve: true },
|
|
95968
96242
|
{ source: "templates/docs/05_FEATURES.md", target: "docs/05_FEATURES.md", root: true, preserve: true },
|
|
95969
|
-
{ source: "templates/docs/99_PROJECT_CONSTITUTION.md", target: "templates/docs/99_PROJECT_CONSTITUTION.md" },
|
|
95970
|
-
{ source: "templates/docs/00_ADR.md", target: "templates/docs/00_ADR.md" },
|
|
95971
|
-
{ source: "templates/docs/01_PRD.md", target: "templates/docs/01_PRD.md" },
|
|
95972
|
-
{ source: "templates/docs/02_ROADMAP.md", target: "templates/docs/02_ROADMAP.md" },
|
|
95973
|
-
{ source: "templates/docs/03_ARCHITECTURE.md", target: "templates/docs/03_ARCHITECTURE.md" },
|
|
95974
|
-
{ source: "templates/docs/04_DESIGN.md", target: "templates/docs/04_DESIGN.md" },
|
|
95975
|
-
{ source: "templates/docs/05_FEATURES.md", target: "templates/docs/05_FEATURES.md" },
|
|
95976
96243
|
{ source: "templates/AGENTS.md", target: "AGENTS.md", root: true, preserve: true }
|
|
95977
96244
|
];
|
|
95978
96245
|
|
|
95979
96246
|
// src/commands/init.ts
|
|
95980
|
-
var
|
|
95981
|
-
var GLOBAL_RULES_DIR2 = join26(
|
|
96247
|
+
var GLOBAL_CONFIG_DIR = join26(".config", "spur");
|
|
96248
|
+
var GLOBAL_RULES_DIR2 = join26(GLOBAL_CONFIG_DIR, "rules");
|
|
95982
96249
|
var GLOBAL_CONFIG_EXAMPLE = BUNDLED_GLOBAL_CONFIG;
|
|
95983
96250
|
var GLOBAL_CONFIG_FILE2 = "config.yaml";
|
|
95984
96251
|
var INDEXED_CONTEXT_MARKER = "## Indexed context";
|
|
@@ -96009,7 +96276,7 @@ If \`.spur/context/\` is absent, proceed normally. Never block work on its absen
|
|
|
96009
96276
|
`;
|
|
96010
96277
|
function globalRulesRoot(context4) {
|
|
96011
96278
|
const override = context4.env.SPUR_GLOBAL_RULES_DIR;
|
|
96012
|
-
return override !== undefined && override.length > 0 ?
|
|
96279
|
+
return override !== undefined && override.length > 0 ? resolve16(context4.cwd, override) : join26(homedir9(), GLOBAL_RULES_DIR2);
|
|
96013
96280
|
}
|
|
96014
96281
|
async function writeIfNew(context4, path9, content, force, result) {
|
|
96015
96282
|
if (!force && await context4.fs.exists(path9)) {
|
|
@@ -96035,12 +96302,15 @@ async function seedGlobalRules(context4) {
|
|
|
96035
96302
|
}
|
|
96036
96303
|
return written;
|
|
96037
96304
|
}
|
|
96305
|
+
function resolveGlobalConfigDir(context4) {
|
|
96306
|
+
const globalOverride = context4.env.SPUR_GLOBAL_RULES_DIR;
|
|
96307
|
+
return globalOverride !== undefined && globalOverride.length > 0 ? resolve16(context4.cwd, globalOverride) : join26(homedir9(), GLOBAL_CONFIG_DIR);
|
|
96308
|
+
}
|
|
96038
96309
|
async function seedGlobalConfig(context4) {
|
|
96039
96310
|
const source = bundledConfigRoot();
|
|
96040
96311
|
if (source === null)
|
|
96041
96312
|
return 0;
|
|
96042
|
-
const
|
|
96043
|
-
const target = globalOverride !== undefined && globalOverride.length > 0 ? resolve17(context4.cwd, globalOverride) : join26(homedir10(), GLOBAL_CONFIG_DIR2);
|
|
96313
|
+
const target = resolveGlobalConfigDir(context4);
|
|
96044
96314
|
let written = 0;
|
|
96045
96315
|
for (const relPath of listBundledConfigFiles()) {
|
|
96046
96316
|
if (relPath === GLOBAL_CONFIG_EXAMPLE)
|
|
@@ -96062,19 +96332,101 @@ async function seedGlobalConfig(context4) {
|
|
|
96062
96332
|
return written;
|
|
96063
96333
|
}
|
|
96064
96334
|
function registerInitCommand(program2, context4, options = {}) {
|
|
96065
|
-
program2.command("init", { hidden: options.hidden === true }).summary("scaffold a local Spur project").option(...SHARED_OPTIONS.nameProjectInit).option(...SHARED_OPTIONS.forceInitRecreate).option("--minimal", "Only write the minimal .spur scaffold").option(...SHARED_OPTIONS.json).action(async (options2) => {
|
|
96335
|
+
program2.command("init", { hidden: options.hidden === true }).summary("scaffold a local Spur project").option(...SHARED_OPTIONS.nameProjectInit).option(...SHARED_OPTIONS.forceInitRecreate).option("--minimal", "Only write the minimal .spur scaffold").option("--adopt-global-config", "Also rewrite ~/.config/spur/config.yaml from the shipped global default (backed up first)").option(...SHARED_OPTIONS.json).action(async (options2) => {
|
|
96066
96336
|
const json3 = options2.json === true;
|
|
96067
96337
|
const force = options2.force === true;
|
|
96068
96338
|
const minimal = options2.minimal === true;
|
|
96339
|
+
const adoptGlobal = options2.adoptGlobalConfig === true;
|
|
96069
96340
|
const projectName = options2.name ?? "default";
|
|
96070
96341
|
const configPath = join26(context4.cwd, CLI_CONFIG.configFile);
|
|
96342
|
+
const result = { created: [], skipped: [] };
|
|
96343
|
+
const globalConfigDir = resolveGlobalConfigDir(context4);
|
|
96344
|
+
const globalConfigPath = join26(globalConfigDir, GLOBAL_CONFIG_FILE2);
|
|
96345
|
+
const globalConfigExists = await context4.fs.exists(globalConfigPath);
|
|
96346
|
+
let misplacedKeys = [];
|
|
96347
|
+
if (globalConfigExists) {
|
|
96348
|
+
try {
|
|
96349
|
+
const raw = await context4.fs.readFile(globalConfigPath);
|
|
96350
|
+
misplacedKeys = misplacedGlobalKeys(parseConfigYaml2(raw));
|
|
96351
|
+
} catch {}
|
|
96352
|
+
}
|
|
96071
96353
|
if (!force && await context4.fs.exists(configPath)) {
|
|
96072
|
-
const
|
|
96073
|
-
|
|
96074
|
-
|
|
96354
|
+
const configRoot = bundledConfigRoot();
|
|
96355
|
+
if (configRoot !== null && !minimal) {
|
|
96356
|
+
for (const relPath of listBundledProjectSeedFiles()) {
|
|
96357
|
+
const sourcePath = join26(configRoot, relPath);
|
|
96358
|
+
if (!await context4.fs.exists(sourcePath))
|
|
96359
|
+
continue;
|
|
96360
|
+
const targetPath = join26(context4.cwd, CLI_CONFIG.configDir, relPath);
|
|
96361
|
+
await context4.fs.ensureDir(join26(targetPath, ".."));
|
|
96362
|
+
await writeIfNew(context4, targetPath, await context4.fs.readFile(sourcePath), false, result);
|
|
96363
|
+
}
|
|
96364
|
+
for (const entry of SCAFFOLD_MANIFEST) {
|
|
96365
|
+
const sourcePath = join26(configRoot, entry.source);
|
|
96366
|
+
if (!await context4.fs.exists(sourcePath))
|
|
96367
|
+
continue;
|
|
96368
|
+
const baseDir = entry.root === true ? context4.cwd : join26(context4.cwd, CLI_CONFIG.configDir);
|
|
96369
|
+
const targetPath = join26(baseDir, entry.target);
|
|
96370
|
+
await context4.fs.ensureDir(join26(targetPath, ".."));
|
|
96371
|
+
const entryForce = false;
|
|
96372
|
+
let body = await context4.fs.readFile(sourcePath);
|
|
96373
|
+
if (entry.target === "AGENTS.md") {
|
|
96374
|
+
body = substituteAgentsMdTemplate(body, projectName);
|
|
96375
|
+
}
|
|
96376
|
+
if (entry.source.startsWith("templates/docs/")) {
|
|
96377
|
+
body = substituteDocTemplateTokens(body);
|
|
96378
|
+
}
|
|
96379
|
+
await writeIfNew(context4, targetPath, body, entryForce, result);
|
|
96380
|
+
}
|
|
96381
|
+
}
|
|
96382
|
+
let adoptedGlobal = false;
|
|
96383
|
+
if (adoptGlobal && globalConfigExists) {
|
|
96384
|
+
const backupPath = `${globalConfigPath}.bak-${new Date().toISOString().replace(/[:.]/g, "-")}`;
|
|
96385
|
+
await context4.fs.writeFile(backupPath, await context4.fs.readFile(globalConfigPath));
|
|
96386
|
+
const bundledRoot = bundledConfigRoot();
|
|
96387
|
+
const examplePath = bundledRoot !== null ? join26(bundledRoot, GLOBAL_CONFIG_EXAMPLE) : null;
|
|
96388
|
+
if (examplePath !== null && await context4.fs.exists(examplePath)) {
|
|
96389
|
+
await context4.fs.writeFile(globalConfigPath, await context4.fs.readFile(examplePath));
|
|
96390
|
+
adoptedGlobal = true;
|
|
96391
|
+
}
|
|
96392
|
+
result.created.push(backupPath);
|
|
96393
|
+
}
|
|
96394
|
+
const rulesSeeded2 = await seedGlobalRules(context4);
|
|
96395
|
+
const configSeeded2 = await seedGlobalConfig(context4);
|
|
96396
|
+
const payload = {
|
|
96397
|
+
ok: true,
|
|
96398
|
+
converged: true,
|
|
96399
|
+
config: CLI_CONFIG.configFile,
|
|
96400
|
+
...result,
|
|
96401
|
+
globalRulesSeeded: rulesSeeded2,
|
|
96402
|
+
globalConfigSeeded: configSeeded2,
|
|
96403
|
+
...adoptedGlobal ? { adoptGlobalConfig: adoptedGlobal } : {},
|
|
96404
|
+
...misplacedKeys.length > 0 ? { misplacedGlobalKeys: misplacedKeys } : {}
|
|
96405
|
+
};
|
|
96406
|
+
if (json3) {
|
|
96407
|
+
context4.output.write(toJson2(payload));
|
|
96408
|
+
} else {
|
|
96409
|
+
context4.output.write("Already initialized \u2014 converged (no project files overwritten)");
|
|
96410
|
+
for (const path9 of result.created)
|
|
96411
|
+
context4.output.write(` \u2713 ${path9}`);
|
|
96412
|
+
for (const path9 of result.skipped)
|
|
96413
|
+
context4.output.write(` - ${path9} (exists)`);
|
|
96414
|
+
if (rulesSeeded2 > 0) {
|
|
96415
|
+
context4.output.write(` \u2713 seeded ${rulesSeeded2} rule file(s) to ~/${GLOBAL_RULES_DIR2}`);
|
|
96416
|
+
}
|
|
96417
|
+
if (configSeeded2 > 0) {
|
|
96418
|
+
context4.output.write(` \u2713 seeded ${configSeeded2} config file(s) to ~/${GLOBAL_CONFIG_DIR}`);
|
|
96419
|
+
}
|
|
96420
|
+
if (adoptedGlobal) {
|
|
96421
|
+
context4.output.write(" \u2713 adopted global config from bundled default (backup written)");
|
|
96422
|
+
}
|
|
96423
|
+
if (misplacedKeys.length > 0) {
|
|
96424
|
+
context4.output.write(` \u26A0 global config carries project-shaped key(s): ${misplacedKeys.join(", ")}`);
|
|
96425
|
+
}
|
|
96426
|
+
}
|
|
96427
|
+
context4.setExitCode(0);
|
|
96075
96428
|
return;
|
|
96076
96429
|
}
|
|
96077
|
-
const result = { created: [], skipped: [] };
|
|
96078
96430
|
const configYaml = `${[
|
|
96079
96431
|
`# Spur project configuration for ${projectName}`,
|
|
96080
96432
|
`# Generated by \`spur init\``,
|
|
@@ -96128,8 +96480,6 @@ ${contextEntry}
|
|
|
96128
96480
|
const configRoot = bundledConfigRoot();
|
|
96129
96481
|
if (configRoot !== null) {
|
|
96130
96482
|
for (const relPath of listBundledProjectSeedFiles()) {
|
|
96131
|
-
if (relPath.startsWith("templates/docs/"))
|
|
96132
|
-
continue;
|
|
96133
96483
|
const sourcePath = join26(configRoot, relPath);
|
|
96134
96484
|
if (!await context4.fs.exists(sourcePath))
|
|
96135
96485
|
continue;
|
|
@@ -96188,7 +96538,7 @@ ${contextEntry}
|
|
|
96188
96538
|
context4.output.write(` \u2713 seeded ${rulesSeeded} rule file(s) to ~/${GLOBAL_RULES_DIR2}`);
|
|
96189
96539
|
}
|
|
96190
96540
|
if (configSeeded > 0) {
|
|
96191
|
-
context4.output.write(` \u2713 seeded ${configSeeded} config file(s) to ~/${
|
|
96541
|
+
context4.output.write(` \u2713 seeded ${configSeeded} config file(s) to ~/${GLOBAL_CONFIG_DIR}`);
|
|
96192
96542
|
}
|
|
96193
96543
|
}
|
|
96194
96544
|
});
|
|
@@ -96243,7 +96593,11 @@ function registerMessageCommand(program2, context4) {
|
|
|
96243
96593
|
async function runMessageSend(svc, context4, body, options) {
|
|
96244
96594
|
const trimmed = body.trim();
|
|
96245
96595
|
if (trimmed === "") {
|
|
96246
|
-
|
|
96596
|
+
if (options.json) {
|
|
96597
|
+
context4.output.write(toJson2({ error: { code: "usage", message: "message send requires a non-empty body" } }));
|
|
96598
|
+
} else {
|
|
96599
|
+
context4.output.error("message send requires a non-empty body");
|
|
96600
|
+
}
|
|
96247
96601
|
return 2;
|
|
96248
96602
|
}
|
|
96249
96603
|
const from = options.from || DEFAULT_FROM;
|
|
@@ -96401,15 +96755,15 @@ async function runMessageWatch(svc, output2, options, runtime = {}) {
|
|
|
96401
96755
|
}
|
|
96402
96756
|
}
|
|
96403
96757
|
function defaultSleep(ms, signal) {
|
|
96404
|
-
return new Promise((
|
|
96758
|
+
return new Promise((resolve17) => {
|
|
96405
96759
|
if (signal?.aborted) {
|
|
96406
|
-
|
|
96760
|
+
resolve17();
|
|
96407
96761
|
return;
|
|
96408
96762
|
}
|
|
96409
|
-
const timer = setTimeout(
|
|
96763
|
+
const timer = setTimeout(resolve17, ms);
|
|
96410
96764
|
signal?.addEventListener("abort", () => {
|
|
96411
96765
|
clearTimeout(timer);
|
|
96412
|
-
|
|
96766
|
+
resolve17();
|
|
96413
96767
|
}, { once: true });
|
|
96414
96768
|
});
|
|
96415
96769
|
}
|
|
@@ -96436,15 +96790,15 @@ function parseTimeout2(raw) {
|
|
|
96436
96790
|
return n3;
|
|
96437
96791
|
}
|
|
96438
96792
|
function sendSleep(ms, signal) {
|
|
96439
|
-
return new Promise((
|
|
96793
|
+
return new Promise((resolve17) => {
|
|
96440
96794
|
if (signal?.aborted) {
|
|
96441
|
-
|
|
96795
|
+
resolve17();
|
|
96442
96796
|
return;
|
|
96443
96797
|
}
|
|
96444
|
-
const timer = setTimeout(
|
|
96798
|
+
const timer = setTimeout(resolve17, ms);
|
|
96445
96799
|
signal?.addEventListener("abort", () => {
|
|
96446
96800
|
clearTimeout(timer);
|
|
96447
|
-
|
|
96801
|
+
resolve17();
|
|
96448
96802
|
}, { once: true });
|
|
96449
96803
|
});
|
|
96450
96804
|
}
|
|
@@ -96514,12 +96868,12 @@ function registerMigrateCommand(program2, context4, options = {}) {
|
|
|
96514
96868
|
// src/commands/projects.ts
|
|
96515
96869
|
init_dist5();
|
|
96516
96870
|
await init_src3();
|
|
96517
|
-
import { basename as basename9, resolve as
|
|
96871
|
+
import { basename as basename9, resolve as resolve17 } from "path";
|
|
96518
96872
|
function registerProjectsCommand(program2, context4) {
|
|
96519
96873
|
const projectsCmd = program2.command("projects").summary("manage the Spur multi-project registry");
|
|
96520
96874
|
projectsCmd.command("add").argument("<path>", "Project root directory path").option(...SHARED_OPTIONS.nameProjectDisplay).option(...SHARED_OPTIONS.jsonProjectsResponse).action(async (pathArg, options) => {
|
|
96521
96875
|
try {
|
|
96522
|
-
const absolutePath =
|
|
96876
|
+
const absolutePath = resolve17(context4.cwd, pathArg);
|
|
96523
96877
|
if (!await context4.fs.exists(absolutePath)) {
|
|
96524
96878
|
throw new Error(`Directory does not exist: ${absolutePath}`);
|
|
96525
96879
|
}
|
|
@@ -97227,8 +97581,8 @@ class EventPublisher {
|
|
|
97227
97581
|
if (bufferedEvents.length > 0) {
|
|
97228
97582
|
return { done: false, value: bufferedEvents.shift() };
|
|
97229
97583
|
}
|
|
97230
|
-
return new Promise((
|
|
97231
|
-
pullResolvers.push([
|
|
97584
|
+
return new Promise((resolve18, reject) => {
|
|
97585
|
+
pullResolvers.push([resolve18, reject]);
|
|
97232
97586
|
});
|
|
97233
97587
|
}, async () => {
|
|
97234
97588
|
unsubscribe();
|
|
@@ -106440,7 +106794,8 @@ function createServerContext(appRt, options) {
|
|
|
106440
106794
|
fs: fs3,
|
|
106441
106795
|
getDb: this.getDb.bind(this),
|
|
106442
106796
|
eventBus: bridgeEventBus(eventsBus),
|
|
106443
|
-
events: bridgeEventBus(eventsBus)
|
|
106797
|
+
events: bridgeEventBus(eventsBus),
|
|
106798
|
+
...options.spurConfig !== undefined ? { spurConfig: options.spurConfig } : {}
|
|
106444
106799
|
});
|
|
106445
106800
|
}
|
|
106446
106801
|
return teamSvc;
|
|
@@ -106507,6 +106862,7 @@ function createServerContext(appRt, options) {
|
|
|
106507
106862
|
agentService: this.agentService.bind(this),
|
|
106508
106863
|
ruleService: this.ruleService.bind(this),
|
|
106509
106864
|
hitlResponder: this.hitlResponder.bind(this),
|
|
106865
|
+
...options.spurConfig !== undefined ? { spurConfig: options.spurConfig } : {},
|
|
106510
106866
|
observabilityBus: () => bridgeEventBus(eventsBus),
|
|
106511
106867
|
events: () => bridgeEventBus(eventsBus)
|
|
106512
106868
|
});
|
|
@@ -106780,6 +107136,7 @@ async function startServer(options, deps = defaultDeps) {
|
|
|
106780
107136
|
if (!webDistPath) {
|
|
106781
107137
|
appRt.logger.warn("Board UI static assets not found \u2014 /board will return 404. " + "Reinstall a package that includes the web board, or set server.webDistPath to a built dist/web directory (index.html).");
|
|
106782
107138
|
}
|
|
107139
|
+
const spurConfig = await loadSpurConfig(process.cwd()).catch(() => null);
|
|
106783
107140
|
const ctx = deps.createServerContext(appRt, {
|
|
106784
107141
|
cwd: process.cwd(),
|
|
106785
107142
|
fs: fs3,
|
|
@@ -106790,10 +107147,10 @@ async function startServer(options, deps = defaultDeps) {
|
|
|
106790
107147
|
jobQueueEnabled: bootConfig.jobqueue.enabled,
|
|
106791
107148
|
scheduler: scheduler3,
|
|
106792
107149
|
teamAutostart: bootConfig.teamAutostart,
|
|
106793
|
-
bootConfig
|
|
107150
|
+
bootConfig,
|
|
107151
|
+
...spurConfig !== undefined ? { spurConfig } : {}
|
|
106794
107152
|
});
|
|
106795
107153
|
let jobWorker;
|
|
106796
|
-
const spurConfig = await loadSpurConfig(process.cwd()).catch(() => null);
|
|
106797
107154
|
const autostartIds = resolveAutostartSet(spurConfig, env.SPUR_TEAM_AUTOSTART);
|
|
106798
107155
|
if (autostartIds.length > 0) {
|
|
106799
107156
|
try {
|
|
@@ -107164,7 +107521,7 @@ var spur_config_schema_default = {
|
|
|
107164
107521
|
},
|
|
107165
107522
|
version: {
|
|
107166
107523
|
type: "string",
|
|
107167
|
-
description: "Config schema version (string, not integer). Current recommended: '1.
|
|
107524
|
+
description: "Config schema version (string, not integer). Current recommended: '1.2' (config-1.2 layered global/project merge, ADR-033 executor tiers + planning blocks). '1' remains accepted for backward compatibility."
|
|
107168
107525
|
},
|
|
107169
107526
|
name: {
|
|
107170
107527
|
type: "string",
|
|
@@ -107884,17 +108241,11 @@ var EMBEDDED_SPUR_SCHEMAS = new Map([
|
|
|
107884
108241
|
]);
|
|
107885
108242
|
|
|
107886
108243
|
// src/history-refresh.ts
|
|
107887
|
-
init_loader();
|
|
107888
108244
|
init_dist6();
|
|
107889
108245
|
await init_src3();
|
|
107890
108246
|
async function maybeTriggerHistoryRefresh(context4, trigger, triggerId) {
|
|
107891
108247
|
try {
|
|
107892
|
-
|
|
107893
|
-
try {
|
|
107894
|
-
config4 = await loadSpurConfig(context4.cwd, { embeddedSchemas: EMBEDDED_SPUR_SCHEMAS });
|
|
107895
|
-
} catch {
|
|
107896
|
-
config4 = null;
|
|
107897
|
-
}
|
|
108248
|
+
const config4 = context4.spurConfig ?? null;
|
|
107898
108249
|
const db2 = await context4.getDb();
|
|
107899
108250
|
const result = await enqueueHistoryRefresh(db2, { config: config4, trigger, triggerId });
|
|
107900
108251
|
if (result.status === "disabled")
|
|
@@ -109196,7 +109547,7 @@ init_dist6();
|
|
|
109196
109547
|
init_dist5();
|
|
109197
109548
|
await init_src3();
|
|
109198
109549
|
import { closeSync as closeSync5, fstatSync as fstatSync3, openSync as openSync5, readSync as readSync3 } from "fs";
|
|
109199
|
-
import { join as join34
|
|
109550
|
+
import { join as join34 } from "path";
|
|
109200
109551
|
import { createInterface } from "readline";
|
|
109201
109552
|
import { setTimeout as sleep5 } from "timers/promises";
|
|
109202
109553
|
|
|
@@ -109349,13 +109700,20 @@ function submitSteeringLine(controller, output2, line) {
|
|
|
109349
109700
|
if (ack === undefined)
|
|
109350
109701
|
output2.error(`[steer] ignored command: ${line}`);
|
|
109351
109702
|
}
|
|
109352
|
-
|
|
109353
|
-
|
|
109354
|
-
|
|
109355
|
-
|
|
109356
|
-
|
|
109357
|
-
|
|
109703
|
+
var BUNDLED_PATH_PREFIX = "bundled:";
|
|
109704
|
+
function resolveWorkflowPaths(config4) {
|
|
109705
|
+
const paths = config4?.workflows?.paths ?? [".spur/workflows/"];
|
|
109706
|
+
const bundledRoot = bundledConfigRoot();
|
|
109707
|
+
const expanded = [];
|
|
109708
|
+
for (const path9 of paths) {
|
|
109709
|
+
if (path9.startsWith(BUNDLED_PATH_PREFIX)) {
|
|
109710
|
+
if (bundledRoot !== null)
|
|
109711
|
+
expanded.push(join34(bundledRoot, path9.slice(BUNDLED_PATH_PREFIX.length)));
|
|
109712
|
+
} else {
|
|
109713
|
+
expanded.push(path9);
|
|
109714
|
+
}
|
|
109358
109715
|
}
|
|
109716
|
+
return expanded;
|
|
109359
109717
|
}
|
|
109360
109718
|
function registerWorkflowCommand(program2, context4) {
|
|
109361
109719
|
const makeSvc = (json3, bus) => new WorkflowAppService({
|
|
@@ -109506,8 +109864,11 @@ Monitor with: spur workflow trace ${runId2} --follow`);
|
|
|
109506
109864
|
let planPreview;
|
|
109507
109865
|
if (options.plan !== false) {
|
|
109508
109866
|
try {
|
|
109509
|
-
const
|
|
109510
|
-
|
|
109867
|
+
const resolved = resolveWorkflowFile(context4.cwd, file2);
|
|
109868
|
+
if (resolved.path !== null) {
|
|
109869
|
+
const def = await loadWorkflowDef(resolved.path, { validateSchema: false });
|
|
109870
|
+
planPreview = renderRunPlan(def);
|
|
109871
|
+
}
|
|
109511
109872
|
} catch {}
|
|
109512
109873
|
}
|
|
109513
109874
|
const runLog = options.log === false ? undefined : new WorkflowRunLogSink({
|
|
@@ -109515,7 +109876,7 @@ Monitor with: spur workflow trace ${runId2} --follow`);
|
|
|
109515
109876
|
dir: join34(context4.cwd, ".spur", "run"),
|
|
109516
109877
|
runId,
|
|
109517
109878
|
...planPreview !== undefined ? { planPreview } : {},
|
|
109518
|
-
...
|
|
109879
|
+
...resolveOutputLogConfig(context4.spurConfig ?? null)
|
|
109519
109880
|
});
|
|
109520
109881
|
if (humanProgress) {
|
|
109521
109882
|
context4.output.write(`Run: ${runId}`);
|
|
@@ -109562,10 +109923,13 @@ Monitor with: spur workflow trace ${runId2} --follow`);
|
|
|
109562
109923
|
const steeringController = options.steer === true ? await (async () => {
|
|
109563
109924
|
let identity7;
|
|
109564
109925
|
try {
|
|
109565
|
-
const
|
|
109566
|
-
|
|
109567
|
-
|
|
109568
|
-
|
|
109926
|
+
const resolved = resolveWorkflowFile(context4.cwd, file2);
|
|
109927
|
+
if (resolved.path !== null) {
|
|
109928
|
+
const def = await loadWorkflowDef(resolved.path, {
|
|
109929
|
+
validateSchema: false
|
|
109930
|
+
});
|
|
109931
|
+
identity7 = createWorkflowEventIdentity(def);
|
|
109932
|
+
}
|
|
109569
109933
|
} catch {}
|
|
109570
109934
|
return new WorkflowSteeringController((ack) => {
|
|
109571
109935
|
bus.emit("workflow.steering", identity7 === undefined ? ack : decorateWorkflowEvent(identity7, "workflow.steering", ack));
|
|
@@ -109674,7 +110038,7 @@ Monitor with: spur workflow trace ${runId2} --follow`);
|
|
|
109674
110038
|
}
|
|
109675
110039
|
const svc = makeSvc(options.json);
|
|
109676
110040
|
const result = logsOnly ? undefined : await svc.clean(minutes, dryRun);
|
|
109677
|
-
const retentionDays =
|
|
110041
|
+
const retentionDays = resolveWorkflowLogRetentionDays(context4.spurConfig ?? null);
|
|
109678
110042
|
const logResult2 = await svc.cleanRunLogs(retentionDays, dryRun);
|
|
109679
110043
|
if (options.json) {
|
|
109680
110044
|
context4.output.write(toJson2(logsOnly ? logResult2 : { ...result, logs: logResult2 }));
|
|
@@ -109723,7 +110087,7 @@ Monitor with: spur workflow trace ${runId2} --follow`);
|
|
|
109723
110087
|
}
|
|
109724
110088
|
});
|
|
109725
110089
|
workflow.command("list").description("List available workflow YAML files.").option(...SHARED_OPTIONS.jsonSupported).action(async (options) => {
|
|
109726
|
-
const paths =
|
|
110090
|
+
const paths = resolveWorkflowPaths(context4.spurConfig ?? null);
|
|
109727
110091
|
const result = await makeSvc().list(paths);
|
|
109728
110092
|
if (options.json) {
|
|
109729
110093
|
context4.output.write(toJson2(result));
|
|
@@ -109732,7 +110096,14 @@ Monitor with: spur workflow trace ${runId2} --follow`);
|
|
|
109732
110096
|
}
|
|
109733
110097
|
});
|
|
109734
110098
|
workflow.command("show").description("Render a workflow definition as a mermaid FSM diagram.").argument("<file>", "Workflow YAML file").action(async (file2) => {
|
|
109735
|
-
const
|
|
110099
|
+
const resolved = resolveWorkflowFile(context4.cwd, file2);
|
|
110100
|
+
if (resolved.path === null) {
|
|
110101
|
+
const [probedProject, probedBundled] = resolved.probed;
|
|
110102
|
+
context4.output.error(`workflow show: file not found: ${probedProject}${probedBundled !== null ? ` (bundled: ${probedBundled})` : ""}`);
|
|
110103
|
+
context4.setExitCode(1);
|
|
110104
|
+
return;
|
|
110105
|
+
}
|
|
110106
|
+
const filePath = resolved.path;
|
|
109736
110107
|
let def;
|
|
109737
110108
|
try {
|
|
109738
110109
|
def = await loadWorkflowDef(filePath, { validateSchema: true });
|
|
@@ -110046,7 +110417,7 @@ init_src();
|
|
|
110046
110417
|
init_src2();
|
|
110047
110418
|
init_dist5();
|
|
110048
110419
|
await init_src3();
|
|
110049
|
-
import { dirname as dirname22, join as join35, resolve as
|
|
110420
|
+
import { dirname as dirname22, join as join35, resolve as resolve18 } from "path";
|
|
110050
110421
|
import { isatty as isatty4 } from "tty";
|
|
110051
110422
|
|
|
110052
110423
|
// ../../node_modules/.bun/@clack+core@1.4.1/node_modules/@clack/core/dist/index.mjs
|
|
@@ -111461,10 +111832,12 @@ function resolveAgentRoles(agentConfig) {
|
|
|
111461
111832
|
return resolved;
|
|
111462
111833
|
}
|
|
111463
111834
|
function createCliContext(options) {
|
|
111464
|
-
const cwd =
|
|
111835
|
+
const cwd = resolve18(options.cwd ?? process.cwd());
|
|
111465
111836
|
const env = options.env ?? process.env;
|
|
111466
111837
|
const fs3 = createNodeFileSystem3(cwd);
|
|
111467
|
-
const
|
|
111838
|
+
const agentConfig = options.agentConfig ?? options.spurConfig?.agent;
|
|
111839
|
+
const agentRoles = options.agentRoles ?? resolveAgentRoles(agentConfig);
|
|
111840
|
+
const agentRolesSource = agentConfig?.roles === undefined ? "fallback" : "config";
|
|
111468
111841
|
let dbPromise;
|
|
111469
111842
|
if (options.db) {
|
|
111470
111843
|
dbPromise = Promise.resolve(options.db);
|
|
@@ -111481,13 +111854,16 @@ function createCliContext(options) {
|
|
|
111481
111854
|
output: options.output,
|
|
111482
111855
|
getDb,
|
|
111483
111856
|
...options.agentConfig !== undefined ? { agentConfig: options.agentConfig } : {},
|
|
111857
|
+
...options.spurConfig !== undefined ? { spurConfig: options.spurConfig } : {},
|
|
111484
111858
|
agentRoles,
|
|
111859
|
+
agentRolesSource,
|
|
111485
111860
|
agentService: (serviceOptions) => new AgentService({
|
|
111486
111861
|
cwd,
|
|
111487
111862
|
env,
|
|
111488
111863
|
output: options.output,
|
|
111489
|
-
agentConfig
|
|
111864
|
+
agentConfig,
|
|
111490
111865
|
roles: agentRoles,
|
|
111866
|
+
rolesSource: agentRolesSource,
|
|
111491
111867
|
getDb,
|
|
111492
111868
|
...serviceOptions?.events !== undefined ? { events: serviceOptions.events } : {},
|
|
111493
111869
|
...serviceOptions?.processRegistry !== undefined ? { processRegistry: serviceOptions.processRegistry } : {}
|
|
@@ -111516,34 +111892,46 @@ async function createMigratedDbAdapter(cwd = process.cwd(), env = process.env, d
|
|
|
111516
111892
|
async function main(argv = process.argv.slice(2), options = {}) {
|
|
111517
111893
|
const output2 = options.output ?? consoleOutput;
|
|
111518
111894
|
let exitCode = 0;
|
|
111519
|
-
const
|
|
111520
|
-
const
|
|
111895
|
+
const cwd = options.cwd ?? process.cwd();
|
|
111896
|
+
const env = options.env ?? process.env;
|
|
111897
|
+
const configFile = resolveConfigFile(cwd);
|
|
111898
|
+
const db2 = options.db ?? await createMigratedDbAdapter(cwd, env, options.dbUrl);
|
|
111899
|
+
let spurConfig;
|
|
111900
|
+
try {
|
|
111901
|
+
spurConfig = await loadSpurConfig(cwd, { embeddedSchemas: EMBEDDED_SPUR_SCHEMAS });
|
|
111902
|
+
} catch (err) {
|
|
111903
|
+
const message = errorMessage4(err);
|
|
111904
|
+
if (argv.includes("--json")) {
|
|
111905
|
+
output2.write(toJson2({ error: { code: "config", message } }));
|
|
111906
|
+
} else {
|
|
111907
|
+
output2.error(message);
|
|
111908
|
+
}
|
|
111909
|
+
await db2.close();
|
|
111910
|
+
return 1;
|
|
111911
|
+
}
|
|
111521
111912
|
try {
|
|
111522
111913
|
if (configFile !== undefined) {
|
|
111523
|
-
await loadSpurConfig(options.cwd ?? process.cwd(), { embeddedSchemas: EMBEDDED_SPUR_SCHEMAS });
|
|
111524
111914
|
const app = await runNodeApplication({
|
|
111525
111915
|
configLoader: {
|
|
111526
111916
|
configFile,
|
|
111527
|
-
bootstrapSection: "bootstrap"
|
|
111528
|
-
appConfig: { safeParse: (raw2) => spurConfigSchema.safeParse(raw2) }
|
|
111917
|
+
bootstrapSection: "bootstrap"
|
|
111529
111918
|
},
|
|
111530
111919
|
config: { logging: { console: false } },
|
|
111531
111920
|
services: { db: db2 },
|
|
111532
111921
|
async start(appRt) {
|
|
111533
111922
|
const context4 = createCliContext({
|
|
111534
|
-
cwd
|
|
111535
|
-
env
|
|
111923
|
+
cwd,
|
|
111924
|
+
env,
|
|
111536
111925
|
output: output2,
|
|
111537
111926
|
db: db2,
|
|
111538
|
-
|
|
111927
|
+
spurConfig
|
|
111539
111928
|
});
|
|
111540
111929
|
exitCode = await runCommandDispatch(argv, context4, output2);
|
|
111541
111930
|
}
|
|
111542
111931
|
});
|
|
111543
111932
|
await app.stop("shutdown");
|
|
111544
111933
|
} else {
|
|
111545
|
-
const
|
|
111546
|
-
const context4 = createCliContext(ctxOpts);
|
|
111934
|
+
const context4 = createCliContext({ cwd, env, output: output2, db: db2, spurConfig });
|
|
111547
111935
|
exitCode = await runCommandDispatch(argv, context4, output2);
|
|
111548
111936
|
}
|
|
111549
111937
|
} finally {
|