@gobing-ai/spur 0.3.8 → 0.3.10
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/README.md +18 -2
- package/{spur-cli/config → config}/rules/boundary/sp-runtime-path.yaml +9 -0
- package/package.json +4 -3
- package/spur.js +580 -98
- package/web/_astro/BoardApp.C6AZyK1W.js +179 -0
- package/web/_astro/BoardApp.EXjc9f_0.js +1 -0
- package/web/_astro/BoardApp.t7x-dYDo.css +1 -0
- package/web/_astro/TaskDetail.qCmrwQkG.js +1 -0
- package/web/_astro/arc.CbRppOdF.js +1 -0
- package/web/_astro/architectureDiagram-3BPJPVTR.9PfIcrsr.js +36 -0
- package/web/_astro/blockDiagram-GPEHLZMM.D8X1aH9F.js +132 -0
- package/web/_astro/c4Diagram-AAUBKEIU.BnAemEBs.js +10 -0
- package/web/_astro/channel.DDlSVLNA.js +1 -0
- package/web/_astro/chunk-2J33WTMH.DzOqcSmH.js +1 -0
- package/web/_astro/chunk-4BX2VUAB.AqtW-DKu.js +1 -0
- package/web/_astro/chunk-55IACEB6.BIRjE6jR.js +1 -0
- package/web/_astro/chunk-727SXJPM.CgDzPlSk.js +206 -0
- package/web/_astro/chunk-AQP2D5EJ.DjOW-ScW.js +231 -0
- package/web/_astro/chunk-FMBD7UC4.wdJmHym6.js +15 -0
- package/web/_astro/chunk-ND2GUHAM.C-Ho8u3p.js +1 -0
- package/web/_astro/chunk-QZHKN3VN.BF1HouUh.js +1 -0
- package/web/_astro/classDiagram-4FO5ZUOK.DAyOMMHn.js +1 -0
- package/web/_astro/classDiagram-v2-Q7XG4LA2.DAyOMMHn.js +1 -0
- package/web/_astro/client.CdFpTatq.js +9 -0
- package/web/_astro/cose-bilkent-S5V4N54A.CNoutjqT.js +1 -0
- package/web/_astro/cytoscape.esm.D3_iZ_3b.js +321 -0
- package/web/_astro/dagre-BM42HDAG.yQbaJnir.js +4 -0
- package/web/_astro/defaultLocale.CrowFXzY.js +1 -0
- package/web/_astro/diagram-2AECGRRQ.Y-0ZX0wP.js +43 -0
- package/web/_astro/diagram-5GNKFQAL.Co7hW1JF.js +10 -0
- package/web/_astro/diagram-KO2AKTUF.BW6g9zEB.js +3 -0
- package/web/_astro/diagram-LMA3HP47.5laYcnBs.js +24 -0
- package/web/_astro/diagram-OG6HWLK6.DOXfn0B3.js +24 -0
- package/web/_astro/erDiagram-TEJ5UH35.B65zPLW1.js +85 -0
- package/web/_astro/flowDiagram-I6XJVG4X.EyV3nzyc.js +162 -0
- package/web/_astro/ganttDiagram-6RSMTGT7.Dbg3JgqV.js +292 -0
- package/web/_astro/gitGraphDiagram-PVQCEYII.C_h4o8Bn.js +106 -0
- package/web/_astro/graph.D2o_JWn5.js +1 -0
- package/web/_astro/index.A0eX93qW.js +1 -0
- package/web/_astro/index.BSoQ0ZL0.css +1 -0
- package/web/_astro/infoDiagram-5YYISTIA.DmMa9Qku.js +2 -0
- package/web/_astro/init.Gi6I4Gst.js +1 -0
- package/web/_astro/ishikawaDiagram-YF4QCWOH.GWMrgoLC.js +70 -0
- package/web/_astro/journeyDiagram-JHISSGLW.BWABlU6N.js +139 -0
- package/web/_astro/kanban-definition-UN3LZRKU.MbfHFA2-.js +89 -0
- package/web/_astro/katex.HP8lGamR.js +257 -0
- package/web/_astro/layout.DNLMvjEt.js +1 -0
- package/web/_astro/linear.BmIHCCO9.js +1 -0
- package/web/_astro/mermaid.core.CpHEEQAK.js +301 -0
- package/web/_astro/mindmap-definition-RKZ34NQL.DYK94Ave.js +96 -0
- package/web/_astro/ordinal.BYWQX77i.js +1 -0
- package/web/_astro/pieDiagram-4H26LBE5.CnEGAkqK.js +30 -0
- package/web/_astro/quadrantDiagram-W4KKPZXB.CsByTJjg.js +7 -0
- package/web/_astro/requirementDiagram-4Y6WPE33.AL6ZRSrQ.js +84 -0
- package/web/_astro/sankeyDiagram-5OEKKPKP.BLAeuWlE.js +40 -0
- package/web/_astro/sequenceDiagram-3UESZ5HK.BGpsvxUR.js +162 -0
- package/web/_astro/stateDiagram-AJRCARHV.BBk0gd25.js +1 -0
- package/web/_astro/stateDiagram-v2-BHNVJYJU.BrqvmSUS.js +1 -0
- package/web/_astro/timeline-definition-PNZ67QCA.DkZf5CQT.js +120 -0
- package/web/_astro/vennDiagram-CIIHVFJN.BZvWwMZF.js +34 -0
- package/web/_astro/wardley-L42UT6IY.HfB08mt3.js +161 -0
- package/web/_astro/wardleyDiagram-YWT4CUSO.DgpZzmgA.js +78 -0
- package/web/_astro/xychartDiagram-2RQKCTM6.BlgrPsbQ.js +7 -0
- package/web/favicon.svg +4 -0
- package/web/index.html +2 -0
- /package/{spur-cli/config → config}/config.example.yaml +0 -0
- /package/{spur-cli/config → config}/plugins/.gitkeep +0 -0
- /package/{spur-cli/config → config}/rules/README.md +0 -0
- /package/{spur-cli/config → config}/rules/boundary/config-loading-ownership.yaml +0 -0
- /package/{spur-cli/config → config}/rules/boundary/dao-boundary.yaml +0 -0
- /package/{spur-cli/config → config}/rules/boundary/planning-folder-hardcode.yaml +0 -0
- /package/{spur-cli/config → config}/rules/boundary/sp-no-vendor-refs.yaml +0 -0
- /package/{spur-cli/config → config}/rules/migration/rg-dialect.yaml +0 -0
- /package/{spur-cli/config → config}/rules/quality/coverage-gate.yaml +0 -0
- /package/{spur-cli/config → config}/rules/quality/tsdoc-exports.yaml +0 -0
- /package/{spur-cli/config → config}/rules/recommended-post-check.yaml +0 -0
- /package/{spur-cli/config → config}/rules/recommended-pre-check.yaml +0 -0
- /package/{spur-cli/config → config}/rules/rg-migration.yaml +0 -0
- /package/{spur-cli/config → config}/rules/strict/http-boundaries.yaml +0 -0
- /package/{spur-cli/config → config}/rules/strict/rule-files-structural.yaml +0 -0
- /package/{spur-cli/config → config}/rules/strict/runtime-boundaries.yaml +0 -0
- /package/{spur-cli/config → config}/rules/strict-check.yaml +0 -0
- /package/{spur-cli/config → config}/rules/structure/protected-files.yaml +0 -0
- /package/{spur-cli/config → config}/rules/structure/test-focus-skip.yaml +0 -0
- /package/{spur-cli/config → config}/rules/structure/test-location.yaml +0 -0
- /package/{spur-cli/config → config}/rules/surface/check-cli-surface.yaml +0 -0
- /package/{spur-cli/config → config}/rules/typescript/bun-tooling.yaml +0 -0
- /package/{spur-cli/config → config}/rules/typescript/guarded-happy-dom-register.yaml +0 -0
- /package/{spur-cli/config → config}/rules/typescript/happy-dom-teardown.yaml +0 -0
- /package/{spur-cli/config → config}/rules/typescript/no-biome-suppressions.yaml +0 -0
- /package/{spur-cli/config → config}/rules/typescript/no-debugger.yaml +0 -0
- /package/{spur-cli/config → config}/rules/typescript/no-leaky-module-mocks.yaml +0 -0
- /package/{spur-cli/config → config}/rules/typescript/no-module-scope-import-calls.yaml +0 -0
- /package/{spur-cli/config → config}/rules/typescript/no-unmocked-module-eval-side-effects.yaml +0 -0
- /package/{spur-cli/config → config}/rules/typescript/output-boundaries.yaml +0 -0
- /package/{spur-cli/config → config}/rules/ui/ui-import-boundary.yaml +0 -0
- /package/{spur-cli/config → config}/tasks/section-matrix.yaml +0 -0
- /package/{spur-cli/config → config}/templates/AGENTS.md +0 -0
- /package/{spur-cli/config → config}/templates/bdd/checklist.md +0 -0
- /package/{spur-cli/config → config}/templates/bdd/gherkin.md +0 -0
- /package/{spur-cli/config → config}/templates/docs/00_ADR.md +0 -0
- /package/{spur-cli/config → config}/templates/docs/01_PRD.md +0 -0
- /package/{spur-cli/config → config}/templates/docs/02_ROADMAP.md +0 -0
- /package/{spur-cli/config → config}/templates/docs/03_ARCHITECTURE.md +0 -0
- /package/{spur-cli/config → config}/templates/docs/04_DESIGN.md +0 -0
- /package/{spur-cli/config → config}/templates/docs/05_FEATURES.md +0 -0
- /package/{spur-cli/config → config}/templates/docs/99_PROJECT_CONSTITUTION.md +0 -0
- /package/{spur-cli/config → config}/templates/feature/default.md +0 -0
- /package/{spur-cli/config → config}/templates/task/brainstorm.md +0 -0
- /package/{spur-cli/config → config}/templates/task/feature-impl.md +0 -0
- /package/{spur-cli/config → config}/templates/task/issue.md +0 -0
- /package/{spur-cli/config → config}/templates/task/meta.md +0 -0
- /package/{spur-cli/config → config}/templates/task/review.md +0 -0
- /package/{spur-cli/config → config}/templates/task/standard.md +0 -0
- /package/{spur-cli/config → config}/workflows/basic.yaml +0 -0
- /package/{spur-cli/config → config}/workflows/docs-pipeline.yaml +0 -0
- /package/{spur-cli/config → config}/workflows/feature-dev.yaml +0 -0
- /package/{spur-cli/config → config}/workflows/feature-lifecycle.yaml +0 -0
- /package/{spur-cli/config → config}/workflows/idea-pipeline.yaml +0 -0
- /package/{spur-cli/config → config}/workflows/planning-pipeline.yaml +0 -0
- /package/{spur-cli/config → config}/workflows/task-lifecycle.yaml +0 -0
- /package/{spur-cli/config → config}/workflows/task-pipeline.yaml +0 -0
- /package/{spur-cli/config → config}/workflows/wrapup-pipeline.yaml +0 -0
package/spur.js
CHANGED
|
@@ -38376,9 +38376,16 @@ function walk(dir, relPrefix, filter = /\.(ya?ml|json)$/i) {
|
|
|
38376
38376
|
}
|
|
38377
38377
|
return acc;
|
|
38378
38378
|
}
|
|
38379
|
-
|
|
38379
|
+
function listBundledProjectSeedFiles() {
|
|
38380
|
+
const root = bundledConfigRoot();
|
|
38381
|
+
if (root === null)
|
|
38382
|
+
return [];
|
|
38383
|
+
return walk(root, "", PROJECT_SEED_FILTER).filter((rel) => rel !== BUNDLED_CONFIG_EXAMPLE).sort();
|
|
38384
|
+
}
|
|
38385
|
+
var BUNDLED_CONFIG_DIRS, cachedRoot, PROJECT_SEED_FILTER, BUNDLED_CONFIG_EXAMPLE = "config.example.yaml";
|
|
38380
38386
|
var init_bundled_config = __esm(() => {
|
|
38381
38387
|
BUNDLED_CONFIG_DIRS = ["config", "spur-cli/config"];
|
|
38388
|
+
PROJECT_SEED_FILTER = /\.(ya?ml|json|md|gitkeep)$/i;
|
|
38382
38389
|
});
|
|
38383
38390
|
|
|
38384
38391
|
// ../../packages/config/src/template-renderer.ts
|
|
@@ -60758,6 +60765,41 @@ var init_system_event_tap = __esm(() => {
|
|
|
60758
60765
|
init_event_names();
|
|
60759
60766
|
});
|
|
60760
60767
|
|
|
60768
|
+
// ../../packages/app/src/services/system-event-emitter.ts
|
|
60769
|
+
class SystemEventEmitter {
|
|
60770
|
+
dao;
|
|
60771
|
+
logger;
|
|
60772
|
+
constructor(dao2, logger3) {
|
|
60773
|
+
this.dao = dao2;
|
|
60774
|
+
this.logger = logger3;
|
|
60775
|
+
}
|
|
60776
|
+
async emit(event2) {
|
|
60777
|
+
const entry = systemEventCatalogEntry(event2.event);
|
|
60778
|
+
if (!entry)
|
|
60779
|
+
return;
|
|
60780
|
+
try {
|
|
60781
|
+
await this.dao.insert({
|
|
60782
|
+
id: createId("sev"),
|
|
60783
|
+
event_name: entry.name,
|
|
60784
|
+
occurred_at: event2.at,
|
|
60785
|
+
actor: extractSystemEventActor(event2),
|
|
60786
|
+
payload_json: safeStringify(normalizeSystemEventPayload(entry, event2))
|
|
60787
|
+
});
|
|
60788
|
+
await this.dao.prune(SYSTEM_EVENTS_CAP);
|
|
60789
|
+
} catch (error51) {
|
|
60790
|
+
this.logger.warn("system_events emitter: persist failed", {
|
|
60791
|
+
event: event2.event,
|
|
60792
|
+
error: error51 instanceof Error ? `${error51.name}: ${error51.message}` : String(error51)
|
|
60793
|
+
});
|
|
60794
|
+
}
|
|
60795
|
+
}
|
|
60796
|
+
}
|
|
60797
|
+
var init_system_event_emitter = __esm(() => {
|
|
60798
|
+
init_src2();
|
|
60799
|
+
init_event_names();
|
|
60800
|
+
init_system_event_tap();
|
|
60801
|
+
});
|
|
60802
|
+
|
|
60761
60803
|
// ../../packages/app/src/services/task-check.ts
|
|
60762
60804
|
import { dirname as dirname9, join as join9 } from "path";
|
|
60763
60805
|
function isPlaceholderBody(body) {
|
|
@@ -62475,11 +62517,282 @@ var init_team_service = __esm(() => {
|
|
|
62475
62517
|
init_planning_folders();
|
|
62476
62518
|
});
|
|
62477
62519
|
|
|
62520
|
+
// ../../packages/app/src/services/token-ledger-service.ts
|
|
62521
|
+
import { closeSync as closeSync2, existsSync as existsSync5, fstatSync, openSync as openSync2, readSync } from "fs";
|
|
62522
|
+
import { join as join11 } from "path";
|
|
62523
|
+
function isSparseToolActivity(events2) {
|
|
62524
|
+
return events2.length === 0 || !events2.some((e) => TOOL_ACTIVITY_TYPES.has(e.type));
|
|
62525
|
+
}
|
|
62526
|
+
function clampToolUseLimit(raw) {
|
|
62527
|
+
if (raw === undefined || !Number.isFinite(raw) || raw <= 0) {
|
|
62528
|
+
return TOKEN_LEDGER_DEFAULT_LIMIT;
|
|
62529
|
+
}
|
|
62530
|
+
return Math.min(Math.floor(raw), TOKEN_LEDGER_MAX_LIMIT);
|
|
62531
|
+
}
|
|
62532
|
+
function parseLedgerLine(line) {
|
|
62533
|
+
const trimmed = line.trim();
|
|
62534
|
+
if (!trimmed)
|
|
62535
|
+
return null;
|
|
62536
|
+
try {
|
|
62537
|
+
const obj = JSON.parse(trimmed);
|
|
62538
|
+
if (typeof obj.ts !== "string" || typeof obj.session !== "string" || typeof obj.type !== "string") {
|
|
62539
|
+
return null;
|
|
62540
|
+
}
|
|
62541
|
+
const event2 = {
|
|
62542
|
+
ts: obj.ts,
|
|
62543
|
+
session: obj.session,
|
|
62544
|
+
type: obj.type
|
|
62545
|
+
};
|
|
62546
|
+
if (typeof obj.file === "string")
|
|
62547
|
+
event2.file = obj.file;
|
|
62548
|
+
if (typeof obj.summary === "string")
|
|
62549
|
+
event2.summary = obj.summary;
|
|
62550
|
+
if (typeof obj.tokens === "number" && Number.isFinite(obj.tokens) && obj.tokens >= 0) {
|
|
62551
|
+
event2.tokens = obj.tokens;
|
|
62552
|
+
}
|
|
62553
|
+
if (typeof obj.action === "string")
|
|
62554
|
+
event2.action = obj.action;
|
|
62555
|
+
if (typeof obj.sessionId === "string")
|
|
62556
|
+
event2.sessionId = obj.sessionId;
|
|
62557
|
+
if (typeof obj.agent === "string")
|
|
62558
|
+
event2.agent = obj.agent;
|
|
62559
|
+
if (typeof obj.model === "string")
|
|
62560
|
+
event2.model = obj.model;
|
|
62561
|
+
if (obj.totals !== null && typeof obj.totals === "object") {
|
|
62562
|
+
const t = obj.totals;
|
|
62563
|
+
if (typeof t.reads === "number" && typeof t.writes === "number" && typeof t.tokens === "number") {
|
|
62564
|
+
event2.totals = { reads: t.reads, writes: t.writes, tokens: t.tokens };
|
|
62565
|
+
}
|
|
62566
|
+
}
|
|
62567
|
+
return event2;
|
|
62568
|
+
} catch {
|
|
62569
|
+
return null;
|
|
62570
|
+
}
|
|
62571
|
+
}
|
|
62572
|
+
function tailTokenLedgerFile(filePath, limit, chunkSize = DEFAULT_CHUNK, before) {
|
|
62573
|
+
if (!existsSync5(filePath)) {
|
|
62574
|
+
return { events: [], truncated: false };
|
|
62575
|
+
}
|
|
62576
|
+
const target = limit + 1;
|
|
62577
|
+
const fd = openSync2(filePath, "r");
|
|
62578
|
+
try {
|
|
62579
|
+
const { size } = fstatSync(fd);
|
|
62580
|
+
if (size === 0)
|
|
62581
|
+
return { events: [], truncated: false };
|
|
62582
|
+
let pos = size;
|
|
62583
|
+
let carry = "";
|
|
62584
|
+
const events2 = [];
|
|
62585
|
+
while (pos > 0 && events2.length < target) {
|
|
62586
|
+
const n2 = Math.min(chunkSize, pos);
|
|
62587
|
+
pos -= n2;
|
|
62588
|
+
const buf = Buffer.alloc(n2);
|
|
62589
|
+
readSync(fd, buf, 0, n2, pos);
|
|
62590
|
+
const text4 = buf.toString("utf8") + carry;
|
|
62591
|
+
const parts = text4.split(`
|
|
62592
|
+
`);
|
|
62593
|
+
if (pos > 0) {
|
|
62594
|
+
carry = parts.shift() ?? "";
|
|
62595
|
+
} else {
|
|
62596
|
+
carry = "";
|
|
62597
|
+
}
|
|
62598
|
+
for (let i2 = parts.length - 1;i2 >= 0; i2--) {
|
|
62599
|
+
const evt = parseLedgerLine(parts[i2] ?? "");
|
|
62600
|
+
if (!evt)
|
|
62601
|
+
continue;
|
|
62602
|
+
if (before !== undefined && evt.ts >= before)
|
|
62603
|
+
continue;
|
|
62604
|
+
events2.push(evt);
|
|
62605
|
+
if (events2.length >= target)
|
|
62606
|
+
break;
|
|
62607
|
+
}
|
|
62608
|
+
}
|
|
62609
|
+
const truncated = events2.length > limit;
|
|
62610
|
+
return {
|
|
62611
|
+
events: events2.slice(0, limit),
|
|
62612
|
+
truncated
|
|
62613
|
+
};
|
|
62614
|
+
} finally {
|
|
62615
|
+
closeSync2(fd);
|
|
62616
|
+
}
|
|
62617
|
+
}
|
|
62618
|
+
|
|
62619
|
+
class TokenLedgerService {
|
|
62620
|
+
ledgerPath;
|
|
62621
|
+
chunkSize;
|
|
62622
|
+
constructor(options) {
|
|
62623
|
+
this.ledgerPath = options.ledgerPath ?? join11(options.cwd, TOKEN_LEDGER_RELATIVE_PATH);
|
|
62624
|
+
this.chunkSize = options.chunkSize ?? DEFAULT_CHUNK;
|
|
62625
|
+
}
|
|
62626
|
+
get path() {
|
|
62627
|
+
return this.ledgerPath;
|
|
62628
|
+
}
|
|
62629
|
+
snapshot(limitRawOrOpts, maybeBefore) {
|
|
62630
|
+
let limitRaw;
|
|
62631
|
+
let before;
|
|
62632
|
+
if (typeof limitRawOrOpts === "object" && limitRawOrOpts !== null) {
|
|
62633
|
+
limitRaw = limitRawOrOpts.limit;
|
|
62634
|
+
before = limitRawOrOpts.before;
|
|
62635
|
+
} else {
|
|
62636
|
+
limitRaw = limitRawOrOpts;
|
|
62637
|
+
before = maybeBefore;
|
|
62638
|
+
}
|
|
62639
|
+
if (before !== undefined && (typeof before !== "string" || before.length === 0)) {
|
|
62640
|
+
before = undefined;
|
|
62641
|
+
}
|
|
62642
|
+
const limit = clampToolUseLimit(limitRaw);
|
|
62643
|
+
const capturedAt = new Date().toISOString();
|
|
62644
|
+
const { events: raw, truncated } = tailTokenLedgerFile(this.ledgerPath, limit, this.chunkSize, before);
|
|
62645
|
+
const events2 = raw.map((e, seq) => ({ ...e, seq }));
|
|
62646
|
+
const sparseToolActivity = isSparseToolActivity(events2);
|
|
62647
|
+
const oldest = events2.length > 0 ? events2[events2.length - 1] : undefined;
|
|
62648
|
+
const nextBefore = truncated && oldest ? oldest.ts : null;
|
|
62649
|
+
return {
|
|
62650
|
+
events: events2,
|
|
62651
|
+
count: events2.length,
|
|
62652
|
+
limit,
|
|
62653
|
+
truncated,
|
|
62654
|
+
path: this.ledgerPath,
|
|
62655
|
+
capturedAt,
|
|
62656
|
+
sparseToolActivity,
|
|
62657
|
+
nextBefore
|
|
62658
|
+
};
|
|
62659
|
+
}
|
|
62660
|
+
}
|
|
62661
|
+
var TOOL_ACTIVITY_TYPES, TOKEN_LEDGER_DEFAULT_LIMIT = 200, TOKEN_LEDGER_MAX_LIMIT = 1000, TOKEN_LEDGER_RELATIVE_PATH, DEFAULT_CHUNK;
|
|
62662
|
+
var init_token_ledger_service = __esm(() => {
|
|
62663
|
+
TOOL_ACTIVITY_TYPES = new Set(["read", "write", "bash", "grep", "glob"]);
|
|
62664
|
+
TOKEN_LEDGER_RELATIVE_PATH = join11(".spur", "context", "token-ledger.jsonl");
|
|
62665
|
+
DEFAULT_CHUNK = 64 * 1024;
|
|
62666
|
+
});
|
|
62667
|
+
|
|
62668
|
+
// ../../packages/app/src/services/token-ledger-watcher.ts
|
|
62669
|
+
import { closeSync as closeSync3, existsSync as existsSync6, fstatSync as fstatSync2, openSync as openSync3, readSync as readSync2, watch } from "fs";
|
|
62670
|
+
|
|
62671
|
+
class TokenLedgerWatcher {
|
|
62672
|
+
ledgerPath;
|
|
62673
|
+
debounceMs;
|
|
62674
|
+
listeners = new Set;
|
|
62675
|
+
watcher;
|
|
62676
|
+
offset = 0;
|
|
62677
|
+
debounceTimer;
|
|
62678
|
+
started = false;
|
|
62679
|
+
carry = "";
|
|
62680
|
+
constructor(options) {
|
|
62681
|
+
this.ledgerPath = options.ledgerPath;
|
|
62682
|
+
this.debounceMs = options.debounceMs ?? 50;
|
|
62683
|
+
}
|
|
62684
|
+
start() {
|
|
62685
|
+
if (this.started)
|
|
62686
|
+
return;
|
|
62687
|
+
this.started = true;
|
|
62688
|
+
this.offset = this.currentSize();
|
|
62689
|
+
try {
|
|
62690
|
+
const target = existsSync6(this.ledgerPath) ? this.ledgerPath : this.parentDir();
|
|
62691
|
+
this.watcher = watch(target, () => this.schedulePoll());
|
|
62692
|
+
} catch {
|
|
62693
|
+
this.watcher = undefined;
|
|
62694
|
+
}
|
|
62695
|
+
}
|
|
62696
|
+
stop() {
|
|
62697
|
+
this.started = false;
|
|
62698
|
+
if (this.debounceTimer)
|
|
62699
|
+
clearTimeout(this.debounceTimer);
|
|
62700
|
+
this.debounceTimer = undefined;
|
|
62701
|
+
try {
|
|
62702
|
+
this.watcher?.close();
|
|
62703
|
+
} catch {}
|
|
62704
|
+
this.watcher = undefined;
|
|
62705
|
+
this.listeners.clear();
|
|
62706
|
+
}
|
|
62707
|
+
subscribe(listener) {
|
|
62708
|
+
this.listeners.add(listener);
|
|
62709
|
+
if (!this.started)
|
|
62710
|
+
this.start();
|
|
62711
|
+
return () => {
|
|
62712
|
+
this.listeners.delete(listener);
|
|
62713
|
+
if (this.listeners.size === 0)
|
|
62714
|
+
this.stop();
|
|
62715
|
+
};
|
|
62716
|
+
}
|
|
62717
|
+
get subscriberCount() {
|
|
62718
|
+
return this.listeners.size;
|
|
62719
|
+
}
|
|
62720
|
+
parentDir() {
|
|
62721
|
+
const idx = Math.max(this.ledgerPath.lastIndexOf("/"), this.ledgerPath.lastIndexOf("\\"));
|
|
62722
|
+
return idx > 0 ? this.ledgerPath.slice(0, idx) : ".";
|
|
62723
|
+
}
|
|
62724
|
+
currentSize() {
|
|
62725
|
+
if (!existsSync6(this.ledgerPath))
|
|
62726
|
+
return 0;
|
|
62727
|
+
try {
|
|
62728
|
+
const fd = openSync3(this.ledgerPath, "r");
|
|
62729
|
+
try {
|
|
62730
|
+
return fstatSync2(fd).size;
|
|
62731
|
+
} finally {
|
|
62732
|
+
closeSync3(fd);
|
|
62733
|
+
}
|
|
62734
|
+
} catch {
|
|
62735
|
+
return 0;
|
|
62736
|
+
}
|
|
62737
|
+
}
|
|
62738
|
+
schedulePoll() {
|
|
62739
|
+
if (this.debounceTimer)
|
|
62740
|
+
clearTimeout(this.debounceTimer);
|
|
62741
|
+
this.debounceTimer = setTimeout(() => {
|
|
62742
|
+
this.debounceTimer = undefined;
|
|
62743
|
+
this.pollNewBytes();
|
|
62744
|
+
}, this.debounceMs);
|
|
62745
|
+
}
|
|
62746
|
+
pollNewBytes() {
|
|
62747
|
+
if (!existsSync6(this.ledgerPath)) {
|
|
62748
|
+
this.offset = 0;
|
|
62749
|
+
this.carry = "";
|
|
62750
|
+
return;
|
|
62751
|
+
}
|
|
62752
|
+
let size;
|
|
62753
|
+
try {
|
|
62754
|
+
const fd = openSync3(this.ledgerPath, "r");
|
|
62755
|
+
try {
|
|
62756
|
+
size = fstatSync2(fd).size;
|
|
62757
|
+
if (size < this.offset) {
|
|
62758
|
+
this.offset = 0;
|
|
62759
|
+
this.carry = "";
|
|
62760
|
+
}
|
|
62761
|
+
if (size === this.offset)
|
|
62762
|
+
return;
|
|
62763
|
+
const len = size - this.offset;
|
|
62764
|
+
const buf = Buffer.alloc(len);
|
|
62765
|
+
readSync2(fd, buf, 0, len, this.offset);
|
|
62766
|
+
this.offset = size;
|
|
62767
|
+
const text4 = this.carry + buf.toString("utf8");
|
|
62768
|
+
const parts = text4.split(`
|
|
62769
|
+
`);
|
|
62770
|
+
this.carry = parts.pop() ?? "";
|
|
62771
|
+
for (const line of parts) {
|
|
62772
|
+
const evt = parseLedgerLine(line);
|
|
62773
|
+
if (!evt)
|
|
62774
|
+
continue;
|
|
62775
|
+
for (const listener of this.listeners) {
|
|
62776
|
+
try {
|
|
62777
|
+
listener(evt);
|
|
62778
|
+
} catch {}
|
|
62779
|
+
}
|
|
62780
|
+
}
|
|
62781
|
+
} finally {
|
|
62782
|
+
closeSync3(fd);
|
|
62783
|
+
}
|
|
62784
|
+
} catch {}
|
|
62785
|
+
}
|
|
62786
|
+
}
|
|
62787
|
+
var init_token_ledger_watcher = __esm(() => {
|
|
62788
|
+
init_token_ledger_service();
|
|
62789
|
+
});
|
|
62790
|
+
|
|
62478
62791
|
// ../../packages/app/src/workflow/actions/agent-run.ts
|
|
62479
62792
|
import { execFile } from "child_process";
|
|
62480
|
-
import { existsSync as
|
|
62793
|
+
import { existsSync as existsSync7 } from "fs";
|
|
62481
62794
|
import { mkdir, writeFile } from "fs/promises";
|
|
62482
|
-
import { dirname as dirname10, isAbsolute as isAbsolute2, join as
|
|
62795
|
+
import { dirname as dirname10, isAbsolute as isAbsolute2, join as join12 } from "path";
|
|
62483
62796
|
import { promisify as promisify3 } from "util";
|
|
62484
62797
|
|
|
62485
62798
|
class AgentRunActionRunner {
|
|
@@ -62533,13 +62846,13 @@ class AgentRunActionRunner {
|
|
|
62533
62846
|
const { exitCode: exitCode2, answer } = captured;
|
|
62534
62847
|
const ok2 = exitCode2 === 0;
|
|
62535
62848
|
if (answerFile !== undefined) {
|
|
62536
|
-
const target = isAbsolute2(answerFile) ? answerFile :
|
|
62849
|
+
const target = isAbsolute2(answerFile) ? answerFile : join12(cwd, answerFile);
|
|
62537
62850
|
await mkdir(dirname10(target), { recursive: true });
|
|
62538
62851
|
await writeFile(target, answer, "utf8");
|
|
62539
62852
|
}
|
|
62540
62853
|
if (ok2 && expectFile !== undefined) {
|
|
62541
|
-
const target = isAbsolute2(expectFile) ? expectFile :
|
|
62542
|
-
if (!
|
|
62854
|
+
const target = isAbsolute2(expectFile) ? expectFile : join12(cwd, expectFile);
|
|
62855
|
+
if (!existsSync7(target)) {
|
|
62543
62856
|
return {
|
|
62544
62857
|
ok: false,
|
|
62545
62858
|
data: { exitCode: exitCode2, agent: agentLabel, answer },
|
|
@@ -62560,8 +62873,8 @@ class AgentRunActionRunner {
|
|
|
62560
62873
|
const exitCode = await this.agentService.run(input, flags);
|
|
62561
62874
|
const ok = exitCode === 0;
|
|
62562
62875
|
if (ok && expectFile !== undefined) {
|
|
62563
|
-
const target = isAbsolute2(expectFile) ? expectFile :
|
|
62564
|
-
if (!
|
|
62876
|
+
const target = isAbsolute2(expectFile) ? expectFile : join12(cwd, expectFile);
|
|
62877
|
+
if (!existsSync7(target)) {
|
|
62565
62878
|
return {
|
|
62566
62879
|
ok: false,
|
|
62567
62880
|
data: { exitCode, agent: agentLabel },
|
|
@@ -62638,7 +62951,7 @@ async function writePartialWorkArtifact(context4, agentLabel, model, captured, c
|
|
|
62638
62951
|
""
|
|
62639
62952
|
].join(`
|
|
62640
62953
|
`);
|
|
62641
|
-
const target =
|
|
62954
|
+
const target = join12(cwd, ".spur", "run", `${context4.runId}-${context4.stateOrNodeId}-partial.md`);
|
|
62642
62955
|
await mkdir(dirname10(target), { recursive: true });
|
|
62643
62956
|
await writeFile(target, body, "utf8");
|
|
62644
62957
|
} catch {}
|
|
@@ -63302,7 +63615,7 @@ var now = () => new Date().toISOString();
|
|
|
63302
63615
|
// ../../packages/app/src/services/workflow-service.ts
|
|
63303
63616
|
import { access as access2, lstat, readdir as readdir3, readFile as readFile2, realpath } from "fs/promises";
|
|
63304
63617
|
import { homedir as homedir3 } from "os";
|
|
63305
|
-
import { join as
|
|
63618
|
+
import { join as join13, resolve as resolve3 } from "path";
|
|
63306
63619
|
function signalSubprocess(pid) {
|
|
63307
63620
|
try {
|
|
63308
63621
|
process.kill(-pid, "SIGTERM");
|
|
@@ -63506,7 +63819,7 @@ class WorkflowAppService {
|
|
|
63506
63819
|
}
|
|
63507
63820
|
async list(workflowPaths = [".spur/workflows/"]) {
|
|
63508
63821
|
const projectRoot = this.ctx.cwd;
|
|
63509
|
-
const globalRoot =
|
|
63822
|
+
const globalRoot = join13(homedir3(), ".config", "spur");
|
|
63510
63823
|
const layers = [];
|
|
63511
63824
|
const entries = [];
|
|
63512
63825
|
const scannedPaths = new Set;
|
|
@@ -63842,6 +64155,7 @@ var isActionStarted = (e) => ("kind" in e) && ("node" in e), isActionFinished =
|
|
|
63842
64155
|
// ../../packages/app/src/index.ts
|
|
63843
64156
|
var exports_src2 = {};
|
|
63844
64157
|
__export(exports_src2, {
|
|
64158
|
+
tailTokenLedgerFile: () => tailTokenLedgerFile,
|
|
63845
64159
|
systemEventCatalogEntry: () => systemEventCatalogEntry,
|
|
63846
64160
|
resolvePlanningFolders: () => resolvePlanningFolders,
|
|
63847
64161
|
renderTesting: () => renderTesting,
|
|
@@ -63854,6 +64168,7 @@ __export(exports_src2, {
|
|
|
63854
64168
|
readVerdict: () => readVerdict,
|
|
63855
64169
|
parseVerdict: () => parseVerdict,
|
|
63856
64170
|
parsePsOutput: () => parsePsOutput,
|
|
64171
|
+
parseLedgerLine: () => parseLedgerLine,
|
|
63857
64172
|
parseEtimeToSeconds: () => parseEtimeToSeconds,
|
|
63858
64173
|
normalizeSystemEventPayload: () => normalizeSystemEventPayload,
|
|
63859
64174
|
hitlConfirmDefault: () => hitlConfirmDefault,
|
|
@@ -63861,14 +64176,21 @@ __export(exports_src2, {
|
|
|
63861
64176
|
extractSystemEventActor: () => extractSystemEventActor,
|
|
63862
64177
|
deriveVerdict: () => deriveVerdict,
|
|
63863
64178
|
createPsProcessInspector: () => createPsProcessInspector,
|
|
64179
|
+
clampToolUseLimit: () => clampToolUseLimit,
|
|
63864
64180
|
bridgeEventBus: () => bridgeEventBus,
|
|
63865
64181
|
WorkflowAppService: () => WorkflowAppService,
|
|
63866
64182
|
UnsupportedProcessPlatformError: () => UnsupportedProcessPlatformError,
|
|
64183
|
+
TokenLedgerWatcher: () => TokenLedgerWatcher,
|
|
64184
|
+
TokenLedgerService: () => TokenLedgerService,
|
|
63867
64185
|
TeamService: () => TeamService,
|
|
63868
64186
|
TaskService: () => TaskService,
|
|
63869
64187
|
TaskCheckService: () => TaskCheckService,
|
|
64188
|
+
TOKEN_LEDGER_RELATIVE_PATH: () => TOKEN_LEDGER_RELATIVE_PATH,
|
|
64189
|
+
TOKEN_LEDGER_MAX_LIMIT: () => TOKEN_LEDGER_MAX_LIMIT,
|
|
64190
|
+
TOKEN_LEDGER_DEFAULT_LIMIT: () => TOKEN_LEDGER_DEFAULT_LIMIT,
|
|
63870
64191
|
TASK_LIFECYCLE_PROFILE: () => TASK_LIFECYCLE_PROFILE,
|
|
63871
64192
|
TASK_ACTION_COMMANDS: () => TASK_ACTION_COMMANDS,
|
|
64193
|
+
SystemEventEmitter: () => SystemEventEmitter,
|
|
63872
64194
|
SupervisorService: () => SupervisorService,
|
|
63873
64195
|
SYSTEM_EVENT_STREAMED_NAMES: () => SYSTEM_EVENT_STREAMED_NAMES,
|
|
63874
64196
|
SYSTEM_EVENT_PREFIXES: () => SYSTEM_EVENT_PREFIXES,
|
|
@@ -63920,11 +64242,14 @@ var init_src3 = __esm(() => {
|
|
|
63920
64242
|
init_process_inspector();
|
|
63921
64243
|
init_process_inventory_service();
|
|
63922
64244
|
init_rule_service();
|
|
64245
|
+
init_system_event_emitter();
|
|
63923
64246
|
init_system_event_tap();
|
|
63924
64247
|
init_task_check();
|
|
63925
64248
|
init_task_record();
|
|
63926
64249
|
init_task_service();
|
|
63927
64250
|
init_team_service();
|
|
64251
|
+
init_token_ledger_service();
|
|
64252
|
+
init_token_ledger_watcher();
|
|
63928
64253
|
init_workflow_service();
|
|
63929
64254
|
init_agent_run();
|
|
63930
64255
|
init_file_exists();
|
|
@@ -71371,13 +71696,38 @@ ${prompt}`;
|
|
|
71371
71696
|
// src/commands/feature.ts
|
|
71372
71697
|
init_src3();
|
|
71373
71698
|
|
|
71699
|
+
// src/planning-emitter.ts
|
|
71700
|
+
init_src3();
|
|
71701
|
+
init_src2();
|
|
71702
|
+
function makeWarnLogger(context4) {
|
|
71703
|
+
return {
|
|
71704
|
+
warn: (msg, data) => {
|
|
71705
|
+
context4.output.error(`${msg}${data ? ` ${JSON.stringify(data)}` : ""}`);
|
|
71706
|
+
}
|
|
71707
|
+
};
|
|
71708
|
+
}
|
|
71709
|
+
function makePlanningEmitter(context4) {
|
|
71710
|
+
let cached2;
|
|
71711
|
+
const logger3 = makeWarnLogger(context4);
|
|
71712
|
+
return {
|
|
71713
|
+
async emit(event2) {
|
|
71714
|
+
try {
|
|
71715
|
+
cached2 ??= new SystemEventEmitter(new SystemEventDao(await context4.getDb()), logger3);
|
|
71716
|
+
await cached2.emit(event2);
|
|
71717
|
+
} catch (error51) {
|
|
71718
|
+
context4.output.error(`system_events emitter: ${error51 instanceof Error ? error51.message : String(error51)}`);
|
|
71719
|
+
}
|
|
71720
|
+
}
|
|
71721
|
+
};
|
|
71722
|
+
}
|
|
71723
|
+
|
|
71374
71724
|
// src/workflow/make-lifecycle-adapter.ts
|
|
71375
71725
|
init_src3();
|
|
71376
71726
|
init_loader();
|
|
71377
71727
|
init_src2();
|
|
71378
|
-
import { existsSync as
|
|
71728
|
+
import { existsSync as existsSync8 } from "fs";
|
|
71379
71729
|
import { homedir as homedir4 } from "os";
|
|
71380
|
-
import { join as
|
|
71730
|
+
import { join as join14, resolve as resolve4 } from "path";
|
|
71381
71731
|
|
|
71382
71732
|
// src/workflow/resolve-spur-bin.ts
|
|
71383
71733
|
import { basename as basename2 } from "path";
|
|
@@ -71395,23 +71745,23 @@ function resolveSpurBin() {
|
|
|
71395
71745
|
}
|
|
71396
71746
|
|
|
71397
71747
|
// src/workflow/make-lifecycle-adapter.ts
|
|
71398
|
-
var GLOBAL_CONFIG_DIR =
|
|
71748
|
+
var GLOBAL_CONFIG_DIR = join14(".config", "spur");
|
|
71399
71749
|
function globalConfigRoot(context4) {
|
|
71400
71750
|
const override = context4.env.SPUR_GLOBAL_RULES_DIR;
|
|
71401
|
-
return override !== undefined && override.length > 0 ? resolve4(context4.cwd, override) :
|
|
71751
|
+
return override !== undefined && override.length > 0 ? resolve4(context4.cwd, override) : join14(homedir4(), GLOBAL_CONFIG_DIR);
|
|
71402
71752
|
}
|
|
71403
71753
|
function resolveWorkflowPath(context4, profile) {
|
|
71404
71754
|
const bundledRoot = bundledConfigRoot();
|
|
71405
71755
|
if (bundledRoot !== null) {
|
|
71406
|
-
const bundledPath =
|
|
71407
|
-
if (
|
|
71756
|
+
const bundledPath = join14(bundledRoot, "workflows", `${profile.workflowName}.yaml`);
|
|
71757
|
+
if (existsSync8(bundledPath))
|
|
71408
71758
|
return bundledPath;
|
|
71409
71759
|
}
|
|
71410
|
-
const projectPath =
|
|
71411
|
-
if (
|
|
71760
|
+
const projectPath = join14(context4.cwd, ".spur", "workflows", `${profile.workflowName}.yaml`);
|
|
71761
|
+
if (existsSync8(projectPath))
|
|
71412
71762
|
return projectPath;
|
|
71413
|
-
const globalPath =
|
|
71414
|
-
if (
|
|
71763
|
+
const globalPath = join14(globalConfigRoot(context4), "workflows", `${profile.workflowName}.yaml`);
|
|
71764
|
+
if (existsSync8(globalPath))
|
|
71415
71765
|
return globalPath;
|
|
71416
71766
|
return null;
|
|
71417
71767
|
}
|
|
@@ -71694,7 +72044,8 @@ async function makeService(context4, folderOverride) {
|
|
|
71694
72044
|
const lifecycle = makeLifecycleAdapter(context4, FEATURE_LIFECYCLE_PROFILE);
|
|
71695
72045
|
const writeService = new PlanningWriteService({
|
|
71696
72046
|
fs: context4.fs,
|
|
71697
|
-
...lifecycle ? { lifecycle } : {}
|
|
72047
|
+
...lifecycle ? { lifecycle } : {},
|
|
72048
|
+
emitter: makePlanningEmitter(context4)
|
|
71698
72049
|
});
|
|
71699
72050
|
return new FeatureService({ fs: context4.fs, writeService, featuresDir, tasksDir });
|
|
71700
72051
|
}
|
|
@@ -71764,13 +72115,13 @@ init_loader();
|
|
|
71764
72115
|
init_src2();
|
|
71765
72116
|
init_dist10();
|
|
71766
72117
|
import { homedir as homedir5 } from "os";
|
|
71767
|
-
import { join as
|
|
72118
|
+
import { join as join15, resolve as resolve5 } from "path";
|
|
71768
72119
|
|
|
71769
72120
|
// src/config.ts
|
|
71770
72121
|
var CLI_CONFIG = {
|
|
71771
72122
|
binaryName: "spur",
|
|
71772
72123
|
binaryLabel: "spur",
|
|
71773
|
-
binaryVersion: "0.3.
|
|
72124
|
+
binaryVersion: "0.3.10",
|
|
71774
72125
|
configDir: ".spur",
|
|
71775
72126
|
configFile: ".spur/config.yaml",
|
|
71776
72127
|
databaseFile: ".spur/spur.db"
|
|
@@ -71821,8 +72172,8 @@ var SCAFFOLD_MANIFEST = [
|
|
|
71821
72172
|
];
|
|
71822
72173
|
|
|
71823
72174
|
// src/commands/init.ts
|
|
71824
|
-
var GLOBAL_CONFIG_DIR2 =
|
|
71825
|
-
var GLOBAL_RULES_DIR2 =
|
|
72175
|
+
var GLOBAL_CONFIG_DIR2 = join15(".config", "spur");
|
|
72176
|
+
var GLOBAL_RULES_DIR2 = join15(GLOBAL_CONFIG_DIR2, "rules");
|
|
71826
72177
|
var GLOBAL_CONFIG_EXAMPLE = "config.example.yaml";
|
|
71827
72178
|
var GLOBAL_CONFIG_FILE2 = "config.yaml";
|
|
71828
72179
|
var INDEXED_CONTEXT_MARKER = "## Indexed context";
|
|
@@ -71849,7 +72200,7 @@ If \`.spur/context/\` is absent, proceed normally. Never block work on its absen
|
|
|
71849
72200
|
`;
|
|
71850
72201
|
function globalRulesRoot(context4) {
|
|
71851
72202
|
const override = context4.env.SPUR_GLOBAL_RULES_DIR;
|
|
71852
|
-
return override !== undefined && override.length > 0 ? resolve5(context4.cwd, override) :
|
|
72203
|
+
return override !== undefined && override.length > 0 ? resolve5(context4.cwd, override) : join15(homedir5(), GLOBAL_RULES_DIR2);
|
|
71853
72204
|
}
|
|
71854
72205
|
async function writeIfNew(context4, path9, content, force, result) {
|
|
71855
72206
|
if (!force && await context4.fs.exists(path9)) {
|
|
@@ -71866,11 +72217,11 @@ async function seedGlobalRules(context4) {
|
|
|
71866
72217
|
const target = globalRulesRoot(context4);
|
|
71867
72218
|
let written = 0;
|
|
71868
72219
|
for (const relPath of await listBundledRuleFiles()) {
|
|
71869
|
-
const destination =
|
|
72220
|
+
const destination = join15(target, relPath);
|
|
71870
72221
|
if (await context4.fs.exists(destination))
|
|
71871
72222
|
continue;
|
|
71872
|
-
await context4.fs.ensureDir(
|
|
71873
|
-
await context4.fs.writeFile(destination, await context4.fs.readFile(
|
|
72223
|
+
await context4.fs.ensureDir(join15(target, ...relPath.split("/").slice(0, -1)));
|
|
72224
|
+
await context4.fs.writeFile(destination, await context4.fs.readFile(join15(source, relPath)));
|
|
71874
72225
|
written += 1;
|
|
71875
72226
|
}
|
|
71876
72227
|
return written;
|
|
@@ -71880,20 +72231,20 @@ async function seedGlobalConfig(context4) {
|
|
|
71880
72231
|
if (source === null)
|
|
71881
72232
|
return 0;
|
|
71882
72233
|
const globalOverride = context4.env.SPUR_GLOBAL_RULES_DIR;
|
|
71883
|
-
const target = globalOverride !== undefined && globalOverride.length > 0 ? resolve5(context4.cwd, globalOverride) :
|
|
72234
|
+
const target = globalOverride !== undefined && globalOverride.length > 0 ? resolve5(context4.cwd, globalOverride) : join15(homedir5(), GLOBAL_CONFIG_DIR2);
|
|
71884
72235
|
let written = 0;
|
|
71885
72236
|
for (const relPath of listBundledConfigFiles()) {
|
|
71886
72237
|
if (relPath === GLOBAL_CONFIG_EXAMPLE)
|
|
71887
72238
|
continue;
|
|
71888
|
-
const destination =
|
|
72239
|
+
const destination = join15(target, relPath);
|
|
71889
72240
|
if (await context4.fs.exists(destination))
|
|
71890
72241
|
continue;
|
|
71891
|
-
await context4.fs.ensureDir(
|
|
71892
|
-
await context4.fs.writeFile(destination, await context4.fs.readFile(
|
|
72242
|
+
await context4.fs.ensureDir(join15(target, ...relPath.split("/").slice(0, -1)));
|
|
72243
|
+
await context4.fs.writeFile(destination, await context4.fs.readFile(join15(source, relPath)));
|
|
71893
72244
|
written += 1;
|
|
71894
72245
|
}
|
|
71895
|
-
const examplePath =
|
|
71896
|
-
const globalConfigPath =
|
|
72246
|
+
const examplePath = join15(source, GLOBAL_CONFIG_EXAMPLE);
|
|
72247
|
+
const globalConfigPath = join15(target, GLOBAL_CONFIG_FILE2);
|
|
71897
72248
|
if (await context4.fs.exists(examplePath) && !await context4.fs.exists(globalConfigPath)) {
|
|
71898
72249
|
await context4.fs.ensureDir(target);
|
|
71899
72250
|
await context4.fs.writeFile(globalConfigPath, await context4.fs.readFile(examplePath));
|
|
@@ -71907,7 +72258,7 @@ function registerInitCommand(program2, context4) {
|
|
|
71907
72258
|
const force = options.force === true;
|
|
71908
72259
|
const minimal = options.minimal === true;
|
|
71909
72260
|
const projectName = options.name ?? "default";
|
|
71910
|
-
const configPath =
|
|
72261
|
+
const configPath = join15(context4.cwd, CLI_CONFIG.configFile);
|
|
71911
72262
|
if (!force && await context4.fs.exists(configPath)) {
|
|
71912
72263
|
const message = `Already initialized: ${CLI_CONFIG.configFile}. Use --force to overwrite.`;
|
|
71913
72264
|
context4.output.write(json3 ? toJson2({ ok: false, reason: "already-initialized", config: CLI_CONFIG.configFile }) : message);
|
|
@@ -71942,13 +72293,13 @@ function registerInitCommand(program2, context4) {
|
|
|
71942
72293
|
].join(`
|
|
71943
72294
|
`)}
|
|
71944
72295
|
`;
|
|
71945
|
-
await context4.fs.ensureDir(
|
|
72296
|
+
await context4.fs.ensureDir(join15(context4.cwd, CLI_CONFIG.configDir));
|
|
71946
72297
|
await context4.fs.writeFile(configPath, configYaml);
|
|
71947
72298
|
result.created.push(configPath);
|
|
71948
|
-
const agentsDir =
|
|
72299
|
+
const agentsDir = join15(context4.cwd, CLI_CONFIG.configDir, "agents");
|
|
71949
72300
|
await context4.fs.ensureDir(agentsDir);
|
|
71950
|
-
await writeIfNew(context4,
|
|
71951
|
-
const gitignorePath =
|
|
72301
|
+
await writeIfNew(context4, join15(agentsDir, ".gitkeep"), "", force, result);
|
|
72302
|
+
const gitignorePath = join15(context4.cwd, ".gitignore");
|
|
71952
72303
|
const contextEntry = ".spur/context/";
|
|
71953
72304
|
if (await context4.fs.exists(gitignorePath)) {
|
|
71954
72305
|
const existing = await context4.fs.readFile(gitignorePath);
|
|
@@ -71967,13 +72318,21 @@ ${contextEntry}
|
|
|
71967
72318
|
if (!minimal) {
|
|
71968
72319
|
const configRoot = bundledConfigRoot();
|
|
71969
72320
|
if (configRoot !== null) {
|
|
72321
|
+
for (const relPath of listBundledProjectSeedFiles()) {
|
|
72322
|
+
const sourcePath = join15(configRoot, relPath);
|
|
72323
|
+
if (!await context4.fs.exists(sourcePath))
|
|
72324
|
+
continue;
|
|
72325
|
+
const targetPath = join15(context4.cwd, CLI_CONFIG.configDir, relPath);
|
|
72326
|
+
await context4.fs.ensureDir(join15(targetPath, ".."));
|
|
72327
|
+
await writeIfNew(context4, targetPath, await context4.fs.readFile(sourcePath), force, result);
|
|
72328
|
+
}
|
|
71970
72329
|
for (const entry of SCAFFOLD_MANIFEST) {
|
|
71971
|
-
const sourcePath =
|
|
72330
|
+
const sourcePath = join15(configRoot, entry.source);
|
|
71972
72331
|
if (!await context4.fs.exists(sourcePath))
|
|
71973
72332
|
continue;
|
|
71974
|
-
const baseDir = entry.root === true ? context4.cwd :
|
|
71975
|
-
const targetPath =
|
|
71976
|
-
await context4.fs.ensureDir(
|
|
72333
|
+
const baseDir = entry.root === true ? context4.cwd : join15(context4.cwd, CLI_CONFIG.configDir);
|
|
72334
|
+
const targetPath = join15(baseDir, entry.target);
|
|
72335
|
+
await context4.fs.ensureDir(join15(targetPath, ".."));
|
|
71977
72336
|
const entryForce = entry.preserve === true ? false : force;
|
|
71978
72337
|
let body = await context4.fs.readFile(sourcePath);
|
|
71979
72338
|
if (entry.target === "AGENTS.md") {
|
|
@@ -71983,7 +72342,7 @@ ${contextEntry}
|
|
|
71983
72342
|
}
|
|
71984
72343
|
}
|
|
71985
72344
|
}
|
|
71986
|
-
const agentsMdPath =
|
|
72345
|
+
const agentsMdPath = join15(context4.cwd, "AGENTS.md");
|
|
71987
72346
|
if (await context4.fs.exists(agentsMdPath)) {
|
|
71988
72347
|
const existing = await context4.fs.readFile(agentsMdPath);
|
|
71989
72348
|
if (!existing.includes(INDEXED_CONTEXT_MARKER)) {
|
|
@@ -72161,10 +72520,10 @@ function parseInterval2(raw) {
|
|
|
72161
72520
|
|
|
72162
72521
|
// src/commands/migrate.ts
|
|
72163
72522
|
init_src2();
|
|
72164
|
-
import { join as
|
|
72523
|
+
import { join as join16 } from "path";
|
|
72165
72524
|
function registerMigrateCommand(program2, context4) {
|
|
72166
72525
|
program2.command("migrate").summary("apply CLI-owned schema migrations").option("--json", "Output machine-readable JSON").action(async (options) => {
|
|
72167
|
-
const migrations = await loadSqlMigrations(
|
|
72526
|
+
const migrations = await loadSqlMigrations(join16(context4.cwd, "drizzle")).catch(() => {
|
|
72168
72527
|
return;
|
|
72169
72528
|
});
|
|
72170
72529
|
const applied = await applyCliMigrations(await context4.getDb(), migrations);
|
|
@@ -72416,7 +72775,7 @@ function formatTraceDetail(detail) {
|
|
|
72416
72775
|
|
|
72417
72776
|
// src/commands/serve.ts
|
|
72418
72777
|
init_src();
|
|
72419
|
-
import { join as
|
|
72778
|
+
import { join as join20 } from "path";
|
|
72420
72779
|
|
|
72421
72780
|
// ../server/src/index.ts
|
|
72422
72781
|
init_src();
|
|
@@ -72426,11 +72785,11 @@ init_src3();
|
|
|
72426
72785
|
init_src();
|
|
72427
72786
|
init_loader();
|
|
72428
72787
|
init_src2();
|
|
72429
|
-
import { dirname as dirname12, isAbsolute as isAbsolute3, join as
|
|
72788
|
+
import { dirname as dirname12, isAbsolute as isAbsolute3, join as join19 } from "path";
|
|
72430
72789
|
init_dist5();
|
|
72431
72790
|
|
|
72432
72791
|
// ../server/src/bootstrap.ts
|
|
72433
|
-
import { join as
|
|
72792
|
+
import { join as join17 } from "path";
|
|
72434
72793
|
|
|
72435
72794
|
// ../../node_modules/.bun/radash@12.1.1/node_modules/radash/dist/esm/async.mjs
|
|
72436
72795
|
var guard = (func, shouldGuard) => {
|
|
@@ -78534,23 +78893,128 @@ function parseLimit(raw2, fallback) {
|
|
|
78534
78893
|
|
|
78535
78894
|
// ../server/src/modules/observability/index.ts
|
|
78536
78895
|
init_src3();
|
|
78896
|
+
var ledgerWatcher;
|
|
78897
|
+
var watcherPath;
|
|
78898
|
+
function getLedgerWatcher(path9) {
|
|
78899
|
+
if (!ledgerWatcher || watcherPath !== path9) {
|
|
78900
|
+
ledgerWatcher?.stop();
|
|
78901
|
+
ledgerWatcher = new TokenLedgerWatcher({ ledgerPath: path9 });
|
|
78902
|
+
watcherPath = path9;
|
|
78903
|
+
ledgerWatcher.start();
|
|
78904
|
+
}
|
|
78905
|
+
return ledgerWatcher;
|
|
78906
|
+
}
|
|
78907
|
+
function toolUseSsePayload(event2) {
|
|
78908
|
+
return {
|
|
78909
|
+
type: "tool-use",
|
|
78910
|
+
occurredAt: event2.ts,
|
|
78911
|
+
event: event2
|
|
78912
|
+
};
|
|
78913
|
+
}
|
|
78914
|
+
function handleProcesses(ctx) {
|
|
78915
|
+
return async (c3) => {
|
|
78916
|
+
try {
|
|
78917
|
+
const snapshot = await ctx.processInventory().snapshot();
|
|
78918
|
+
return c3.json(snapshot);
|
|
78919
|
+
} catch (err) {
|
|
78920
|
+
if (err instanceof UnsupportedProcessPlatformError) {
|
|
78921
|
+
return c3.json({ error: err.message, code: err.code }, 501);
|
|
78922
|
+
}
|
|
78923
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
78924
|
+
return c3.json({ error: message }, 500);
|
|
78925
|
+
}
|
|
78926
|
+
};
|
|
78927
|
+
}
|
|
78928
|
+
function handleToolUseGet(ctx) {
|
|
78929
|
+
return (c3) => {
|
|
78930
|
+
try {
|
|
78931
|
+
const limitParam = c3.req.query("limit");
|
|
78932
|
+
let limitRaw;
|
|
78933
|
+
if (limitParam !== undefined) {
|
|
78934
|
+
const parsed = Number.parseInt(limitParam, 10);
|
|
78935
|
+
if (!Number.isNaN(parsed))
|
|
78936
|
+
limitRaw = parsed;
|
|
78937
|
+
}
|
|
78938
|
+
const before = c3.req.query("before") ?? undefined;
|
|
78939
|
+
const limit = clampToolUseLimit(limitRaw);
|
|
78940
|
+
const snapshot = ctx.tokenLedger().snapshot({ limit, before });
|
|
78941
|
+
return c3.json(snapshot);
|
|
78942
|
+
} catch (err) {
|
|
78943
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
78944
|
+
return c3.json({ error: message }, 500);
|
|
78945
|
+
}
|
|
78946
|
+
};
|
|
78947
|
+
}
|
|
78948
|
+
function handleToolUseStream(ctx) {
|
|
78949
|
+
return (c3) => {
|
|
78950
|
+
const closed = { current: false };
|
|
78951
|
+
let heartbeatInterval;
|
|
78952
|
+
let unsubscribe;
|
|
78953
|
+
const signal = c3.req.raw.signal;
|
|
78954
|
+
let closeController = () => {};
|
|
78955
|
+
const teardown = () => {
|
|
78956
|
+
if (closed.current)
|
|
78957
|
+
return;
|
|
78958
|
+
closed.current = true;
|
|
78959
|
+
if (heartbeatInterval)
|
|
78960
|
+
clearInterval(heartbeatInterval);
|
|
78961
|
+
try {
|
|
78962
|
+
unsubscribe?.();
|
|
78963
|
+
} catch {}
|
|
78964
|
+
signal.removeEventListener("abort", teardown);
|
|
78965
|
+
closeController();
|
|
78966
|
+
};
|
|
78967
|
+
const stream = new ReadableStream({
|
|
78968
|
+
start(controller) {
|
|
78969
|
+
const encoder = new TextEncoder;
|
|
78970
|
+
closeController = () => {
|
|
78971
|
+
try {
|
|
78972
|
+
controller.close();
|
|
78973
|
+
} catch {}
|
|
78974
|
+
};
|
|
78975
|
+
if (signal.aborted) {
|
|
78976
|
+
teardown();
|
|
78977
|
+
return;
|
|
78978
|
+
}
|
|
78979
|
+
signal.addEventListener("abort", teardown);
|
|
78980
|
+
heartbeatInterval = setInterval(sendSseKeepalive, 15000, closed, controller, encoder);
|
|
78981
|
+
enqueueSseFrame(closed, controller, encoder, {
|
|
78982
|
+
type: "connected",
|
|
78983
|
+
occurredAt: new Date().toISOString()
|
|
78984
|
+
});
|
|
78985
|
+
try {
|
|
78986
|
+
const path9 = ctx.tokenLedger().path;
|
|
78987
|
+
const watcher = getLedgerWatcher(path9);
|
|
78988
|
+
unsubscribe = watcher.subscribe((event2) => {
|
|
78989
|
+
if (!enqueueSseFrame(closed, controller, encoder, toolUseSsePayload(event2)))
|
|
78990
|
+
teardown();
|
|
78991
|
+
});
|
|
78992
|
+
} catch {
|
|
78993
|
+
enqueueSseFrame(closed, controller, encoder, {
|
|
78994
|
+
type: "error",
|
|
78995
|
+
error: "ledger watch unavailable",
|
|
78996
|
+
occurredAt: new Date().toISOString()
|
|
78997
|
+
});
|
|
78998
|
+
}
|
|
78999
|
+
},
|
|
79000
|
+
cancel() {
|
|
79001
|
+
teardown();
|
|
79002
|
+
}
|
|
79003
|
+
});
|
|
79004
|
+
return c3.newResponse(stream, 200, {
|
|
79005
|
+
"Content-Type": "text/event-stream",
|
|
79006
|
+
"Cache-Control": "no-cache"
|
|
79007
|
+
});
|
|
79008
|
+
};
|
|
79009
|
+
}
|
|
78537
79010
|
var observabilityModule = {
|
|
78538
79011
|
name: "observability",
|
|
78539
79012
|
mount(app, ctx) {
|
|
78540
79013
|
if (!ctx)
|
|
78541
79014
|
return;
|
|
78542
|
-
app.get("/api/observability/processes",
|
|
78543
|
-
|
|
78544
|
-
|
|
78545
|
-
return c3.json(snapshot);
|
|
78546
|
-
} catch (err) {
|
|
78547
|
-
if (err instanceof UnsupportedProcessPlatformError) {
|
|
78548
|
-
return c3.json({ error: err.message, code: err.code }, 501);
|
|
78549
|
-
}
|
|
78550
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
78551
|
-
return c3.json({ error: message }, 500);
|
|
78552
|
-
}
|
|
78553
|
-
});
|
|
79015
|
+
app.get("/api/observability/processes", handleProcesses(ctx));
|
|
79016
|
+
app.get("/api/observability/tool-use", handleToolUseGet(ctx));
|
|
79017
|
+
app.get("/api/observability/tool-use/stream", handleToolUseStream(ctx));
|
|
78554
79018
|
}
|
|
78555
79019
|
};
|
|
78556
79020
|
|
|
@@ -80788,7 +81252,7 @@ function createApp(appRt, opts) {
|
|
|
80788
81252
|
app.use("*", async (c3, next) => {
|
|
80789
81253
|
const pathname = c3.req.path === "/" ? "/index.html" : c3.req.path;
|
|
80790
81254
|
try {
|
|
80791
|
-
const file2 = Bun.file(
|
|
81255
|
+
const file2 = Bun.file(join17(webDistPath, pathname));
|
|
80792
81256
|
if (await file2.exists()) {
|
|
80793
81257
|
const headers = new Headers({ "content-type": file2.type });
|
|
80794
81258
|
return new Response(file2.stream(), { headers });
|
|
@@ -80801,7 +81265,7 @@ function createApp(appRt, opts) {
|
|
|
80801
81265
|
return c3.json({ error: "Not Found" }, 404);
|
|
80802
81266
|
}
|
|
80803
81267
|
try {
|
|
80804
|
-
const indexFile = Bun.file(
|
|
81268
|
+
const indexFile = Bun.file(join17(webDistPath, "index.html"));
|
|
80805
81269
|
if (await indexFile.exists()) {
|
|
80806
81270
|
return new Response(indexFile.stream(), {
|
|
80807
81271
|
headers: { "content-type": "text/html; charset=utf-8" }
|
|
@@ -80822,7 +81286,7 @@ init_src3();
|
|
|
80822
81286
|
init_src();
|
|
80823
81287
|
init_src2();
|
|
80824
81288
|
init_dist5();
|
|
80825
|
-
import { dirname as dirname11, join as
|
|
81289
|
+
import { dirname as dirname11, join as join18 } from "path";
|
|
80826
81290
|
var NOOP_OUTPUT = { write: (_s) => {}, error: (_s) => {} };
|
|
80827
81291
|
|
|
80828
81292
|
class LazyPlanningEventEmitter {
|
|
@@ -80857,7 +81321,7 @@ class NotConfiguredError extends Error {
|
|
|
80857
81321
|
function createServerContext(appRt, options) {
|
|
80858
81322
|
const cwd = options.cwd;
|
|
80859
81323
|
const fs3 = options.fs;
|
|
80860
|
-
const dbUrl = options.dbUrl ??
|
|
81324
|
+
const dbUrl = options.dbUrl ?? join18(cwd, DEFAULT_DATABASE_URL);
|
|
80861
81325
|
const eventsBus = options.eventsBus ?? appRt.events;
|
|
80862
81326
|
const jobQueueEnabled = options.jobQueueEnabled ?? false;
|
|
80863
81327
|
const folders = options.folders ?? DEFAULT_PLANNING_FOLDERS;
|
|
@@ -80875,6 +81339,7 @@ function createServerContext(appRt, options) {
|
|
|
80875
81339
|
let teamSvc;
|
|
80876
81340
|
let supervisorSvc;
|
|
80877
81341
|
let processInventorySvc;
|
|
81342
|
+
let tokenLedgerSvc;
|
|
80878
81343
|
let agentSvc;
|
|
80879
81344
|
let ruleSvc;
|
|
80880
81345
|
let workflowSvc;
|
|
@@ -80965,6 +81430,12 @@ function createServerContext(appRt, options) {
|
|
|
80965
81430
|
}
|
|
80966
81431
|
return processInventorySvc;
|
|
80967
81432
|
},
|
|
81433
|
+
tokenLedger() {
|
|
81434
|
+
if (!tokenLedgerSvc) {
|
|
81435
|
+
tokenLedgerSvc = new TokenLedgerService({ cwd });
|
|
81436
|
+
}
|
|
81437
|
+
return tokenLedgerSvc;
|
|
81438
|
+
},
|
|
80968
81439
|
agentService() {
|
|
80969
81440
|
agentSvc ??= new AgentService({
|
|
80970
81441
|
cwd,
|
|
@@ -81144,13 +81615,15 @@ async function runTaskActionJob(ctx, env, payload, createAgentService = createTa
|
|
|
81144
81615
|
}
|
|
81145
81616
|
}
|
|
81146
81617
|
async function resolveWebDistPath(configuredPath) {
|
|
81147
|
-
const candidates = configuredPath && configuredPath.trim() !== "" ? [isAbsolute3(configuredPath) ? configuredPath :
|
|
81148
|
-
|
|
81149
|
-
|
|
81150
|
-
|
|
81618
|
+
const candidates = configuredPath && configuredPath.trim() !== "" ? [isAbsolute3(configuredPath) ? configuredPath : join19(process.cwd(), configuredPath)] : [
|
|
81619
|
+
join19(process.cwd(), "dist/web"),
|
|
81620
|
+
join19(import.meta.dir, "web"),
|
|
81621
|
+
join19(dirname12(process.execPath), "web"),
|
|
81622
|
+
join19(dirname12(process.execPath), "../web"),
|
|
81623
|
+
join19(import.meta.dir, "../../../dist/web")
|
|
81151
81624
|
];
|
|
81152
81625
|
for (const candidate of candidates) {
|
|
81153
|
-
if (await Bun.file(
|
|
81626
|
+
if (await Bun.file(join19(candidate, "index.html")).exists()) {
|
|
81154
81627
|
return candidate;
|
|
81155
81628
|
}
|
|
81156
81629
|
}
|
|
@@ -81172,12 +81645,16 @@ async function startServer(options, deps = defaultDeps) {
|
|
|
81172
81645
|
if (bootConfig.scheduler.enabled) {
|
|
81173
81646
|
scheduler3 = await deps.createScheduler();
|
|
81174
81647
|
}
|
|
81648
|
+
const webDistPath = await resolveWebDistPath(options.webDistPath);
|
|
81649
|
+
if (!webDistPath) {
|
|
81650
|
+
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).");
|
|
81651
|
+
}
|
|
81175
81652
|
const ctx = deps.createServerContext(appRt, {
|
|
81176
81653
|
cwd: process.cwd(),
|
|
81177
81654
|
fs: fs3,
|
|
81178
81655
|
dbUrl: options.dbUrl,
|
|
81179
81656
|
folders: await resolvePlanningFolders(fs3),
|
|
81180
|
-
webDistPath
|
|
81657
|
+
webDistPath,
|
|
81181
81658
|
jobQueueEnabled: bootConfig.jobqueue.enabled,
|
|
81182
81659
|
scheduler: scheduler3,
|
|
81183
81660
|
teamAutostart: bootConfig.teamAutostart,
|
|
@@ -81255,9 +81732,13 @@ async function startServer(options, deps = defaultDeps) {
|
|
|
81255
81732
|
process.on("SIGINT", () => void shutdown("SIGINT"));
|
|
81256
81733
|
process.on("SIGTERM", () => void shutdown("SIGTERM"));
|
|
81257
81734
|
const url2 = `http://${options.host}:${options.port}`;
|
|
81258
|
-
appRt.logger.info("Server started", {
|
|
81735
|
+
appRt.logger.info("Server started", {
|
|
81736
|
+
port: options.port,
|
|
81737
|
+
host: options.host,
|
|
81738
|
+
board: webDistPath ? `${url2}/board` : null
|
|
81739
|
+
});
|
|
81259
81740
|
if (options.openBrowser) {
|
|
81260
|
-
await deps.openUrl(`${url2}/board`);
|
|
81741
|
+
await deps.openUrl(webDistPath ? `${url2}/board` : `${url2}/api/health`);
|
|
81261
81742
|
}
|
|
81262
81743
|
if (options.keepAlive !== false) {
|
|
81263
81744
|
await new Promise(() => {});
|
|
@@ -81270,7 +81751,7 @@ if (false) {}
|
|
|
81270
81751
|
|
|
81271
81752
|
// src/commands/serve.ts
|
|
81272
81753
|
function resolveServeDbUrl(cwd, env, configuredUrl) {
|
|
81273
|
-
return env.DATABASE_URL === undefined ?
|
|
81754
|
+
return env.DATABASE_URL === undefined ? join20(cwd, DEFAULT_DATABASE_URL) : configuredUrl;
|
|
81274
81755
|
}
|
|
81275
81756
|
function registerServeCommand(program2, context4) {
|
|
81276
81757
|
program2.command("serve").summary("start the Spur web server (local fallback)").option("--port <n>", "Server port (env: PORT, default: 3000)", parseInt).option("--host <addr>", "Bind address (env: HOST, default: localhost)").option("--no-open", "Skip opening the browser").option("--cwd <path>", "Working directory", context4.cwd).option("--json", "Output { port, url, pid } and exit").action(async (options) => {
|
|
@@ -81309,7 +81790,7 @@ function registerServeCommand(program2, context4) {
|
|
|
81309
81790
|
}
|
|
81310
81791
|
|
|
81311
81792
|
// src/commands/status.ts
|
|
81312
|
-
import { join as
|
|
81793
|
+
import { join as join21 } from "path";
|
|
81313
81794
|
|
|
81314
81795
|
// src/errors.ts
|
|
81315
81796
|
class CommandError extends Error {
|
|
@@ -81380,8 +81861,8 @@ function registerStatusCommand(program2, context4) {
|
|
|
81380
81861
|
}
|
|
81381
81862
|
async function runStatusCore(path9, options, context4) {
|
|
81382
81863
|
const [packageJsonExists, spurConfigExists, git, agentSpecs] = await Promise.all([
|
|
81383
|
-
context4.fs.exists(
|
|
81384
|
-
context4.fs.exists(
|
|
81864
|
+
context4.fs.exists(join21(context4.cwd, "package.json")),
|
|
81865
|
+
context4.fs.exists(join21(context4.cwd, ".spur", "config.yaml")),
|
|
81385
81866
|
gitContext(context4.cwd),
|
|
81386
81867
|
listAgentSpecIds(context4)
|
|
81387
81868
|
]);
|
|
@@ -81409,14 +81890,14 @@ async function runStatusCore(path9, options, context4) {
|
|
|
81409
81890
|
return status.ok ? 0 : 1;
|
|
81410
81891
|
}
|
|
81411
81892
|
async function listAgentSpecIds(context4) {
|
|
81412
|
-
const dir =
|
|
81893
|
+
const dir = join21(context4.cwd, ".spur", "agents");
|
|
81413
81894
|
if (!await context4.fs.exists(dir))
|
|
81414
81895
|
return [];
|
|
81415
81896
|
const entries = await context4.fs.readDir(dir);
|
|
81416
81897
|
return entries.filter((entry) => entry.endsWith(".yaml") || entry.endsWith(".yml")).map((entry) => entry.replace(/\.ya?ml$/, "")).sort();
|
|
81417
81898
|
}
|
|
81418
81899
|
async function readTargetStatus(context4, targetPath) {
|
|
81419
|
-
const resolved =
|
|
81900
|
+
const resolved = join21(context4.cwd, targetPath);
|
|
81420
81901
|
const stat2 = await context4.fs.stat(resolved);
|
|
81421
81902
|
if (stat2 === null)
|
|
81422
81903
|
throw new CommandError(`status failed: path does not exist at ${resolved}`);
|
|
@@ -81427,8 +81908,8 @@ async function readTargetStatus(context4, targetPath) {
|
|
|
81427
81908
|
init_src3();
|
|
81428
81909
|
init_loader();
|
|
81429
81910
|
init_src2();
|
|
81430
|
-
import { existsSync as
|
|
81431
|
-
import { join as
|
|
81911
|
+
import { existsSync as existsSync9, readFileSync as readFileSync8 } from "fs";
|
|
81912
|
+
import { join as join22 } from "path";
|
|
81432
81913
|
// schemas/section-matrix.schema.json
|
|
81433
81914
|
var section_matrix_schema_default = {
|
|
81434
81915
|
$schema: "http://json-schema.org/draft-07/schema#",
|
|
@@ -82283,7 +82764,8 @@ async function makeService2(context4, folderOverride, noLifecycle = false) {
|
|
|
82283
82764
|
const lifecycle = noLifecycle ? undefined : makeLifecycleAdapter(context4, TASK_LIFECYCLE_PROFILE);
|
|
82284
82765
|
const writeService = new PlanningWriteService({
|
|
82285
82766
|
fs: context4.fs,
|
|
82286
|
-
...lifecycle ? { lifecycle } : {}
|
|
82767
|
+
...lifecycle ? { lifecycle } : {},
|
|
82768
|
+
emitter: makePlanningEmitter(context4)
|
|
82287
82769
|
});
|
|
82288
82770
|
return new TaskService({
|
|
82289
82771
|
fs: context4.fs,
|
|
@@ -82302,16 +82784,16 @@ function loadTemplateContent(projectRoot, variant) {
|
|
|
82302
82784
|
return templateContentCache.get(variant);
|
|
82303
82785
|
if (templateMissSet.has(variant))
|
|
82304
82786
|
return;
|
|
82305
|
-
const localPath =
|
|
82306
|
-
if (
|
|
82787
|
+
const localPath = join22(projectRoot, ".spur", "tasks", "templates", `${variant}.md`);
|
|
82788
|
+
if (existsSync9(localPath)) {
|
|
82307
82789
|
const content = readFileSync8(localPath, "utf8");
|
|
82308
82790
|
templateContentCache.set(variant, content);
|
|
82309
82791
|
return content;
|
|
82310
82792
|
}
|
|
82311
82793
|
const root = bundledConfigRoot();
|
|
82312
82794
|
if (root !== null) {
|
|
82313
|
-
const templatePath =
|
|
82314
|
-
if (
|
|
82795
|
+
const templatePath = join22(root, "templates", "task", `${variant}.md`);
|
|
82796
|
+
if (existsSync9(templatePath)) {
|
|
82315
82797
|
const content = readFileSync8(templatePath, "utf8");
|
|
82316
82798
|
templateContentCache.set(variant, content);
|
|
82317
82799
|
return content;
|
|
@@ -82326,14 +82808,14 @@ function loadTemplateBodies(projectRoot, variant) {
|
|
|
82326
82808
|
if (cached2 !== undefined)
|
|
82327
82809
|
return cached2;
|
|
82328
82810
|
let bodies = {};
|
|
82329
|
-
const localPath =
|
|
82330
|
-
if (
|
|
82811
|
+
const localPath = join22(projectRoot, ".spur", "tasks", "templates", `${variant}.md`);
|
|
82812
|
+
if (existsSync9(localPath)) {
|
|
82331
82813
|
bodies = extractTemplateBodies(readFileSync8(localPath, "utf8"));
|
|
82332
82814
|
} else {
|
|
82333
82815
|
const root = bundledConfigRoot();
|
|
82334
82816
|
if (root !== null) {
|
|
82335
|
-
const templatePath =
|
|
82336
|
-
if (
|
|
82817
|
+
const templatePath = join22(root, "templates", "task", `${variant}.md`);
|
|
82818
|
+
if (existsSync9(templatePath)) {
|
|
82337
82819
|
bodies = extractTemplateBodies(readFileSync8(templatePath, "utf8"));
|
|
82338
82820
|
}
|
|
82339
82821
|
}
|
|
@@ -82367,8 +82849,8 @@ async function loadSectionMatrix(projectRoot) {
|
|
|
82367
82849
|
return promise2;
|
|
82368
82850
|
}
|
|
82369
82851
|
async function loadSectionMatrixUncached(projectRoot) {
|
|
82370
|
-
const localPath =
|
|
82371
|
-
if (
|
|
82852
|
+
const localPath = join22(projectRoot, ".spur", "tasks", "section-matrix.yaml");
|
|
82853
|
+
if (existsSync9(localPath)) {
|
|
82372
82854
|
const data = await loadStructuredSpurConfig(localPath, {
|
|
82373
82855
|
validateJsonSchema: true,
|
|
82374
82856
|
embeddedSchemas: EMBEDDED_SPUR_SCHEMAS
|
|
@@ -82377,8 +82859,8 @@ async function loadSectionMatrixUncached(projectRoot) {
|
|
|
82377
82859
|
}
|
|
82378
82860
|
const root = bundledConfigRoot();
|
|
82379
82861
|
if (root !== null) {
|
|
82380
|
-
const matrixPath =
|
|
82381
|
-
if (
|
|
82862
|
+
const matrixPath = join22(root, "tasks", "section-matrix.yaml");
|
|
82863
|
+
if (existsSync9(matrixPath)) {
|
|
82382
82864
|
const data = await loadStructuredSpurConfig(matrixPath, {
|
|
82383
82865
|
validateJsonSchema: true,
|
|
82384
82866
|
embeddedSchemas: EMBEDDED_SPUR_SCHEMAS
|
|
@@ -82823,7 +83305,7 @@ init_src3();
|
|
|
82823
83305
|
init_src();
|
|
82824
83306
|
init_src2();
|
|
82825
83307
|
init_dist5();
|
|
82826
|
-
import { dirname as dirname13, join as
|
|
83308
|
+
import { dirname as dirname13, join as join23, resolve as resolve7 } from "path";
|
|
82827
83309
|
import { isatty as isatty4 } from "tty";
|
|
82828
83310
|
|
|
82829
83311
|
// ../../node_modules/.bun/@clack+core@1.4.1/node_modules/@clack/core/dist/index.mjs
|
|
@@ -84237,7 +84719,7 @@ function createCliContext(options) {
|
|
|
84237
84719
|
function noopSetExitCode(_code) {}
|
|
84238
84720
|
async function createMigratedDbAdapter(cwd = process.cwd(), env = process.env, dbUrl) {
|
|
84239
84721
|
const config4 = buildConfigFromEnv(env);
|
|
84240
|
-
const configuredUrl = env.DATABASE_URL === undefined ?
|
|
84722
|
+
const configuredUrl = env.DATABASE_URL === undefined ? join23(cwd, DEFAULT_DATABASE_URL) : config4.database.url;
|
|
84241
84723
|
const url2 = dbUrl ?? configuredUrl;
|
|
84242
84724
|
if (url2 !== IN_MEMORY_DATABASE_URL) {
|
|
84243
84725
|
await createNodeFileSystem3().ensureDir(dirname13(url2));
|