@gobing-ai/spur 0.3.61 → 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.global.yaml +64 -57
- package/config/corpus-baseline.json +409 -49
- package/config/plugin-scripts.json +2 -2
- package/config/rules/boundary/config-loading-ownership.yaml +21 -0
- package/config/workflows/history-anatomy.yaml +366 -0
- package/package.json +1 -1
- package/plugins/sp/README.md +19 -6
- package/plugins/sp/commands/dev-find-issue.md +25 -46
- package/plugins/sp/commands/dev-run.md +22 -3
- 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 +5 -5
- package/plugins/sp/scripts/history-anatomy-cache.mjs +669 -0
- package/plugins/sp/scripts/history-anatomy-cache.ts +818 -0
- 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/spur-dev/references/dev-operations.md +2 -2
- package/plugins/sp/skills/spur-dev/references/execution-batch.md +14 -1
- package/plugins/sp/skills/spur-dev/references/execution-workflow.md +7 -0
- package/plugins/sp/skills/spur-dev/references/flag-glossary.md +25 -13
- package/spur.js +1091 -823
- package/web/_astro/BoardApp.Z9jMwI9G.js +1 -0
- package/web/_astro/BoardApp.rkWGVwwK.js +178 -0
- package/web/_astro/{TaskDetail.D2N60cfE.js → TaskDetail.B7ODt_bA.js} +1 -1
- package/web/_astro/{arc.D-EfJJwf.js → arc.C5QRz6AQ.js} +1 -1
- package/web/_astro/{architectureDiagram-3BPJPVTR.CgvTTzqp.js → architectureDiagram-3BPJPVTR.CHptn8gZ.js} +1 -1
- package/web/_astro/{blockDiagram-GPEHLZMM.CnOohvvn.js → blockDiagram-GPEHLZMM.b1nEDkDw.js} +1 -1
- package/web/_astro/{c4Diagram-AAUBKEIU.BFcBGUy_.js → c4Diagram-AAUBKEIU.BWj8S_Qq.js} +1 -1
- package/web/_astro/channel.BJtn6CGV.js +1 -0
- package/web/_astro/{chunk-2J33WTMH.C-6MR-XY.js → chunk-2J33WTMH.q0BBuE1n.js} +1 -1
- package/web/_astro/{chunk-4BX2VUAB.BN4LP5AR.js → chunk-4BX2VUAB.DP2KDkAU.js} +1 -1
- package/web/_astro/{chunk-55IACEB6.tUJ_CTtZ.js → chunk-55IACEB6.CkCId72p.js} +1 -1
- package/web/_astro/{chunk-727SXJPM.BNCk-sxv.js → chunk-727SXJPM.oHWzxMot.js} +1 -1
- package/web/_astro/{chunk-AQP2D5EJ.BkpFIbNa.js → chunk-AQP2D5EJ.DkkgxfMP.js} +1 -1
- package/web/_astro/{chunk-FMBD7UC4.DcSZ87PN.js → chunk-FMBD7UC4.lmFJDvRK.js} +1 -1
- package/web/_astro/{chunk-ND2GUHAM.BkLvHFFf.js → chunk-ND2GUHAM.52jt0eHK.js} +1 -1
- package/web/_astro/{chunk-QZHKN3VN.HOdgszax.js → chunk-QZHKN3VN.Cg8KEFoD.js} +1 -1
- package/web/_astro/{classDiagram-4FO5ZUOK.CWfRiY6b.js → classDiagram-4FO5ZUOK.BuOUhxcD.js} +1 -1
- package/web/_astro/{classDiagram-v2-Q7XG4LA2.CWfRiY6b.js → classDiagram-v2-Q7XG4LA2.BuOUhxcD.js} +1 -1
- package/web/_astro/{cose-bilkent-S5V4N54A.C6j4PxoN.js → cose-bilkent-S5V4N54A.BRUU8E_0.js} +1 -1
- package/web/_astro/{dagre-BM42HDAG.BATZG1II.js → dagre-BM42HDAG.GDbfFYVV.js} +1 -1
- package/web/_astro/{diagram-2AECGRRQ.B0f5yY6x.js → diagram-2AECGRRQ.CvIDBeJF.js} +1 -1
- package/web/_astro/{diagram-5GNKFQAL.Bewupqv0.js → diagram-5GNKFQAL.DMgJjWOX.js} +1 -1
- package/web/_astro/{diagram-KO2AKTUF.C23r1tB2.js → diagram-KO2AKTUF.njjl-0AP.js} +1 -1
- package/web/_astro/{diagram-LMA3HP47.DUErdBOR.js → diagram-LMA3HP47.CcCqgP8M.js} +1 -1
- package/web/_astro/{diagram-OG6HWLK6.BubmwAjb.js → diagram-OG6HWLK6.Btqd-YVE.js} +1 -1
- package/web/_astro/{erDiagram-TEJ5UH35.BE_Qs5mv.js → erDiagram-TEJ5UH35.BbhML_Xo.js} +1 -1
- package/web/_astro/{flowDiagram-I6XJVG4X.COWdbzon.js → flowDiagram-I6XJVG4X.CkvsIgY8.js} +1 -1
- package/web/_astro/{ganttDiagram-6RSMTGT7.5EGYC4MK.js → ganttDiagram-6RSMTGT7.m8IWD_wW.js} +1 -1
- package/web/_astro/{gitGraphDiagram-PVQCEYII.bUUV7iEw.js → gitGraphDiagram-PVQCEYII.5z87HXO-.js} +1 -1
- package/web/_astro/{index.Cestp9nh.css → index.nWve6EHS.css} +1 -1
- package/web/_astro/{infoDiagram-5YYISTIA.CbiInFvz.js → infoDiagram-5YYISTIA.Bvyvsd7Q.js} +1 -1
- package/web/_astro/{ishikawaDiagram-YF4QCWOH.CB7lrSsJ.js → ishikawaDiagram-YF4QCWOH.DdWVYO87.js} +1 -1
- package/web/_astro/{journeyDiagram-JHISSGLW.rhGZgWt8.js → journeyDiagram-JHISSGLW.C3kOlYH1.js} +1 -1
- package/web/_astro/{kanban-definition-UN3LZRKU.DPeZD_lP.js → kanban-definition-UN3LZRKU.CfKTUHVC.js} +1 -1
- package/web/_astro/{linear.l60Nyp5b.js → linear.CMDHnzgX.js} +1 -1
- package/web/_astro/{mermaid.core.DmtMJcmL.js → mermaid.core.DN7-WrsP.js} +4 -4
- package/web/_astro/{mindmap-definition-RKZ34NQL.Cc47AcCn.js → mindmap-definition-RKZ34NQL.DcQxLvqG.js} +1 -1
- package/web/_astro/{pieDiagram-4H26LBE5.B8cN-S9g.js → pieDiagram-4H26LBE5.Nu-Inbw6.js} +1 -1
- package/web/_astro/{quadrantDiagram-W4KKPZXB.DY1FN89L.js → quadrantDiagram-W4KKPZXB.Dck2EChs.js} +1 -1
- package/web/_astro/{requirementDiagram-4Y6WPE33.CnM6VbV8.js → requirementDiagram-4Y6WPE33.C--E5XuW.js} +1 -1
- package/web/_astro/{sankeyDiagram-5OEKKPKP.B9DcGfNV.js → sankeyDiagram-5OEKKPKP.B_0iRNna.js} +1 -1
- package/web/_astro/{sequenceDiagram-3UESZ5HK.ymxaNlAY.js → sequenceDiagram-3UESZ5HK.PKuKr9mk.js} +1 -1
- package/web/_astro/{stateDiagram-AJRCARHV.DDOJ3d8P.js → stateDiagram-AJRCARHV.ClhGHb-O.js} +1 -1
- package/web/_astro/{stateDiagram-v2-BHNVJYJU.Ck0Nb_KY.js → stateDiagram-v2-BHNVJYJU.Bv6BBnvg.js} +1 -1
- package/web/_astro/{timeline-definition-PNZ67QCA.BNOvZwAN.js → timeline-definition-PNZ67QCA.BZm2ZvAH.js} +1 -1
- package/web/_astro/{vennDiagram-CIIHVFJN.D3k5ivSF.js → vennDiagram-CIIHVFJN.Dt6yZXry.js} +1 -1
- package/web/_astro/{wardley-L42UT6IY.BylaxVqn.js → wardley-L42UT6IY.rUs-E00M.js} +1 -1
- package/web/_astro/{wardleyDiagram-YWT4CUSO.HLNtFUm9.js → wardleyDiagram-YWT4CUSO.BcWgv4cA.js} +1 -1
- package/web/_astro/{xychartDiagram-2RQKCTM6.B-WooKSU.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.BtRfVADq.js +0 -1
- package/web/_astro/BoardApp.CBIzcvqi.js +0 -178
- package/web/_astro/channel.kIu33Gui.js +0 -1
package/spur.js
CHANGED
|
@@ -37418,479 +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 misplacedGlobalKeys(parsed) {
|
|
37596
|
-
const misplaced = [];
|
|
37597
|
-
for (const key of PROJECT_SHAPED_GLOBAL_KEYS) {
|
|
37598
|
-
if (key in parsed)
|
|
37599
|
-
misplaced.push(key);
|
|
37600
|
-
}
|
|
37601
|
-
const agent = parsed.agent;
|
|
37602
|
-
if (typeof agent === "object" && agent !== null && "team" in agent) {
|
|
37603
|
-
misplaced.push("agent.team");
|
|
37604
|
-
}
|
|
37605
|
-
return misplaced;
|
|
37606
|
-
}
|
|
37607
|
-
function parseEnvBoolean(value) {
|
|
37608
|
-
if (value === undefined || value === "")
|
|
37609
|
-
return;
|
|
37610
|
-
const normalized = value.toLowerCase();
|
|
37611
|
-
if (["1", "true", "yes", "on"].includes(normalized))
|
|
37612
|
-
return true;
|
|
37613
|
-
if (["0", "false", "no", "off"].includes(normalized))
|
|
37614
|
-
return false;
|
|
37615
|
-
throw new Error(`Invalid boolean environment value: expected true/false, received ${value}`);
|
|
37616
|
-
}
|
|
37617
|
-
function buildConfigFromEnv(env = process.env) {
|
|
37618
|
-
return configSchema2.parse({
|
|
37619
|
-
database: {
|
|
37620
|
-
url: env[SPUR_ENV_VARS.databaseUrl]
|
|
37621
|
-
},
|
|
37622
|
-
server: {
|
|
37623
|
-
port: env[SPUR_ENV_VARS.port],
|
|
37624
|
-
host: env[SPUR_ENV_VARS.host]
|
|
37625
|
-
},
|
|
37626
|
-
telemetry: {
|
|
37627
|
-
enabled: parseEnvBoolean(env.SPUR_TELEMETRY_ENABLED),
|
|
37628
|
-
endpoint: env.SPUR_TELEMETRY_ENDPOINT
|
|
37629
|
-
},
|
|
37630
|
-
logging: {
|
|
37631
|
-
level: env.SPUR_LOG_LEVEL
|
|
37632
|
-
}
|
|
37633
|
-
});
|
|
37634
|
-
}
|
|
37635
|
-
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, configSchema2;
|
|
37636
|
-
var init_src = __esm(() => {
|
|
37637
|
-
init_zod();
|
|
37638
|
-
init_finding_codes();
|
|
37639
|
-
init_projects();
|
|
37640
|
-
SPUR_ENV_VARS = {
|
|
37641
|
-
nodeEnv: "NODE_ENV",
|
|
37642
|
-
port: "PORT",
|
|
37643
|
-
host: "HOST",
|
|
37644
|
-
publicApiUrl: "PUBLIC_API_URL",
|
|
37645
|
-
databaseUrl: "DATABASE_URL"
|
|
37646
|
-
};
|
|
37647
|
-
SPUR_LOG_LEVELS = ["debug", "info", "warn", "error"];
|
|
37648
|
-
folderConfigSchema = exports_external.object({
|
|
37649
|
-
baseCounter: exports_external.number().int().nonnegative().default(0),
|
|
37650
|
-
label: exports_external.string().optional()
|
|
37651
|
-
});
|
|
37652
|
-
tasksConfigSchema = exports_external.object({
|
|
37653
|
-
folders: exports_external.record(exports_external.string(), folderConfigSchema).default({}),
|
|
37654
|
-
active: folderPathWithDefault(DEFAULT_TASKS_DIR),
|
|
37655
|
-
severity: exports_external.record(exports_external.string(), exports_external.enum(["error", "warning", "off"])).optional()
|
|
37656
|
-
}).superRefine((data, ctx) => {
|
|
37657
|
-
if (data.severity) {
|
|
37658
|
-
for (const code of Object.keys(data.severity)) {
|
|
37659
|
-
if (!isFindingCode(code)) {
|
|
37660
|
-
ctx.addIssue({
|
|
37661
|
-
code: exports_external.ZodIssueCode.custom,
|
|
37662
|
-
path: ["severity", code],
|
|
37663
|
-
message: `Unknown finding code "${code}" in severity overrides map`
|
|
37664
|
-
});
|
|
37665
|
-
}
|
|
37666
|
-
}
|
|
37667
|
-
}
|
|
37668
|
-
});
|
|
37669
|
-
featuresConfigSchema = exports_external.object({
|
|
37670
|
-
dir: folderPathWithDefault(DEFAULT_FEATURES_DIR)
|
|
37671
|
-
});
|
|
37672
|
-
EXECUTOR_CAPABILITY_TIERS = ["cheap", "standard", "capable-1", "capable-2", "capable-3"];
|
|
37673
|
-
executorCapabilityTierSchema = exports_external.preprocess((value) => {
|
|
37674
|
-
if (value === undefined || value === null)
|
|
37675
|
-
return;
|
|
37676
|
-
return typeof value === "string" ? normalizeExecutorTier(value) : value;
|
|
37677
|
-
}, exports_external.enum(EXECUTOR_CAPABILITY_TIERS).optional());
|
|
37678
|
-
AGENT_ROLE_NAMES = ["scribe", "coder", "reviewer", "planner"];
|
|
37679
|
-
DEFAULT_AGENT_ROLES = new Map([
|
|
37680
|
-
["scribe", { tier: "cheap", stages: ["changelog"] }],
|
|
37681
|
-
["coder", { tier: "standard", stages: ["implement", "test", "wrap"] }],
|
|
37682
|
-
["reviewer", { tier: "capable-1", stages: ["verify", "review", "dogfood"] }],
|
|
37683
|
-
["planner", { tier: "capable-2", stages: ["plan", "refine", "brainstorm"] }]
|
|
37684
|
-
]);
|
|
37685
|
-
AgentExecutorConfigSchema = exports_external.object({
|
|
37686
|
-
name: exports_external.string().min(1),
|
|
37687
|
-
agent: exports_external.string().min(1),
|
|
37688
|
-
model: exports_external.string().min(1).optional(),
|
|
37689
|
-
tier: executorCapabilityTierSchema.optional()
|
|
37690
|
-
});
|
|
37691
|
-
AgentRoleConfigSchema = exports_external.object({
|
|
37692
|
-
tier: exports_external.enum(EXECUTOR_CAPABILITY_TIERS).optional(),
|
|
37693
|
-
stages: exports_external.array(exports_external.string().min(1)).min(1).optional()
|
|
37694
|
-
});
|
|
37695
|
-
AGENT_ID_REGEX = /^[a-z][a-z0-9_-]{1,63}$/;
|
|
37696
|
-
TeamMemberConfigSchema = exports_external.union([
|
|
37697
|
-
exports_external.string().min(1),
|
|
37698
|
-
exports_external.object({
|
|
37699
|
-
executor: exports_external.string().min(1).optional(),
|
|
37700
|
-
id: exports_external.string().min(1).optional(),
|
|
37701
|
-
role: exports_external.enum(AGENT_ROLE_NAMES, {
|
|
37702
|
-
error: (issue2) => new Error(`Unknown role "${issue2.input}" \u2014 expected one of: ${AGENT_ROLE_NAMES.join(", ")}`)
|
|
37703
|
-
}).optional(),
|
|
37704
|
-
purpose: exports_external.string().optional(),
|
|
37705
|
-
workspace: exports_external.string().min(1).optional(),
|
|
37706
|
-
model: exports_external.string().min(1).optional(),
|
|
37707
|
-
autonomy: exports_external.string().optional(),
|
|
37708
|
-
systemPrompt: exports_external.string().optional(),
|
|
37709
|
-
command: exports_external.array(exports_external.string().min(1)).optional(),
|
|
37710
|
-
autostart: exports_external.boolean().optional()
|
|
37711
|
-
})
|
|
37712
|
-
]);
|
|
37713
|
-
TeamConfigSchema = exports_external.object({
|
|
37714
|
-
name: exports_external.string().min(1),
|
|
37715
|
-
work_dir: exports_external.string().min(1),
|
|
37716
|
-
autostart: exports_external.boolean().optional(),
|
|
37717
|
-
members: exports_external.array(TeamMemberConfigSchema).min(1)
|
|
37718
|
-
});
|
|
37719
|
-
AgentOutputConfigSchema = exports_external.object({
|
|
37720
|
-
"max-bytes": exports_external.number().int().positive().optional(),
|
|
37721
|
-
"max-lines": exports_external.number().int().positive().optional()
|
|
37722
|
-
});
|
|
37723
|
-
AgentConfigSchema = exports_external.object({
|
|
37724
|
-
default: exports_external.string().optional(),
|
|
37725
|
-
executors: exports_external.array(AgentExecutorConfigSchema).optional(),
|
|
37726
|
-
roles: exports_external.record(exports_external.string(), AgentRoleConfigSchema).optional(),
|
|
37727
|
-
team: exports_external.record(exports_external.string(), TeamConfigSchema).optional(),
|
|
37728
|
-
output: AgentOutputConfigSchema.optional(),
|
|
37729
|
-
sessionAffinity: exports_external.boolean().optional()
|
|
37730
|
-
}).superRefine((value, ctx) => {
|
|
37731
|
-
for (const key of Object.keys(value.roles ?? {})) {
|
|
37732
|
-
if (!AGENT_ROLE_NAMES.includes(key)) {
|
|
37733
|
-
ctx.addIssue({
|
|
37734
|
-
code: exports_external.ZodIssueCode.custom,
|
|
37735
|
-
path: ["roles", key],
|
|
37736
|
-
message: `Unknown role "${key}" \u2014 expected one of: ${AGENT_ROLE_NAMES.join(", ")}`
|
|
37737
|
-
});
|
|
37738
|
-
}
|
|
37739
|
-
}
|
|
37740
|
-
const executors = value.executors;
|
|
37741
|
-
const executorNames = new Set;
|
|
37742
|
-
if (executors !== undefined) {
|
|
37743
|
-
const seen = new Set;
|
|
37744
|
-
for (const [index2, executor] of executors.entries()) {
|
|
37745
|
-
if (seen.has(executor.name)) {
|
|
37746
|
-
ctx.addIssue({
|
|
37747
|
-
code: exports_external.ZodIssueCode.custom,
|
|
37748
|
-
message: `Duplicate executor name: ${executor.name}`,
|
|
37749
|
-
path: ["executors", index2, "name"]
|
|
37750
|
-
});
|
|
37751
|
-
}
|
|
37752
|
-
if (executor.name === "inline" || executor.name === "auto") {
|
|
37753
|
-
ctx.addIssue({
|
|
37754
|
-
code: exports_external.ZodIssueCode.custom,
|
|
37755
|
-
message: `Executor name "${executor.name}" is reserved (the --agent selector value '${executor.name}' has fixed semantics); rename executor at index ${index2}.`,
|
|
37756
|
-
path: ["executors", index2, "name"]
|
|
37757
|
-
});
|
|
37758
|
-
}
|
|
37759
|
-
if (AGENT_ROLE_NAMES.includes(executor.name)) {
|
|
37760
|
-
ctx.addIssue({
|
|
37761
|
-
code: exports_external.ZodIssueCode.custom,
|
|
37762
|
-
message: `Executor name "${executor.name}" collides with the role selector namespace ("${executor.name}"); rename executor at index ${index2}.`,
|
|
37763
|
-
path: ["executors", index2, "name"]
|
|
37764
|
-
});
|
|
37765
|
-
}
|
|
37766
|
-
seen.add(executor.name);
|
|
37767
|
-
executorNames.add(executor.name);
|
|
37768
|
-
}
|
|
37769
|
-
}
|
|
37770
|
-
const team = value.team;
|
|
37771
|
-
if (team === undefined)
|
|
37772
|
-
return;
|
|
37773
|
-
const seenComposed = new Set;
|
|
37774
|
-
for (const [teamId, teamConfig] of Object.entries(team)) {
|
|
37775
|
-
const seenLocal = new Set;
|
|
37776
|
-
const members = teamConfig.members.map(normalizeMember);
|
|
37777
|
-
members.forEach((ref, index2) => {
|
|
37778
|
-
if (ref.executor === undefined && ref.role === undefined) {
|
|
37779
|
-
ctx.addIssue({
|
|
37780
|
-
code: exports_external.ZodIssueCode.custom,
|
|
37781
|
-
message: `Team member at index ${index2} in team "${teamId}" declares neither role nor executor \u2014 at least one of role or executor is required.`,
|
|
37782
|
-
path: ["team", teamId, "members", index2]
|
|
37783
|
-
});
|
|
37784
|
-
return;
|
|
37785
|
-
}
|
|
37786
|
-
const localId = memberLocalId(ref, members, index2);
|
|
37787
|
-
if (seenLocal.has(localId)) {
|
|
37788
|
-
ctx.addIssue({
|
|
37789
|
-
code: exports_external.ZodIssueCode.custom,
|
|
37790
|
-
message: `Duplicate team member id: ${localId} in team "${teamId}"`,
|
|
37791
|
-
path: ["team", teamId, "members", index2]
|
|
37792
|
-
});
|
|
37793
|
-
}
|
|
37794
|
-
seenLocal.add(localId);
|
|
37795
|
-
const composedId = `${teamId}-${localId}`;
|
|
37796
|
-
if (!AGENT_ID_REGEX.test(composedId)) {
|
|
37797
|
-
ctx.addIssue({
|
|
37798
|
-
code: exports_external.ZodIssueCode.custom,
|
|
37799
|
-
message: `Invalid composed agent id "${composedId}": team key "${teamId}" + member "${localId}" must match ^[a-z][a-z0-9_-]{1,63}$ (2-64 chars, lowercase).`,
|
|
37800
|
-
path: ["team", teamId, "members", index2]
|
|
37801
|
-
});
|
|
37802
|
-
}
|
|
37803
|
-
if (seenComposed.has(composedId)) {
|
|
37804
|
-
ctx.addIssue({
|
|
37805
|
-
code: exports_external.ZodIssueCode.custom,
|
|
37806
|
-
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).`,
|
|
37807
|
-
path: ["team", teamId, "members", index2]
|
|
37808
|
-
});
|
|
37809
|
-
}
|
|
37810
|
-
seenComposed.add(composedId);
|
|
37811
|
-
if (ref.id !== undefined && AGENT_ROLE_NAMES.includes(ref.id)) {
|
|
37812
|
-
ctx.addIssue({
|
|
37813
|
-
code: exports_external.ZodIssueCode.custom,
|
|
37814
|
-
message: `Team member id "${ref.id}" collides with the role selector namespace ("${ref.id}") in team "${teamId}"; rename the member id.`,
|
|
37815
|
-
path: ["team", teamId, "members", index2]
|
|
37816
|
-
});
|
|
37817
|
-
}
|
|
37818
|
-
if (ref.id !== undefined && executorNames.has(ref.id)) {
|
|
37819
|
-
ctx.addIssue({
|
|
37820
|
-
code: exports_external.ZodIssueCode.custom,
|
|
37821
|
-
message: `Team member id "${ref.id}" collides with executor name "${ref.id}" in team "${teamId}"; the --agent selector namespace must be pairwise disjoint.`,
|
|
37822
|
-
path: ["team", teamId, "members", index2]
|
|
37823
|
-
});
|
|
37824
|
-
}
|
|
37825
|
-
if (executorNames.has(composedId)) {
|
|
37826
|
-
ctx.addIssue({
|
|
37827
|
-
code: exports_external.ZodIssueCode.custom,
|
|
37828
|
-
message: `Composed agent id "${composedId}" collides with executor name "${composedId}"; the --agent selector namespace must be pairwise disjoint.`,
|
|
37829
|
-
path: ["team", teamId, "members", index2]
|
|
37830
|
-
});
|
|
37831
|
-
}
|
|
37832
|
-
if (AGENT_ROLE_NAMES.includes(composedId)) {
|
|
37833
|
-
ctx.addIssue({
|
|
37834
|
-
code: exports_external.ZodIssueCode.custom,
|
|
37835
|
-
message: `Composed agent id "${composedId}" collides with the role selector namespace ("${composedId}"); the --agent selector namespace must be pairwise disjoint.`,
|
|
37836
|
-
path: ["team", teamId, "members", index2]
|
|
37837
|
-
});
|
|
37838
|
-
}
|
|
37839
|
-
});
|
|
37840
|
-
}
|
|
37841
|
-
});
|
|
37842
|
-
RulesConfigSchema = exports_external.object({
|
|
37843
|
-
paths: exports_external.array(exports_external.string()).optional()
|
|
37844
|
-
});
|
|
37845
|
-
WorkflowsConfigSchema = exports_external.object({
|
|
37846
|
-
paths: exports_external.array(exports_external.string()).optional()
|
|
37847
|
-
});
|
|
37848
|
-
WorkflowConfigSchema = exports_external.object({
|
|
37849
|
-
logRetentionDays: exports_external.number().int().positive().default(30)
|
|
37850
|
-
});
|
|
37851
|
-
RedactionConfigSchema = exports_external.object({
|
|
37852
|
-
enabled: exports_external.boolean().optional()
|
|
37853
|
-
});
|
|
37854
|
-
HistoryRefreshConfigSchema = exports_external.object({
|
|
37855
|
-
on_completion: exports_external.boolean().default(false),
|
|
37856
|
-
debounce_ms: exports_external.number().int().min(1000).default(600000)
|
|
37857
|
-
});
|
|
37858
|
-
HistoryConfigSchema = exports_external.object({
|
|
37859
|
-
refresh: HistoryRefreshConfigSchema.optional()
|
|
37860
|
-
});
|
|
37861
|
-
spurConfigSchema = exports_external.object({
|
|
37862
|
-
version: exports_external.string().optional(),
|
|
37863
|
-
name: exports_external.string().optional(),
|
|
37864
|
-
agent: AgentConfigSchema.optional(),
|
|
37865
|
-
rules: RulesConfigSchema.optional(),
|
|
37866
|
-
workflows: WorkflowsConfigSchema.optional(),
|
|
37867
|
-
workflow: WorkflowConfigSchema.optional(),
|
|
37868
|
-
redaction: RedactionConfigSchema.optional(),
|
|
37869
|
-
history: HistoryConfigSchema.optional(),
|
|
37870
|
-
tasks: tasksConfigSchema.optional(),
|
|
37871
|
-
features: featuresConfigSchema.optional()
|
|
37872
|
-
});
|
|
37873
|
-
PROJECT_SHAPED_GLOBAL_KEYS = ["name", "bootstrap", "rules", "redaction", "tasks", "features"];
|
|
37874
|
-
configSchema2 = exports_external.object({
|
|
37875
|
-
database: exports_external.object({
|
|
37876
|
-
url: exports_external.string().default(DEFAULT_DATABASE_URL)
|
|
37877
|
-
}).default({ url: DEFAULT_DATABASE_URL }),
|
|
37878
|
-
server: exports_external.object({
|
|
37879
|
-
port: exports_external.coerce.number().int().positive().default(3000),
|
|
37880
|
-
host: exports_external.string().default("localhost"),
|
|
37881
|
-
openBrowser: exports_external.boolean().default(true),
|
|
37882
|
-
webDistPath: exports_external.string().nullable().default(null)
|
|
37883
|
-
}).default({ port: 3000, host: "localhost", openBrowser: true, webDistPath: null }),
|
|
37884
|
-
telemetry: exports_external.object({
|
|
37885
|
-
enabled: exports_external.boolean().default(false),
|
|
37886
|
-
endpoint: exports_external.string().optional()
|
|
37887
|
-
}).default({ enabled: false }),
|
|
37888
|
-
logging: exports_external.object({
|
|
37889
|
-
level: exports_external.enum(SPUR_LOG_LEVELS).default("info")
|
|
37890
|
-
}).default({ level: "info" })
|
|
37891
|
-
});
|
|
37892
|
-
});
|
|
37893
|
-
|
|
37894
37421
|
// ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.42+815552c3ca302057/node_modules/@gobing-ai/ts-runtime/dist/config.js
|
|
37895
37422
|
function parseYamlObject(text3) {
|
|
37896
37423
|
let parsed;
|
|
@@ -37940,7 +37467,7 @@ function interpolateTree2(value) {
|
|
|
37940
37467
|
function buildConfigFromObject2(raw, options = {}) {
|
|
37941
37468
|
const interpolated = interpolateTree2(raw);
|
|
37942
37469
|
const merged = options.overrides ? deepMerge(interpolated, options.overrides) : interpolated;
|
|
37943
|
-
const result =
|
|
37470
|
+
const result = configSchema2.safeParse(merged);
|
|
37944
37471
|
if (!result.success) {
|
|
37945
37472
|
throw new ConfigLoadError2("Config validation failed", result.error.issues);
|
|
37946
37473
|
}
|
|
@@ -37977,12 +37504,12 @@ function deepFreeze2(obj) {
|
|
|
37977
37504
|
}
|
|
37978
37505
|
return obj;
|
|
37979
37506
|
}
|
|
37980
|
-
var
|
|
37507
|
+
var configSchema2, ENV_INTERPOLATION_RE2, YamlParseError, ConfigLoadError2;
|
|
37981
37508
|
var init_config2 = __esm(() => {
|
|
37982
37509
|
init_dist();
|
|
37983
37510
|
init_dist2();
|
|
37984
37511
|
init_zod();
|
|
37985
|
-
|
|
37512
|
+
configSchema2 = exports_external.object({
|
|
37986
37513
|
app: exports_external.object({
|
|
37987
37514
|
name: exports_external.string().default("app"),
|
|
37988
37515
|
env: exports_external.enum(["development", "staging", "production", "test"]).default("development"),
|
|
@@ -39448,7 +38975,7 @@ __export(exports_dist2, {
|
|
|
39448
38975
|
createLogStream: () => createLogStream2,
|
|
39449
38976
|
createInMemoryProcessRegistry: () => createInMemoryProcessRegistry2,
|
|
39450
38977
|
createCfFileSystem: () => createCfFileSystem2,
|
|
39451
|
-
configSchema: () =>
|
|
38978
|
+
configSchema: () => configSchema2,
|
|
39452
38979
|
cloudflareWorkersFactory: () => cloudflareWorkersFactory2,
|
|
39453
38980
|
buildConfigFromYaml: () => buildConfigFromYaml,
|
|
39454
38981
|
buildConfigFromObject: () => buildConfigFromObject2,
|
|
@@ -39488,6 +39015,481 @@ var init_dist5 = __esm(() => {
|
|
|
39488
39015
|
init_types2();
|
|
39489
39016
|
});
|
|
39490
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
|
+
|
|
39491
39493
|
// ../../packages/config/src/bundled-config.ts
|
|
39492
39494
|
import { existsSync as existsSync3, readdirSync as readdirSync3, statSync as statSync4 } from "fs";
|
|
39493
39495
|
import { dirname as dirname3, join as join2 } from "path";
|
|
@@ -50269,6 +50271,53 @@ function selectorDigest(selector) {
|
|
|
50269
50271
|
var HISTORY_ARTIFACT_SCHEMA_VERSION = 1;
|
|
50270
50272
|
var init_artifact = () => {};
|
|
50271
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
|
+
|
|
50272
50321
|
// ../../packages/domain/src/analytics/models.ts
|
|
50273
50322
|
function resolvePricing(model) {
|
|
50274
50323
|
if (model === undefined || model.length === 0)
|
|
@@ -50885,6 +50934,22 @@ async function bySession(db2, sel, top, opts) {
|
|
|
50885
50934
|
};
|
|
50886
50935
|
});
|
|
50887
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
|
+
}
|
|
50888
50953
|
async function loops(db2, sel, opts) {
|
|
50889
50954
|
const { where, params } = buildMessageWhere(sel);
|
|
50890
50955
|
const wm = applyWatermarkToWhere(where, opts?.watermark);
|
|
@@ -52030,7 +52095,11 @@ function narrowArtifact(artifact, opts, artifactPath) {
|
|
|
52030
52095
|
narrowed = {
|
|
52031
52096
|
...artifact,
|
|
52032
52097
|
byTool: artifact.byTool.slice(0, top),
|
|
52033
|
-
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
|
|
52034
52103
|
};
|
|
52035
52104
|
}
|
|
52036
52105
|
parts.push(`top ${top}`);
|
|
@@ -52425,7 +52494,7 @@ function renderSessionSummary(artifact, derived) {
|
|
|
52425
52494
|
"",
|
|
52426
52495
|
"| Metric | Value |",
|
|
52427
52496
|
"| --- | --- |",
|
|
52428
|
-
`| Sessions | ${artifact.
|
|
52497
|
+
`| Sessions | ${fmtTopOf(artifact.population?.sessions, artifact.population?.appliedTop)} |`,
|
|
52429
52498
|
`| Wall-clock span | ${wall} |`,
|
|
52430
52499
|
`| Messages | ${t.messages.toLocaleString("en-US")} |`,
|
|
52431
52500
|
`| Tool calls | ${t.toolCalls.toLocaleString("en-US")} |`,
|
|
@@ -52650,23 +52719,38 @@ function renderBottlenecks(derived) {
|
|
|
52650
52719
|
}
|
|
52651
52720
|
function renderRawData(artifact) {
|
|
52652
52721
|
const s = artifact.selector;
|
|
52722
|
+
const p = artifact.population;
|
|
52653
52723
|
const lines = [
|
|
52654
52724
|
"## Raw Data",
|
|
52655
52725
|
"",
|
|
52656
52726
|
`- Selector: since=${s.since ?? "-"} until=${s.until ?? "-"} sources=${s.sources ? s.sources.join(",") : "all"} session=${s.sessionId ?? "-"} run=${s.runId ?? "-"} task=${s.taskWbs ?? "-"}`,
|
|
52657
|
-
`- 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`
|
|
52658
52728
|
];
|
|
52659
52729
|
if (artifact.warnings.length > 0) {
|
|
52660
|
-
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
|
+
}
|
|
52661
52734
|
}
|
|
52662
52735
|
if (artifact.coverage.length > 0) {
|
|
52663
|
-
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 |", "| --- | --- | ---: | ---: | ---: | ---: | --- | ---: | ---: |");
|
|
52664
52737
|
for (const c3 of artifact.coverage) {
|
|
52665
|
-
|
|
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} |`);
|
|
52666
52741
|
}
|
|
52667
52742
|
}
|
|
52668
52743
|
return lines;
|
|
52669
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
|
+
}
|
|
52670
52754
|
function fmtWall(ms) {
|
|
52671
52755
|
if (ms < 1000)
|
|
52672
52756
|
return `${Math.round(ms)}ms`;
|
|
@@ -52695,7 +52779,7 @@ function fmtToolDur(ms, bucket) {
|
|
|
52695
52779
|
const allUnmeasured = bucket.calls > 0 && bucket.durationUnmeasured === bucket.calls;
|
|
52696
52780
|
return allUnmeasured ? "n/a" : fmtDur(ms);
|
|
52697
52781
|
}
|
|
52698
|
-
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;
|
|
52699
52783
|
var init_render_forensics = __esm(() => {
|
|
52700
52784
|
init_artifact();
|
|
52701
52785
|
init_render_report();
|
|
@@ -53494,6 +53578,7 @@ var init_run_cost = __esm(() => {
|
|
|
53494
53578
|
// ../../packages/domain/src/analytics/index.ts
|
|
53495
53579
|
var init_analytics = __esm(() => {
|
|
53496
53580
|
init_artifact();
|
|
53581
|
+
init_artifact_digest();
|
|
53497
53582
|
init_costs();
|
|
53498
53583
|
init_forensic_query();
|
|
53499
53584
|
init_models();
|
|
@@ -57413,7 +57498,7 @@ var init_dist7 = __esm(() => {
|
|
|
57413
57498
|
});
|
|
57414
57499
|
|
|
57415
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
|
|
57416
|
-
import { createHash as
|
|
57501
|
+
import { createHash as createHash3 } from "crypto";
|
|
57417
57502
|
function stableJson(value) {
|
|
57418
57503
|
if (Array.isArray(value)) {
|
|
57419
57504
|
return `[${value.map((entry) => entry === undefined ? "null" : stableJson(entry)).join(",")}]`;
|
|
@@ -57425,7 +57510,7 @@ function stableJson(value) {
|
|
|
57425
57510
|
return JSON.stringify(value) ?? "null";
|
|
57426
57511
|
}
|
|
57427
57512
|
function sha256(value) {
|
|
57428
|
-
return
|
|
57513
|
+
return createHash3("sha256").update(stableJson(value)).digest("hex");
|
|
57429
57514
|
}
|
|
57430
57515
|
var init_hash = () => {};
|
|
57431
57516
|
|
|
@@ -64451,9 +64536,9 @@ var init_db2 = __esm(() => {
|
|
|
64451
64536
|
});
|
|
64452
64537
|
|
|
64453
64538
|
// ../../packages/domain/src/envelope/fingerprint.ts
|
|
64454
|
-
import { createHash as
|
|
64539
|
+
import { createHash as createHash4 } from "crypto";
|
|
64455
64540
|
function computeContentHash(content) {
|
|
64456
|
-
return
|
|
64541
|
+
return createHash4("sha256").update(content, "utf-8").digest("hex");
|
|
64457
64542
|
}
|
|
64458
64543
|
var init_fingerprint = () => {};
|
|
64459
64544
|
|
|
@@ -65273,7 +65358,7 @@ function attributeWithoutTelemetry(layers, capturedLayers) {
|
|
|
65273
65358
|
}
|
|
65274
65359
|
|
|
65275
65360
|
// ../../packages/domain/src/envelope/invalidation.ts
|
|
65276
|
-
import { createHash as
|
|
65361
|
+
import { createHash as createHash5 } from "crypto";
|
|
65277
65362
|
function computeInvalidationFingerprint(trigger) {
|
|
65278
65363
|
if (trigger.kind === "tool-output")
|
|
65279
65364
|
return null;
|
|
@@ -65297,7 +65382,7 @@ function computeInvalidationFingerprint(trigger) {
|
|
|
65297
65382
|
default:
|
|
65298
65383
|
return null;
|
|
65299
65384
|
}
|
|
65300
|
-
return
|
|
65385
|
+
return createHash5("sha256").update(raw, "utf-8").digest("hex");
|
|
65301
65386
|
}
|
|
65302
65387
|
function checkLayerStale(layer, freshFingerprint) {
|
|
65303
65388
|
if (freshFingerprint === null) {
|
|
@@ -66605,7 +66690,9 @@ __export(exports_src, {
|
|
|
66605
66690
|
serializeStablePrefix: () => serializeStablePrefix,
|
|
66606
66691
|
serializeLayer: () => serializeLayer,
|
|
66607
66692
|
serializeEnvelope: () => serializeEnvelope,
|
|
66693
|
+
semanticArtifactDigest: () => semanticArtifactDigest,
|
|
66608
66694
|
selectorDigest: () => selectorDigest,
|
|
66695
|
+
selectionPopulation: () => selectionPopulation,
|
|
66609
66696
|
sectionMatrixSchema: () => sectionMatrixSchema,
|
|
66610
66697
|
scaffoldFeatureScenarios: () => scaffoldFeatureScenarios,
|
|
66611
66698
|
runRetention: () => runRetention,
|
|
@@ -66780,6 +66867,7 @@ __export(exports_src, {
|
|
|
66780
66867
|
ROUTING_SUMMARY_DEFAULT_WINDOW_MS: () => ROUTING_SUMMARY_DEFAULT_WINDOW_MS,
|
|
66781
66868
|
REPORT_MODES: () => REPORT_MODES,
|
|
66782
66869
|
REGISTERED_CANONICAL_STAGES: () => REGISTERED_CANONICAL_STAGES,
|
|
66870
|
+
RANKED_ARTIFACT_KEYS: () => RANKED_ARTIFACT_KEYS,
|
|
66783
66871
|
QUEUE_JOBS_SCHEMA_SQL: () => QUEUE_JOBS_SCHEMA_SQL,
|
|
66784
66872
|
PlanningEventDao: () => PlanningEventDao,
|
|
66785
66873
|
PhaseRunDao: () => PhaseRunDao,
|
|
@@ -66820,7 +66908,8 @@ __export(exports_src, {
|
|
|
66820
66908
|
ArtifactDao: () => ArtifactDao,
|
|
66821
66909
|
ActionRunDao: () => ActionRunDao,
|
|
66822
66910
|
AUTHORITY_LANES: () => AUTHORITY_LANES,
|
|
66823
|
-
ARTIFACT_DIRECTIONS: () => ARTIFACT_DIRECTIONS
|
|
66911
|
+
ARTIFACT_DIRECTIONS: () => ARTIFACT_DIRECTIONS,
|
|
66912
|
+
ARTIFACT_ARRAY_CLASSIFICATION: () => ARTIFACT_ARRAY_CLASSIFICATION
|
|
66824
66913
|
});
|
|
66825
66914
|
var init_src2 = __esm(() => {
|
|
66826
66915
|
init_db2();
|
|
@@ -67901,6 +67990,9 @@ class AgentService {
|
|
|
67901
67990
|
async doctor(args, deps) {
|
|
67902
67991
|
const executors = this.ctx.agentConfig?.executors;
|
|
67903
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
|
+
}
|
|
67904
67996
|
if (args.agent === undefined) {
|
|
67905
67997
|
const results2 = await doctorRunner.runAll();
|
|
67906
67998
|
return this.renderDoctor(results2, executors, args.json, args.agent);
|
|
@@ -67909,7 +68001,11 @@ class AgentService {
|
|
|
67909
68001
|
if (roleDef !== undefined) {
|
|
67910
68002
|
const resolved = await this.resolveRole(args.agent, roleDef.tier, doctorRunner);
|
|
67911
68003
|
if (!resolved.ok) {
|
|
67912
|
-
|
|
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
|
+
}
|
|
67913
68009
|
return resolved.exitCode;
|
|
67914
68010
|
}
|
|
67915
68011
|
const results2 = [await doctorRunner.runOne(resolved.executor ?? resolved.agent)];
|
|
@@ -67932,7 +68028,7 @@ class AgentService {
|
|
|
67932
68028
|
const executor = executorByName.get(result.agent) ?? { name: result.agent, agent: result.agent };
|
|
67933
68029
|
return { ...result, capabilityTier: getExecutorTier(executor) };
|
|
67934
68030
|
});
|
|
67935
|
-
this.ctx.output.write(toJson({ agents: rows }));
|
|
68031
|
+
this.ctx.output.write(toJson({ agents: rows, rolesSource: this.ctx.rolesSource ?? "config" }));
|
|
67936
68032
|
} else if (agent !== undefined) {
|
|
67937
68033
|
this.ctx.output.write(renderDoctorDetail(results[0] ?? null));
|
|
67938
68034
|
} else {
|
|
@@ -67946,7 +68042,11 @@ class AgentService {
|
|
|
67946
68042
|
execution: this.defaultExecutionOptions(flags)
|
|
67947
68043
|
});
|
|
67948
68044
|
if (!outcome.ok) {
|
|
67949
|
-
|
|
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
|
+
}
|
|
67950
68050
|
return outcome.exitCode;
|
|
67951
68051
|
}
|
|
67952
68052
|
const result = outcome.result;
|
|
@@ -69864,6 +69964,294 @@ var init_planning_check_base = __esm(() => {
|
|
|
69864
69964
|
init_structural_repair();
|
|
69865
69965
|
});
|
|
69866
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
|
+
|
|
69867
70255
|
// ../../packages/app/src/services/feature-check.ts
|
|
69868
70256
|
var exports_feature_check = {};
|
|
69869
70257
|
__export(exports_feature_check, {
|
|
@@ -69996,6 +70384,8 @@ var init_feature_check = __esm(() => {
|
|
|
69996
70384
|
init_done_transition_guard();
|
|
69997
70385
|
init_planning_check_base();
|
|
69998
70386
|
init_structural_repair();
|
|
70387
|
+
init_task_record();
|
|
70388
|
+
init_verify_verdict();
|
|
69999
70389
|
DEFAULT_FEATURE_MATRIX = {
|
|
70000
70390
|
variants: {
|
|
70001
70391
|
standard: {
|
|
@@ -70255,7 +70645,12 @@ var init_feature_check = __esm(() => {
|
|
|
70255
70645
|
if (tac.trim().length > 0)
|
|
70256
70646
|
linkedTaskAc.push(tac);
|
|
70257
70647
|
linkedTaskSolutions.push(taskDoc.getSection("Solution") ?? "");
|
|
70258
|
-
linkedTaskRecords.push({
|
|
70648
|
+
linkedTaskRecords.push({
|
|
70649
|
+
wbs,
|
|
70650
|
+
status: tStatus,
|
|
70651
|
+
ac: tac,
|
|
70652
|
+
testing: taskDoc.getSection("Testing") ?? ""
|
|
70653
|
+
});
|
|
70259
70654
|
} catch {
|
|
70260
70655
|
findings.push({
|
|
70261
70656
|
layer: "L4",
|
|
@@ -70367,9 +70762,42 @@ var init_feature_check = __esm(() => {
|
|
|
70367
70762
|
}
|
|
70368
70763
|
}
|
|
70369
70764
|
const artifacts2 = new Map;
|
|
70765
|
+
const testingByWbs = new Map(linkedTasks.map((t) => [t.wbs, t.testing]));
|
|
70370
70766
|
for (const wbs of doneWbs) {
|
|
70371
70767
|
const artifact = await this.readVerdictArtifact(runDir, wbs);
|
|
70372
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
|
+
}
|
|
70373
70801
|
const diagnosticParts = [];
|
|
70374
70802
|
if (artifact.diagnostics.artifactError !== undefined) {
|
|
70375
70803
|
if (artifact.diagnostics.artifactError !== "artifact is missing") {
|
|
@@ -70415,7 +70843,7 @@ var init_feature_check = __esm(() => {
|
|
|
70415
70843
|
const artifact = artifacts2.get(task.wbs);
|
|
70416
70844
|
if (artifact === undefined)
|
|
70417
70845
|
continue;
|
|
70418
|
-
if (artifact.verdict !== "PASS")
|
|
70846
|
+
if (artifact.verdict !== "PASS" || artifact.computedVerdict !== "PASS")
|
|
70419
70847
|
continue;
|
|
70420
70848
|
const rows = [...artifact.requirements, ...artifact.acceptanceCriteria];
|
|
70421
70849
|
const matched = rows.find((r) => rowMatchesScenario(r.id, sc));
|
|
@@ -70445,6 +70873,7 @@ var init_feature_check = __esm(() => {
|
|
|
70445
70873
|
return {
|
|
70446
70874
|
path: loaded.path,
|
|
70447
70875
|
verdict: typeof parsed.verdict === "string" ? parsed.verdict : undefined,
|
|
70876
|
+
computedVerdict: computeAggregate(loaded.artifact),
|
|
70448
70877
|
requirements: req.rows,
|
|
70449
70878
|
acceptanceCriteria: ac.rows,
|
|
70450
70879
|
diagnostics: {
|
|
@@ -77049,7 +77478,8 @@ class HistoryService {
|
|
|
77049
77478
|
stepDurationRows,
|
|
77050
77479
|
cacheWasteAggRow,
|
|
77051
77480
|
cacheWasteRows,
|
|
77052
|
-
stepSupportRows
|
|
77481
|
+
stepSupportRows,
|
|
77482
|
+
population
|
|
77053
77483
|
] = await Promise.all([
|
|
77054
77484
|
messageRollup(db2, selector, queryOpts),
|
|
77055
77485
|
toolRollup(db2, selector, queryOpts),
|
|
@@ -77066,7 +77496,8 @@ class HistoryService {
|
|
|
77066
77496
|
topStepsByDuration(db2, selector, top, queryOpts),
|
|
77067
77497
|
cacheWasteAggregate(db2, selector, queryOpts),
|
|
77068
77498
|
topCacheWasteSteps(db2, selector, top, queryOpts),
|
|
77069
|
-
stepSupport(db2, selector, queryOpts)
|
|
77499
|
+
stepSupport(db2, selector, queryOpts),
|
|
77500
|
+
selectionPopulation(db2, selector, queryOpts)
|
|
77070
77501
|
]);
|
|
77071
77502
|
await dropWatermarkExclude();
|
|
77072
77503
|
const totals = foldTotals2(mRows, tRows);
|
|
@@ -77076,6 +77507,11 @@ class HistoryService {
|
|
|
77076
77507
|
const daily = Object.entries(byDay).map(([date6, totals2]) => ({ date: date6, ...totals2 })).sort((a2, b) => a2.date.localeCompare(b.date));
|
|
77077
77508
|
const coverage = buildCoverage(sourceRows, tRows, driftRows, opts.coverageErrors, opts.importCoverage);
|
|
77078
77509
|
const derived = computeDerived(spanRows, toolDurRows, todoRows);
|
|
77510
|
+
const warnings = [
|
|
77511
|
+
...buildWarnings(driftRows, coverage),
|
|
77512
|
+
...derivedWarnings(derived),
|
|
77513
|
+
...opts.extraWarnings ?? []
|
|
77514
|
+
];
|
|
77079
77515
|
const stateByKey = new Map;
|
|
77080
77516
|
for (const w of watermarks)
|
|
77081
77517
|
stateByKey.set(`${w.sessionId}\x00${w.source}`, w.state);
|
|
@@ -77114,11 +77550,7 @@ class HistoryService {
|
|
|
77114
77550
|
sessionState: stateByKey.get(`${r.sessionId}\x00${r.source}`) ?? "complete"
|
|
77115
77551
|
})),
|
|
77116
77552
|
loops: loopRows,
|
|
77117
|
-
warnings
|
|
77118
|
-
...buildWarnings(driftRows, coverage),
|
|
77119
|
-
...derivedWarnings(derived),
|
|
77120
|
-
...opts.extraWarnings ?? []
|
|
77121
|
-
],
|
|
77553
|
+
warnings,
|
|
77122
77554
|
pairings,
|
|
77123
77555
|
ladderSnapshot,
|
|
77124
77556
|
derived,
|
|
@@ -77129,7 +77561,14 @@ class HistoryService {
|
|
|
77129
77561
|
inputTokens: cacheWasteAggRow?.inputTokens ?? 0,
|
|
77130
77562
|
topSteps: cacheWasteRows
|
|
77131
77563
|
},
|
|
77132
|
-
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
|
+
}
|
|
77133
77572
|
};
|
|
77134
77573
|
await refreshHistoryRollups(db2);
|
|
77135
77574
|
if (opts.out !== undefined || opts.cwd !== undefined) {
|
|
@@ -77234,8 +77673,8 @@ class HistoryService {
|
|
|
77234
77673
|
lastImportedAt: null,
|
|
77235
77674
|
parseErrors: result.parseErrors.length,
|
|
77236
77675
|
validationErrors: result.validationErrors.length,
|
|
77237
|
-
parseErrorSamples: result.parseErrors.slice(0,
|
|
77238
|
-
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),
|
|
77239
77678
|
...result.reconciliation ? { reconciliation: result.reconciliation } : {}
|
|
77240
77679
|
};
|
|
77241
77680
|
return { coverageEntry, sourceWarnings };
|
|
@@ -77438,16 +77877,16 @@ function boundCoverage(coverage) {
|
|
|
77438
77877
|
const bounded2 = coverage.map((entry) => {
|
|
77439
77878
|
const pe = entry.parseErrorSamples;
|
|
77440
77879
|
const ve = entry.validationErrorSamples;
|
|
77441
|
-
for (const sample of pe.slice(
|
|
77880
|
+
for (const sample of pe.slice(MAX_ERROR_SAMPLES2)) {
|
|
77442
77881
|
overflow.push({ source: entry.source, kind: "parse", sample });
|
|
77443
77882
|
}
|
|
77444
|
-
for (const sample of ve.slice(
|
|
77883
|
+
for (const sample of ve.slice(MAX_ERROR_SAMPLES2)) {
|
|
77445
77884
|
overflow.push({ source: entry.source, kind: "validation", sample });
|
|
77446
77885
|
}
|
|
77447
77886
|
return {
|
|
77448
77887
|
...entry,
|
|
77449
|
-
parseErrorSamples: pe.slice(0,
|
|
77450
|
-
validationErrorSamples: ve.slice(0,
|
|
77888
|
+
parseErrorSamples: pe.slice(0, MAX_ERROR_SAMPLES2),
|
|
77889
|
+
validationErrorSamples: ve.slice(0, MAX_ERROR_SAMPLES2)
|
|
77451
77890
|
};
|
|
77452
77891
|
});
|
|
77453
77892
|
return { bounded: bounded2, overflow };
|
|
@@ -77544,7 +77983,7 @@ function pruneReports(cwd, retentionDays = REPORT_RETENTION_DAYS, now2 = new Dat
|
|
|
77544
77983
|
}
|
|
77545
77984
|
return pruned.sort((a2, b) => a2.localeCompare(b));
|
|
77546
77985
|
}
|
|
77547
|
-
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;
|
|
77548
77987
|
var init_history_service = __esm(() => {
|
|
77549
77988
|
init_src2();
|
|
77550
77989
|
init_dist8();
|
|
@@ -80194,205 +80633,6 @@ var init_system_event_follow = __esm(() => {
|
|
|
80194
80633
|
init_src2();
|
|
80195
80634
|
});
|
|
80196
80635
|
|
|
80197
|
-
// ../../packages/app/src/services/task-record.ts
|
|
80198
|
-
function escapeTablePipe(s3) {
|
|
80199
|
-
return s3.replace(/\|/g, "\\|");
|
|
80200
|
-
}
|
|
80201
|
-
function parseVerdict(raw, fallbackWbs) {
|
|
80202
|
-
if (raw.trim() === "") {
|
|
80203
|
-
return { wbs: fallbackWbs ?? "", verdict: "UNKNOWN", requirements: [], checks: [] };
|
|
80204
|
-
}
|
|
80205
|
-
try {
|
|
80206
|
-
const parsed = JSON.parse(raw);
|
|
80207
|
-
if (parsed !== null && typeof parsed === "object") {
|
|
80208
|
-
const obj = parsed;
|
|
80209
|
-
const wbs = typeof obj.wbs === "string" ? obj.wbs : fallbackWbs ?? "";
|
|
80210
|
-
const verdict = normalizeVerdict(obj.verdict);
|
|
80211
|
-
const requirements = normalizeRequirements(obj.requirements);
|
|
80212
|
-
const acceptanceCriteria = normalizeAcceptanceCriteria(obj.acceptanceCriteria);
|
|
80213
|
-
const checks4 = normalizeChecks(obj.checks);
|
|
80214
|
-
return { wbs, verdict, requirements, acceptanceCriteria, checks: checks4 };
|
|
80215
|
-
}
|
|
80216
|
-
} catch {}
|
|
80217
|
-
return { wbs: fallbackWbs ?? "", verdict: "UNKNOWN", requirements: [], checks: [] };
|
|
80218
|
-
}
|
|
80219
|
-
async function readVerdict(fs3, path9, fallbackWbs) {
|
|
80220
|
-
let raw;
|
|
80221
|
-
try {
|
|
80222
|
-
raw = await fs3.readFile(path9);
|
|
80223
|
-
} catch {
|
|
80224
|
-
return { wbs: fallbackWbs ?? "", verdict: "UNKNOWN", requirements: [], checks: [] };
|
|
80225
|
-
}
|
|
80226
|
-
return parseVerdict(raw, fallbackWbs);
|
|
80227
|
-
}
|
|
80228
|
-
function normalizeVerdict(raw) {
|
|
80229
|
-
if (typeof raw !== "string")
|
|
80230
|
-
return "UNKNOWN";
|
|
80231
|
-
const upper = raw.toUpperCase();
|
|
80232
|
-
if (upper === "PASS")
|
|
80233
|
-
return "PASS";
|
|
80234
|
-
if (upper === "PARTIAL")
|
|
80235
|
-
return "PARTIAL";
|
|
80236
|
-
if (upper === "FAIL")
|
|
80237
|
-
return "FAIL";
|
|
80238
|
-
return "UNKNOWN";
|
|
80239
|
-
}
|
|
80240
|
-
function normalizeRequirements(raw) {
|
|
80241
|
-
if (!Array.isArray(raw))
|
|
80242
|
-
return [];
|
|
80243
|
-
return raw.filter((r) => r !== null && typeof r === "object").map((r) => ({
|
|
80244
|
-
id: typeof r.id === "string" ? r.id : "",
|
|
80245
|
-
status: typeof r.status === "string" ? r.status : "",
|
|
80246
|
-
evidence: typeof r.evidence === "string" ? r.evidence : ""
|
|
80247
|
-
}));
|
|
80248
|
-
}
|
|
80249
|
-
function normalizeAcceptanceCriteria(raw) {
|
|
80250
|
-
if (!Array.isArray(raw))
|
|
80251
|
-
return [];
|
|
80252
|
-
return raw.filter((ac) => ac !== null && typeof ac === "object").map((ac) => ({
|
|
80253
|
-
id: typeof ac.id === "string" ? ac.id : "",
|
|
80254
|
-
status: typeof ac.status === "string" ? ac.status : "",
|
|
80255
|
-
evidenceType: typeof ac.evidenceType === "string" ? ac.evidenceType : "",
|
|
80256
|
-
evidence: typeof ac.evidence === "string" ? ac.evidence : ""
|
|
80257
|
-
}));
|
|
80258
|
-
}
|
|
80259
|
-
function normalizeChecks(raw) {
|
|
80260
|
-
if (!Array.isArray(raw))
|
|
80261
|
-
return [];
|
|
80262
|
-
return raw.filter((c3) => c3 !== null && typeof c3 === "object").map((c3) => ({
|
|
80263
|
-
name: typeof c3.name === "string" ? c3.name : "",
|
|
80264
|
-
status: typeof c3.status === "string" ? c3.status : "",
|
|
80265
|
-
evidence: typeof c3.evidence === "string" ? c3.evidence : ""
|
|
80266
|
-
}));
|
|
80267
|
-
}
|
|
80268
|
-
function renderTesting(v) {
|
|
80269
|
-
const lines = [];
|
|
80270
|
-
lines.push("**Pipeline verify results**");
|
|
80271
|
-
lines.push("");
|
|
80272
|
-
lines.push(`- Verdict: ${v.verdict} (from verdict artifact)`);
|
|
80273
|
-
lines.push("");
|
|
80274
|
-
if (v.requirements.length === 0) {
|
|
80275
|
-
lines.push("| Requirement | Status | Evidence |");
|
|
80276
|
-
lines.push("|-------------|--------|----------|");
|
|
80277
|
-
lines.push(`| \u2014 | \u2014 | No requirements recorded; verify verdict ${v.verdict} |`);
|
|
80278
|
-
} else {
|
|
80279
|
-
lines.push("| Requirement | Status | Evidence |");
|
|
80280
|
-
lines.push("|-------------|--------|----------|");
|
|
80281
|
-
for (const req of v.requirements) {
|
|
80282
|
-
const evidence = escapeTablePipe(req.evidence.replace(/\n/g, " "));
|
|
80283
|
-
lines.push(`| ${req.id} | ${req.status} | ${evidence} |`);
|
|
80284
|
-
}
|
|
80285
|
-
}
|
|
80286
|
-
if ((v.acceptanceCriteria ?? []).length > 0) {
|
|
80287
|
-
lines.push("");
|
|
80288
|
-
lines.push("| Acceptance Criteria | Status | Evidence Type | Evidence |");
|
|
80289
|
-
lines.push("|---------------------|--------|---------------|----------|");
|
|
80290
|
-
for (const ac of v.acceptanceCriteria ?? []) {
|
|
80291
|
-
const evidence = escapeTablePipe(ac.evidence.replace(/\n/g, " "));
|
|
80292
|
-
lines.push(`| ${ac.id} | ${ac.status} | ${ac.evidenceType} | ${evidence} |`);
|
|
80293
|
-
}
|
|
80294
|
-
}
|
|
80295
|
-
lines.push("- Coverage: N/A (verdict-based; verify pipeline does not measure code coverage)");
|
|
80296
|
-
return lines.join(`
|
|
80297
|
-
`);
|
|
80298
|
-
}
|
|
80299
|
-
function renderReview(v) {
|
|
80300
|
-
const lines = [];
|
|
80301
|
-
lines.push(`**SECU findings** (pipeline verify step \u2014 verdict: ${v.verdict})`);
|
|
80302
|
-
lines.push("");
|
|
80303
|
-
lines.push("| Priority | Dimension | Location | Finding |");
|
|
80304
|
-
lines.push("|----------|-----------|----------|----------|");
|
|
80305
|
-
if (v.checks.length === 0) {
|
|
80306
|
-
lines.push(`| P4 | \u2014 | \u2014 | No P1\u2013P3 findings; verify verdict ${v.verdict} |`);
|
|
80307
|
-
} else {
|
|
80308
|
-
for (const check2 of v.checks) {
|
|
80309
|
-
const finding = escapeTablePipe(check2.evidence.replace(/\n/g, " "));
|
|
80310
|
-
const priority = /^P[1-4]$/.test(check2.status) ? check2.status : check2.status === "fail" ? "P1" : "P4";
|
|
80311
|
-
lines.push(`| ${priority} | ${check2.name} | \u2014 | ${finding} |`);
|
|
80312
|
-
}
|
|
80313
|
-
}
|
|
80314
|
-
lines.push("");
|
|
80315
|
-
return lines.join(`
|
|
80316
|
-
`);
|
|
80317
|
-
}
|
|
80318
|
-
function renderSolutionFromDiff(diffText) {
|
|
80319
|
-
const lines = [];
|
|
80320
|
-
lines.push("Change-map (auto-generated \u2014 implement step did not record a Solution).");
|
|
80321
|
-
lines.push("Each entry cites the first changed line per file (`file:line`).");
|
|
80322
|
-
lines.push("");
|
|
80323
|
-
lines.push("| Change (`file:line`) |");
|
|
80324
|
-
lines.push("|----------------------|");
|
|
80325
|
-
const citations = extractFileLineCitations(diffText);
|
|
80326
|
-
if (citations.length === 0) {
|
|
80327
|
-
const files = extractChangedFiles(diffText);
|
|
80328
|
-
if (files.length === 0) {
|
|
80329
|
-
lines.push("| `(no changes detected)` |");
|
|
80330
|
-
} else {
|
|
80331
|
-
for (const f of files) {
|
|
80332
|
-
lines.push(`| \`${f}:1\` |`);
|
|
80333
|
-
}
|
|
80334
|
-
}
|
|
80335
|
-
} else {
|
|
80336
|
-
for (const citation of citations) {
|
|
80337
|
-
lines.push(`| \`${citation}\` |`);
|
|
80338
|
-
}
|
|
80339
|
-
}
|
|
80340
|
-
lines.push("");
|
|
80341
|
-
return lines.join(`
|
|
80342
|
-
`);
|
|
80343
|
-
}
|
|
80344
|
-
function extractFileLineCitations(diffText) {
|
|
80345
|
-
const citations = new Set;
|
|
80346
|
-
let currentFile = null;
|
|
80347
|
-
for (const line of diffText.split(`
|
|
80348
|
-
`)) {
|
|
80349
|
-
const fileMatch = /^\+\+\+ b\/(.+)$/.exec(line);
|
|
80350
|
-
if (fileMatch) {
|
|
80351
|
-
currentFile = fileMatch[1] ?? null;
|
|
80352
|
-
continue;
|
|
80353
|
-
}
|
|
80354
|
-
if (currentFile === null)
|
|
80355
|
-
continue;
|
|
80356
|
-
const hunkMatch = /^@@ -\d+(?:,\d+)? \+(\d+)(?:,\d+)? @@/.exec(line);
|
|
80357
|
-
if (hunkMatch) {
|
|
80358
|
-
const newLine = hunkMatch[1];
|
|
80359
|
-
if (newLine !== undefined) {
|
|
80360
|
-
citations.add(`${currentFile}:${newLine}`);
|
|
80361
|
-
}
|
|
80362
|
-
}
|
|
80363
|
-
}
|
|
80364
|
-
return [...citations].sort();
|
|
80365
|
-
}
|
|
80366
|
-
function extractChangedFiles(diffText) {
|
|
80367
|
-
const files = new Set;
|
|
80368
|
-
for (const line of diffText.split(`
|
|
80369
|
-
`)) {
|
|
80370
|
-
const match = /^\+\+\+ b\/(.+)$/.exec(line);
|
|
80371
|
-
if (match) {
|
|
80372
|
-
const filePath = match[1];
|
|
80373
|
-
if (filePath !== undefined)
|
|
80374
|
-
files.add(filePath);
|
|
80375
|
-
}
|
|
80376
|
-
}
|
|
80377
|
-
return [...files].sort();
|
|
80378
|
-
}
|
|
80379
|
-
function gitDiffU0(cwd) {
|
|
80380
|
-
try {
|
|
80381
|
-
const result = new BunSyncProcessExecutor2().runSync({
|
|
80382
|
-
command: "git",
|
|
80383
|
-
args: ["diff", "-U0", "HEAD", "--", "*.ts", "*.tsx", "*.js"],
|
|
80384
|
-
...cwd !== undefined ? { cwd } : {},
|
|
80385
|
-
rejectOnError: false
|
|
80386
|
-
});
|
|
80387
|
-
return result.exitCode === 0 ? result.stdout : "";
|
|
80388
|
-
} catch {
|
|
80389
|
-
return "";
|
|
80390
|
-
}
|
|
80391
|
-
}
|
|
80392
|
-
var init_task_record = __esm(() => {
|
|
80393
|
-
init_dist5();
|
|
80394
|
-
});
|
|
80395
|
-
|
|
80396
80636
|
// ../../packages/app/src/services/task-scaffold.ts
|
|
80397
80637
|
import { dirname as dirname13 } from "path";
|
|
80398
80638
|
|
|
@@ -81902,7 +82142,7 @@ class TeamService {
|
|
|
81902
82142
|
}
|
|
81903
82143
|
async listTeams() {
|
|
81904
82144
|
const specs = await loadAgentSpecs(this.configDir);
|
|
81905
|
-
const config4 =
|
|
82145
|
+
const config4 = this.ctx.spurConfig ?? null;
|
|
81906
82146
|
const teams = new Map;
|
|
81907
82147
|
const configTeamIds = new Set;
|
|
81908
82148
|
if (config4?.agent?.team) {
|
|
@@ -81961,7 +82201,7 @@ class TeamService {
|
|
|
81961
82201
|
return Array.from(teams.values());
|
|
81962
82202
|
}
|
|
81963
82203
|
async materializeTeam(teamId, opts) {
|
|
81964
|
-
const config4 =
|
|
82204
|
+
const config4 = this.ctx.spurConfig ?? null;
|
|
81965
82205
|
const teamConfig = config4?.agent?.team?.[teamId];
|
|
81966
82206
|
if (!teamConfig) {
|
|
81967
82207
|
throw new Error(`Team "${teamId}" not found in agent.team config`);
|
|
@@ -82086,13 +82326,6 @@ class TeamService {
|
|
|
82086
82326
|
const workDir = this.resolveWorkspaceDir(first);
|
|
82087
82327
|
return { workDir, isCurrentProject: this.isCurrentProject(workDir) };
|
|
82088
82328
|
}
|
|
82089
|
-
async loadTeamConfig() {
|
|
82090
|
-
try {
|
|
82091
|
-
return await loadSpurConfig(this.ctx.cwd);
|
|
82092
|
-
} catch {
|
|
82093
|
-
return null;
|
|
82094
|
-
}
|
|
82095
|
-
}
|
|
82096
82329
|
async inboxDao() {
|
|
82097
82330
|
const db2 = await this.ctx.getDb();
|
|
82098
82331
|
return new InboxMessageDao(db2);
|
|
@@ -82198,7 +82431,6 @@ function resolveAutostartSet(config4, envAutostart) {
|
|
|
82198
82431
|
}
|
|
82199
82432
|
var init_team_service = __esm(() => {
|
|
82200
82433
|
init_src();
|
|
82201
|
-
init_loader();
|
|
82202
82434
|
init_src2();
|
|
82203
82435
|
init_dist9();
|
|
82204
82436
|
init_planning_folders();
|
|
@@ -83324,21 +83556,26 @@ var init_agent_run = __esm(() => {
|
|
|
83324
83556
|
init_steering();
|
|
83325
83557
|
});
|
|
83326
83558
|
|
|
83327
|
-
// ../../packages/app/src/workflow/
|
|
83328
|
-
|
|
83329
|
-
|
|
83330
|
-
|
|
83331
|
-
return {
|
|
83332
|
-
error: `command.gate "executable" must not contain shell metacharacters (got ${executable})`
|
|
83333
|
-
};
|
|
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})` };
|
|
83334
83563
|
}
|
|
83335
|
-
const tokens =
|
|
83564
|
+
const tokens = value.trim().split(/\s+/).filter((t) => t.length > 0);
|
|
83336
83565
|
const command = tokens[0];
|
|
83337
83566
|
if (command === undefined) {
|
|
83338
|
-
|
|
83567
|
+
const key2 = label.slice(label.indexOf('"'));
|
|
83568
|
+
return { error: `Action option ${key2} must be a non-empty string` };
|
|
83339
83569
|
}
|
|
83340
83570
|
return { command, leadingArgs: tokens.slice(1) };
|
|
83341
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";
|
|
83342
83579
|
function sleep3(ms) {
|
|
83343
83580
|
return new Promise((resolve10) => setTimeout(resolve10, ms));
|
|
83344
83581
|
}
|
|
@@ -83399,7 +83636,7 @@ class CommandGateActionRunner {
|
|
|
83399
83636
|
error: `resultFile must resolve beneath .spur/run/ (got ${resultFileRaw})`
|
|
83400
83637
|
};
|
|
83401
83638
|
}
|
|
83402
|
-
const split =
|
|
83639
|
+
const split = splitLaunchCommand(executable, 'command.gate "executable"');
|
|
83403
83640
|
if ("error" in split) {
|
|
83404
83641
|
return { ok: false, error: split.error };
|
|
83405
83642
|
}
|
|
@@ -83479,25 +83716,14 @@ ${lastStderr}`;
|
|
|
83479
83716
|
};
|
|
83480
83717
|
}
|
|
83481
83718
|
}
|
|
83482
|
-
var KIND2 = "command.gate"
|
|
83719
|
+
var KIND2 = "command.gate";
|
|
83483
83720
|
var init_command_gate = __esm(() => {
|
|
83484
83721
|
init_dist5();
|
|
83485
|
-
|
|
83722
|
+
init_split_launch_command();
|
|
83486
83723
|
});
|
|
83487
83724
|
|
|
83488
83725
|
// ../../packages/app/src/workflow/actions/doctor-probe.ts
|
|
83489
83726
|
import { normalize as normalize2, resolve as resolve10, sep as sep2 } from "path";
|
|
83490
|
-
function splitSpurBin(spurBin) {
|
|
83491
|
-
if (SHELL_METACHARACTERS2.test(spurBin)) {
|
|
83492
|
-
return { error: `doctor.probe "spurBin" must not contain shell metacharacters (got ${spurBin})` };
|
|
83493
|
-
}
|
|
83494
|
-
const tokens = spurBin.trim().split(/\s+/).filter((t) => t.length > 0);
|
|
83495
|
-
const command = tokens[0];
|
|
83496
|
-
if (command === undefined) {
|
|
83497
|
-
return { error: 'Action option "spurBin" must be a non-empty string' };
|
|
83498
|
-
}
|
|
83499
|
-
return { command, leadingArgs: tokens.slice(1) };
|
|
83500
|
-
}
|
|
83501
83727
|
function stringOption2(options, key2, fallback) {
|
|
83502
83728
|
const value = options[key2];
|
|
83503
83729
|
if (typeof value === "string")
|
|
@@ -83557,7 +83783,7 @@ class DoctorProbeActionRunner {
|
|
|
83557
83783
|
error: `resultFile must resolve beneath .spur/run/ (got ${resultFileRaw})`
|
|
83558
83784
|
};
|
|
83559
83785
|
}
|
|
83560
|
-
const split =
|
|
83786
|
+
const split = splitLaunchCommand(spurBin, 'doctor.probe "spurBin"');
|
|
83561
83787
|
if ("error" in split) {
|
|
83562
83788
|
return { ok: false, error: split.error };
|
|
83563
83789
|
}
|
|
@@ -83633,11 +83859,11 @@ ${res.stderr}`.trim();
|
|
|
83633
83859
|
return { ok: true, data: { status, resultFile: normalized, output: lines } };
|
|
83634
83860
|
}
|
|
83635
83861
|
}
|
|
83636
|
-
var KIND3 = "doctor.probe",
|
|
83862
|
+
var KIND3 = "doctor.probe", RELAY_FAMILY, ENV_MISS_PATTERN, AUTH_FAIL_PATTERN;
|
|
83637
83863
|
var init_doctor_probe = __esm(() => {
|
|
83638
83864
|
init_dist5();
|
|
83639
83865
|
init_observability();
|
|
83640
|
-
|
|
83866
|
+
init_split_launch_command();
|
|
83641
83867
|
RELAY_FAMILY = /^(omp|pi)(-.*)?$/;
|
|
83642
83868
|
ENV_MISS_PATTERN = /API key not found for provider|no probe registered/i;
|
|
83643
83869
|
AUTH_FAIL_PATTERN = /invalid (API )?key|unauthori[sz]ed|forbidden|authentication failed|credential(s)? rejected/i;
|
|
@@ -85006,7 +85232,7 @@ class WorkflowAppService {
|
|
|
85006
85232
|
const isDry = opts.dryRun === true;
|
|
85007
85233
|
const warnings = [];
|
|
85008
85234
|
const runVars = {
|
|
85009
|
-
...
|
|
85235
|
+
...resolveDefaultAgentVar(this.ctx.spurConfig ?? null, opts.vars, (m) => warnings.push(m)),
|
|
85010
85236
|
...opts.vars ?? {},
|
|
85011
85237
|
__runId: runId
|
|
85012
85238
|
};
|
|
@@ -85329,14 +85555,12 @@ class WorkflowAppService {
|
|
|
85329
85555
|
let agentSlice = {
|
|
85330
85556
|
...this.ctx.secretValues !== undefined ? { secretValues: this.ctx.secretValues } : {}
|
|
85331
85557
|
};
|
|
85332
|
-
|
|
85333
|
-
|
|
85334
|
-
agentSlice
|
|
85335
|
-
|
|
85336
|
-
|
|
85337
|
-
|
|
85338
|
-
};
|
|
85339
|
-
} 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
|
+
};
|
|
85340
85564
|
try {
|
|
85341
85565
|
const fs3 = createNodeFileSystem3(this.ctx.cwd);
|
|
85342
85566
|
const { foldersConfig, featuresDir } = await resolvePlanningFolders(fs3);
|
|
@@ -85581,22 +85805,16 @@ function resolveWorkflowFile(cwd, file2) {
|
|
|
85581
85805
|
}
|
|
85582
85806
|
return { path: null, probed: [projectPath, null] };
|
|
85583
85807
|
}
|
|
85584
|
-
|
|
85808
|
+
function resolveDefaultAgentVar(config4, callerVars, warn) {
|
|
85585
85809
|
const result = {};
|
|
85586
85810
|
if (callerVars?.implementAgent === undefined && callerVars?.agent !== undefined) {
|
|
85587
85811
|
result.implementAgent = callerVars.agent;
|
|
85588
85812
|
}
|
|
85589
|
-
|
|
85590
|
-
try {
|
|
85591
|
-
config4 = await loadSpurConfig(cwd);
|
|
85592
|
-
} catch {
|
|
85593
|
-
return result;
|
|
85594
|
-
}
|
|
85595
|
-
const configured = config4.agent?.default;
|
|
85813
|
+
const configured = config4?.agent?.default;
|
|
85596
85814
|
if (typeof configured !== "string" || configured.length === 0) {
|
|
85597
85815
|
return result;
|
|
85598
85816
|
}
|
|
85599
|
-
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;
|
|
85600
85818
|
if (!valid) {
|
|
85601
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`);
|
|
85602
85820
|
return result;
|
|
@@ -85608,25 +85826,17 @@ async function resolveDefaultAgentVar(cwd, callerVars, warn) {
|
|
|
85608
85826
|
}
|
|
85609
85827
|
return result;
|
|
85610
85828
|
}
|
|
85611
|
-
|
|
85612
|
-
|
|
85613
|
-
return (await loadSpurConfig(cwd)).workflow?.logRetentionDays ?? 30;
|
|
85614
|
-
} catch {
|
|
85615
|
-
return 30;
|
|
85616
|
-
}
|
|
85829
|
+
function resolveWorkflowLogRetentionDays(config4) {
|
|
85830
|
+
return config4?.workflow?.logRetentionDays ?? 30;
|
|
85617
85831
|
}
|
|
85618
|
-
|
|
85619
|
-
|
|
85620
|
-
|
|
85621
|
-
if (output2 === undefined)
|
|
85622
|
-
return {};
|
|
85623
|
-
return {
|
|
85624
|
-
...output2["max-bytes"] !== undefined ? { maxBytes: output2["max-bytes"] } : {},
|
|
85625
|
-
...output2["max-lines"] !== undefined ? { maxLines: output2["max-lines"] } : {}
|
|
85626
|
-
};
|
|
85627
|
-
} catch {
|
|
85832
|
+
function resolveOutputLogConfig(config4) {
|
|
85833
|
+
const output2 = config4?.agent?.output;
|
|
85834
|
+
if (output2 === undefined)
|
|
85628
85835
|
return {};
|
|
85629
|
-
|
|
85836
|
+
return {
|
|
85837
|
+
...output2["max-bytes"] !== undefined ? { maxBytes: output2["max-bytes"] } : {},
|
|
85838
|
+
...output2["max-lines"] !== undefined ? { maxLines: output2["max-lines"] } : {}
|
|
85839
|
+
};
|
|
85630
85840
|
}
|
|
85631
85841
|
async function outputArtifactForRun(cwd, runId) {
|
|
85632
85842
|
const relative5 = join22(".spur", "run", `${runId}.log`);
|
|
@@ -85842,6 +86052,9 @@ var init_workflow_service = __esm(() => {
|
|
|
85842
86052
|
|
|
85843
86053
|
// ../../packages/app/src/workflow/idea-handoff.ts
|
|
85844
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
|
+
}
|
|
85845
86058
|
async function finalizeIdeaHandoff(options) {
|
|
85846
86059
|
const root = options.projectRoot ?? process.cwd();
|
|
85847
86060
|
const fs3 = options.fileSystem ?? createNodeFileSystem3();
|
|
@@ -85853,6 +86066,18 @@ async function finalizeIdeaHandoff(options) {
|
|
|
85853
86066
|
const resultPath = resolve14(runDir, `${runId}-idea-batch-create-result.json`);
|
|
85854
86067
|
const orderPath = resolve14(runDir, `${runId}-idea-task-order.json`);
|
|
85855
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;
|
|
85856
86081
|
if (!await fs3.exists(batchPath) || !await fs3.exists(resultPath) || !await fs3.exists(orderPath)) {
|
|
85857
86082
|
return {
|
|
85858
86083
|
ok: false,
|
|
@@ -85922,8 +86147,8 @@ async function finalizeIdeaHandoff(options) {
|
|
|
85922
86147
|
}
|
|
85923
86148
|
if (deps.length > 0) {
|
|
85924
86149
|
const depRes = await executor.run({
|
|
85925
|
-
command:
|
|
85926
|
-
args: ["task", "deps", ownWbs, "set", ...deps, "--json"],
|
|
86150
|
+
command: spurCommand,
|
|
86151
|
+
args: [...spurArgsPrefix, "task", "deps", ownWbs, "set", ...deps, "--json"],
|
|
85927
86152
|
cwd: root,
|
|
85928
86153
|
forceBuffered: true,
|
|
85929
86154
|
rejectOnError: false
|
|
@@ -85934,27 +86159,45 @@ async function finalizeIdeaHandoff(options) {
|
|
|
85934
86159
|
wbsList: result.wbs,
|
|
85935
86160
|
nextCommand: "",
|
|
85936
86161
|
reportPath,
|
|
85937
|
-
error: `Failed to set dependencies for task ${ownWbs}: ${depRes
|
|
86162
|
+
error: `Failed to set dependencies for task ${ownWbs}: ${processEvidence(depRes)}`
|
|
85938
86163
|
};
|
|
85939
86164
|
}
|
|
85940
86165
|
}
|
|
85941
86166
|
}
|
|
85942
|
-
await executor.run({
|
|
85943
|
-
command:
|
|
85944
|
-
args: ["feature", "refresh", "--feature", featureId2, "--json"],
|
|
86167
|
+
const refreshRes = await executor.run({
|
|
86168
|
+
command: spurCommand,
|
|
86169
|
+
args: [...spurArgsPrefix, "feature", "refresh", "--feature", featureId2, "--json"],
|
|
85945
86170
|
cwd: root,
|
|
85946
86171
|
forceBuffered: true,
|
|
85947
86172
|
rejectOnError: false
|
|
85948
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
|
+
}
|
|
85949
86183
|
const checkResults = [];
|
|
85950
86184
|
for (const wbs of result.wbs) {
|
|
85951
86185
|
const checkRes = await executor.run({
|
|
85952
|
-
command:
|
|
85953
|
-
args: ["task", "check", wbs, "--json"],
|
|
86186
|
+
command: spurCommand,
|
|
86187
|
+
args: [...spurArgsPrefix, "task", "check", wbs, "--json"],
|
|
85954
86188
|
cwd: root,
|
|
85955
86189
|
forceBuffered: true,
|
|
85956
86190
|
rejectOnError: false
|
|
85957
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
|
+
}
|
|
85958
86201
|
checkResults.push({ wbs, pass: checkRes.exitCode === 0 });
|
|
85959
86202
|
}
|
|
85960
86203
|
const anyFailed = checkResults.some((c3) => !c3.pass);
|
|
@@ -86000,6 +86243,7 @@ async function finalizeIdeaHandoff(options) {
|
|
|
86000
86243
|
}
|
|
86001
86244
|
var init_idea_handoff = __esm(() => {
|
|
86002
86245
|
init_dist5();
|
|
86246
|
+
init_split_launch_command();
|
|
86003
86247
|
});
|
|
86004
86248
|
|
|
86005
86249
|
// ../../packages/app/src/workflow/idea-handoff-cli.ts
|
|
@@ -86909,7 +87153,6 @@ var {
|
|
|
86909
87153
|
} = import__.default;
|
|
86910
87154
|
|
|
86911
87155
|
// src/index.ts
|
|
86912
|
-
init_src();
|
|
86913
87156
|
init_loader();
|
|
86914
87157
|
|
|
86915
87158
|
// ../../node_modules/.bun/@gobing-ai+ts-infra@0.4.42+4012563f10a1cd34/node_modules/@gobing-ai/ts-infra/dist/application-node.js
|
|
@@ -95693,7 +95936,7 @@ import { createRequire } from "module";
|
|
|
95693
95936
|
var CLI_CONFIG = {
|
|
95694
95937
|
binaryName: "spur",
|
|
95695
95938
|
binaryLabel: "spur",
|
|
95696
|
-
binaryVersion: "0.3.
|
|
95939
|
+
binaryVersion: "0.3.62",
|
|
95697
95940
|
configDir: ".spur",
|
|
95698
95941
|
configFile: ".spur/config.yaml",
|
|
95699
95942
|
databaseFile: ".spur/spur.db"
|
|
@@ -96350,7 +96593,11 @@ function registerMessageCommand(program2, context4) {
|
|
|
96350
96593
|
async function runMessageSend(svc, context4, body, options) {
|
|
96351
96594
|
const trimmed = body.trim();
|
|
96352
96595
|
if (trimmed === "") {
|
|
96353
|
-
|
|
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
|
+
}
|
|
96354
96601
|
return 2;
|
|
96355
96602
|
}
|
|
96356
96603
|
const from = options.from || DEFAULT_FROM;
|
|
@@ -106547,7 +106794,8 @@ function createServerContext(appRt, options) {
|
|
|
106547
106794
|
fs: fs3,
|
|
106548
106795
|
getDb: this.getDb.bind(this),
|
|
106549
106796
|
eventBus: bridgeEventBus(eventsBus),
|
|
106550
|
-
events: bridgeEventBus(eventsBus)
|
|
106797
|
+
events: bridgeEventBus(eventsBus),
|
|
106798
|
+
...options.spurConfig !== undefined ? { spurConfig: options.spurConfig } : {}
|
|
106551
106799
|
});
|
|
106552
106800
|
}
|
|
106553
106801
|
return teamSvc;
|
|
@@ -106614,6 +106862,7 @@ function createServerContext(appRt, options) {
|
|
|
106614
106862
|
agentService: this.agentService.bind(this),
|
|
106615
106863
|
ruleService: this.ruleService.bind(this),
|
|
106616
106864
|
hitlResponder: this.hitlResponder.bind(this),
|
|
106865
|
+
...options.spurConfig !== undefined ? { spurConfig: options.spurConfig } : {},
|
|
106617
106866
|
observabilityBus: () => bridgeEventBus(eventsBus),
|
|
106618
106867
|
events: () => bridgeEventBus(eventsBus)
|
|
106619
106868
|
});
|
|
@@ -106887,6 +107136,7 @@ async function startServer(options, deps = defaultDeps) {
|
|
|
106887
107136
|
if (!webDistPath) {
|
|
106888
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).");
|
|
106889
107138
|
}
|
|
107139
|
+
const spurConfig = await loadSpurConfig(process.cwd()).catch(() => null);
|
|
106890
107140
|
const ctx = deps.createServerContext(appRt, {
|
|
106891
107141
|
cwd: process.cwd(),
|
|
106892
107142
|
fs: fs3,
|
|
@@ -106897,10 +107147,10 @@ async function startServer(options, deps = defaultDeps) {
|
|
|
106897
107147
|
jobQueueEnabled: bootConfig.jobqueue.enabled,
|
|
106898
107148
|
scheduler: scheduler3,
|
|
106899
107149
|
teamAutostart: bootConfig.teamAutostart,
|
|
106900
|
-
bootConfig
|
|
107150
|
+
bootConfig,
|
|
107151
|
+
...spurConfig !== undefined ? { spurConfig } : {}
|
|
106901
107152
|
});
|
|
106902
107153
|
let jobWorker;
|
|
106903
|
-
const spurConfig = await loadSpurConfig(process.cwd()).catch(() => null);
|
|
106904
107154
|
const autostartIds = resolveAutostartSet(spurConfig, env.SPUR_TEAM_AUTOSTART);
|
|
106905
107155
|
if (autostartIds.length > 0) {
|
|
106906
107156
|
try {
|
|
@@ -107991,17 +108241,11 @@ var EMBEDDED_SPUR_SCHEMAS = new Map([
|
|
|
107991
108241
|
]);
|
|
107992
108242
|
|
|
107993
108243
|
// src/history-refresh.ts
|
|
107994
|
-
init_loader();
|
|
107995
108244
|
init_dist6();
|
|
107996
108245
|
await init_src3();
|
|
107997
108246
|
async function maybeTriggerHistoryRefresh(context4, trigger, triggerId) {
|
|
107998
108247
|
try {
|
|
107999
|
-
|
|
108000
|
-
try {
|
|
108001
|
-
config4 = await loadSpurConfig(context4.cwd, { embeddedSchemas: EMBEDDED_SPUR_SCHEMAS });
|
|
108002
|
-
} catch {
|
|
108003
|
-
config4 = null;
|
|
108004
|
-
}
|
|
108248
|
+
const config4 = context4.spurConfig ?? null;
|
|
108005
108249
|
const db2 = await context4.getDb();
|
|
108006
108250
|
const result = await enqueueHistoryRefresh(db2, { config: config4, trigger, triggerId });
|
|
108007
108251
|
if (result.status === "disabled")
|
|
@@ -109456,13 +109700,20 @@ function submitSteeringLine(controller, output2, line) {
|
|
|
109456
109700
|
if (ack === undefined)
|
|
109457
109701
|
output2.error(`[steer] ignored command: ${line}`);
|
|
109458
109702
|
}
|
|
109459
|
-
|
|
109460
|
-
|
|
109461
|
-
|
|
109462
|
-
|
|
109463
|
-
|
|
109464
|
-
|
|
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
|
+
}
|
|
109465
109715
|
}
|
|
109716
|
+
return expanded;
|
|
109466
109717
|
}
|
|
109467
109718
|
function registerWorkflowCommand(program2, context4) {
|
|
109468
109719
|
const makeSvc = (json3, bus) => new WorkflowAppService({
|
|
@@ -109625,7 +109876,7 @@ Monitor with: spur workflow trace ${runId2} --follow`);
|
|
|
109625
109876
|
dir: join34(context4.cwd, ".spur", "run"),
|
|
109626
109877
|
runId,
|
|
109627
109878
|
...planPreview !== undefined ? { planPreview } : {},
|
|
109628
|
-
...
|
|
109879
|
+
...resolveOutputLogConfig(context4.spurConfig ?? null)
|
|
109629
109880
|
});
|
|
109630
109881
|
if (humanProgress) {
|
|
109631
109882
|
context4.output.write(`Run: ${runId}`);
|
|
@@ -109787,7 +110038,7 @@ Monitor with: spur workflow trace ${runId2} --follow`);
|
|
|
109787
110038
|
}
|
|
109788
110039
|
const svc = makeSvc(options.json);
|
|
109789
110040
|
const result = logsOnly ? undefined : await svc.clean(minutes, dryRun);
|
|
109790
|
-
const retentionDays =
|
|
110041
|
+
const retentionDays = resolveWorkflowLogRetentionDays(context4.spurConfig ?? null);
|
|
109791
110042
|
const logResult2 = await svc.cleanRunLogs(retentionDays, dryRun);
|
|
109792
110043
|
if (options.json) {
|
|
109793
110044
|
context4.output.write(toJson2(logsOnly ? logResult2 : { ...result, logs: logResult2 }));
|
|
@@ -109836,7 +110087,7 @@ Monitor with: spur workflow trace ${runId2} --follow`);
|
|
|
109836
110087
|
}
|
|
109837
110088
|
});
|
|
109838
110089
|
workflow.command("list").description("List available workflow YAML files.").option(...SHARED_OPTIONS.jsonSupported).action(async (options) => {
|
|
109839
|
-
const paths =
|
|
110090
|
+
const paths = resolveWorkflowPaths(context4.spurConfig ?? null);
|
|
109840
110091
|
const result = await makeSvc().list(paths);
|
|
109841
110092
|
if (options.json) {
|
|
109842
110093
|
context4.output.write(toJson2(result));
|
|
@@ -111584,7 +111835,9 @@ function createCliContext(options) {
|
|
|
111584
111835
|
const cwd = resolve18(options.cwd ?? process.cwd());
|
|
111585
111836
|
const env = options.env ?? process.env;
|
|
111586
111837
|
const fs3 = createNodeFileSystem3(cwd);
|
|
111587
|
-
const
|
|
111838
|
+
const agentConfig = options.agentConfig ?? options.spurConfig?.agent;
|
|
111839
|
+
const agentRoles = options.agentRoles ?? resolveAgentRoles(agentConfig);
|
|
111840
|
+
const agentRolesSource = agentConfig?.roles === undefined ? "fallback" : "config";
|
|
111588
111841
|
let dbPromise;
|
|
111589
111842
|
if (options.db) {
|
|
111590
111843
|
dbPromise = Promise.resolve(options.db);
|
|
@@ -111601,13 +111854,16 @@ function createCliContext(options) {
|
|
|
111601
111854
|
output: options.output,
|
|
111602
111855
|
getDb,
|
|
111603
111856
|
...options.agentConfig !== undefined ? { agentConfig: options.agentConfig } : {},
|
|
111857
|
+
...options.spurConfig !== undefined ? { spurConfig: options.spurConfig } : {},
|
|
111604
111858
|
agentRoles,
|
|
111859
|
+
agentRolesSource,
|
|
111605
111860
|
agentService: (serviceOptions) => new AgentService({
|
|
111606
111861
|
cwd,
|
|
111607
111862
|
env,
|
|
111608
111863
|
output: options.output,
|
|
111609
|
-
agentConfig
|
|
111864
|
+
agentConfig,
|
|
111610
111865
|
roles: agentRoles,
|
|
111866
|
+
rolesSource: agentRolesSource,
|
|
111611
111867
|
getDb,
|
|
111612
111868
|
...serviceOptions?.events !== undefined ? { events: serviceOptions.events } : {},
|
|
111613
111869
|
...serviceOptions?.processRegistry !== undefined ? { processRegistry: serviceOptions.processRegistry } : {}
|
|
@@ -111636,34 +111892,46 @@ async function createMigratedDbAdapter(cwd = process.cwd(), env = process.env, d
|
|
|
111636
111892
|
async function main(argv = process.argv.slice(2), options = {}) {
|
|
111637
111893
|
const output2 = options.output ?? consoleOutput;
|
|
111638
111894
|
let exitCode = 0;
|
|
111639
|
-
const
|
|
111640
|
-
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
|
+
}
|
|
111641
111912
|
try {
|
|
111642
111913
|
if (configFile !== undefined) {
|
|
111643
|
-
await loadSpurConfig(options.cwd ?? process.cwd(), { embeddedSchemas: EMBEDDED_SPUR_SCHEMAS });
|
|
111644
111914
|
const app = await runNodeApplication({
|
|
111645
111915
|
configLoader: {
|
|
111646
111916
|
configFile,
|
|
111647
|
-
bootstrapSection: "bootstrap"
|
|
111648
|
-
appConfig: { safeParse: (raw2) => spurConfigSchema.safeParse(raw2) }
|
|
111917
|
+
bootstrapSection: "bootstrap"
|
|
111649
111918
|
},
|
|
111650
111919
|
config: { logging: { console: false } },
|
|
111651
111920
|
services: { db: db2 },
|
|
111652
111921
|
async start(appRt) {
|
|
111653
111922
|
const context4 = createCliContext({
|
|
111654
|
-
cwd
|
|
111655
|
-
env
|
|
111923
|
+
cwd,
|
|
111924
|
+
env,
|
|
111656
111925
|
output: output2,
|
|
111657
111926
|
db: db2,
|
|
111658
|
-
|
|
111927
|
+
spurConfig
|
|
111659
111928
|
});
|
|
111660
111929
|
exitCode = await runCommandDispatch(argv, context4, output2);
|
|
111661
111930
|
}
|
|
111662
111931
|
});
|
|
111663
111932
|
await app.stop("shutdown");
|
|
111664
111933
|
} else {
|
|
111665
|
-
const
|
|
111666
|
-
const context4 = createCliContext(ctxOpts);
|
|
111934
|
+
const context4 = createCliContext({ cwd, env, output: output2, db: db2, spurConfig });
|
|
111667
111935
|
exitCode = await runCommandDispatch(argv, context4, output2);
|
|
111668
111936
|
}
|
|
111669
111937
|
} finally {
|