@kaddo/mcp 3.46.0 → 3.48.0
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/dist/index.js +508 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -5516,6 +5516,453 @@ function buildRoadmapQuality(dir) {
|
|
|
5516
5516
|
return { initiatives, work_item_candidates };
|
|
5517
5517
|
}
|
|
5518
5518
|
|
|
5519
|
+
// ../cli/src/core/scan-signals.ts
|
|
5520
|
+
function signalCount(signals) {
|
|
5521
|
+
return Object.values(signals).reduce((sum, arr) => sum + arr.length, 0);
|
|
5522
|
+
}
|
|
5523
|
+
function hasWarnings(signals) {
|
|
5524
|
+
return signals.tests.some((s) => s.label.includes("No test directory"));
|
|
5525
|
+
}
|
|
5526
|
+
function renderSignalsCompact(signals) {
|
|
5527
|
+
const lines = [];
|
|
5528
|
+
const CATEGORIES = [
|
|
5529
|
+
["auth", "Auth"],
|
|
5530
|
+
["payments", "Payments"],
|
|
5531
|
+
["webhooks", "Webhooks"],
|
|
5532
|
+
["storage", "Storage"],
|
|
5533
|
+
["background_jobs", "Background jobs"],
|
|
5534
|
+
["email", "Email"],
|
|
5535
|
+
["database", "Database"],
|
|
5536
|
+
["migrations", "Migrations"],
|
|
5537
|
+
["api_routes", "API routes"],
|
|
5538
|
+
["tests", "Tests"],
|
|
5539
|
+
["security", "Security"],
|
|
5540
|
+
["infrastructure", "Infrastructure"],
|
|
5541
|
+
["external_integrations", "External integrations"],
|
|
5542
|
+
["environment", "Environment"]
|
|
5543
|
+
];
|
|
5544
|
+
for (const [key, label] of CATEGORIES) {
|
|
5545
|
+
const arr = signals[key];
|
|
5546
|
+
if (arr.length === 0) continue;
|
|
5547
|
+
if (arr.length === 1) {
|
|
5548
|
+
lines.push(`- ${label}: ${arr[0].label}`);
|
|
5549
|
+
} else {
|
|
5550
|
+
lines.push(`- ${label}: ${arr.length}`);
|
|
5551
|
+
}
|
|
5552
|
+
}
|
|
5553
|
+
return lines.length > 0 ? lines.join("\n") + "\n" : "No signals detected.\n";
|
|
5554
|
+
}
|
|
5555
|
+
|
|
5556
|
+
// ../cli/src/core/project-route.ts
|
|
5557
|
+
function isUseful(q) {
|
|
5558
|
+
return q === "useful";
|
|
5559
|
+
}
|
|
5560
|
+
var enableKaddo = {
|
|
5561
|
+
id: "enable-kaddo",
|
|
5562
|
+
label: "Enable Kaddo",
|
|
5563
|
+
evaluate: (ctx) => ({
|
|
5564
|
+
status: ctx.hasConfig ? "done" : "current",
|
|
5565
|
+
evidence: ctx.hasConfig ? [".kaddo/config.yml"] : void 0,
|
|
5566
|
+
command: ctx.hasConfig ? void 0 : "kaddo init"
|
|
5567
|
+
})
|
|
5568
|
+
};
|
|
5569
|
+
var scanRepository = {
|
|
5570
|
+
id: "scan-repository",
|
|
5571
|
+
label: "Scan repository",
|
|
5572
|
+
evaluate: (ctx) => {
|
|
5573
|
+
if (!ctx.hasScan) return { status: "pending", command: "kaddo scan" };
|
|
5574
|
+
if (ctx.hasScanWarnings) return { status: "warning", evidence: [".kaddo/scan.json"], reason: "Scan has warnings (e.g. no test directory detected).", command: "kaddo scan" };
|
|
5575
|
+
return { status: "done", evidence: [".kaddo/scan.json"] };
|
|
5576
|
+
}
|
|
5577
|
+
};
|
|
5578
|
+
var defineBusiness = {
|
|
5579
|
+
id: "define-business",
|
|
5580
|
+
label: "Define business context",
|
|
5581
|
+
evaluate: (ctx) => ({
|
|
5582
|
+
status: isUseful(ctx.qBusiness) ? "done" : ctx.qBusiness === "missing" ? "pending" : "warning",
|
|
5583
|
+
evidence: isUseful(ctx.qBusiness) ? ["knowledge/business/business.md"] : void 0,
|
|
5584
|
+
reason: ctx.qBusiness === "placeholder" ? "Business context is still a bootstrap placeholder." : void 0,
|
|
5585
|
+
agent: isUseful(ctx.qBusiness) ? void 0 : "business-agent"
|
|
5586
|
+
})
|
|
5587
|
+
};
|
|
5588
|
+
var defineProduct = {
|
|
5589
|
+
id: "define-product",
|
|
5590
|
+
label: "Define product context",
|
|
5591
|
+
evaluate: (ctx) => ({
|
|
5592
|
+
status: isUseful(ctx.qProduct) ? "done" : ctx.qProduct === "missing" ? "pending" : "warning",
|
|
5593
|
+
evidence: isUseful(ctx.qProduct) ? ["knowledge/product/product.md"] : void 0,
|
|
5594
|
+
agent: isUseful(ctx.qProduct) ? void 0 : "capability-agent"
|
|
5595
|
+
})
|
|
5596
|
+
};
|
|
5597
|
+
var discoverCapabilities = {
|
|
5598
|
+
id: "discover-capabilities",
|
|
5599
|
+
label: "Discover capabilities",
|
|
5600
|
+
evaluate: (ctx) => ({
|
|
5601
|
+
status: isUseful(ctx.qCapabilities) ? "done" : ctx.qCapabilities === "missing" ? "pending" : "warning",
|
|
5602
|
+
evidence: isUseful(ctx.qCapabilities) ? ["knowledge/product/capabilities.md"] : void 0,
|
|
5603
|
+
agent: isUseful(ctx.qCapabilities) ? void 0 : "capability-agent"
|
|
5604
|
+
})
|
|
5605
|
+
};
|
|
5606
|
+
var describeArchitecture = {
|
|
5607
|
+
id: "describe-architecture",
|
|
5608
|
+
label: "Describe current architecture",
|
|
5609
|
+
evaluate: (ctx) => {
|
|
5610
|
+
const done = isUseful(ctx.qCurrentState) && isUseful(ctx.qCodebase);
|
|
5611
|
+
const evidence = [];
|
|
5612
|
+
if (isUseful(ctx.qCurrentState)) evidence.push("knowledge/tech/current-state.md");
|
|
5613
|
+
if (isUseful(ctx.qCodebase)) evidence.push("knowledge/tech/codebase.md");
|
|
5614
|
+
return {
|
|
5615
|
+
status: done ? "done" : "pending",
|
|
5616
|
+
evidence: evidence.length > 0 ? evidence : void 0,
|
|
5617
|
+
agent: done ? void 0 : "architecture-agent"
|
|
5618
|
+
};
|
|
5619
|
+
}
|
|
5620
|
+
};
|
|
5621
|
+
var captureTechDecisions = {
|
|
5622
|
+
id: "capture-technical-decisions",
|
|
5623
|
+
label: "Capture technical decisions",
|
|
5624
|
+
evaluate: (ctx) => {
|
|
5625
|
+
if (ctx.decisionCandidates === 0 && ctx.totalAdrs === 0) {
|
|
5626
|
+
return { status: "optional", reason: "No decision candidates found." };
|
|
5627
|
+
}
|
|
5628
|
+
if (ctx.totalAdrs > 0) {
|
|
5629
|
+
return { status: "done", evidence: ["knowledge/tech/decisions/"], reason: `${ctx.totalAdrs} ADR(s) exist.` };
|
|
5630
|
+
}
|
|
5631
|
+
return {
|
|
5632
|
+
status: "warning",
|
|
5633
|
+
reason: `${ctx.decisionCandidates} decision candidate(s) exist but no ADRs have been materialized.`,
|
|
5634
|
+
command: "kaddo adr",
|
|
5635
|
+
skill: "adr-writing"
|
|
5636
|
+
};
|
|
5637
|
+
}
|
|
5638
|
+
};
|
|
5639
|
+
var createWorkSource = {
|
|
5640
|
+
id: "create-work-source",
|
|
5641
|
+
label: "Create or connect work source",
|
|
5642
|
+
evaluate: (ctx) => ({
|
|
5643
|
+
status: ctx.hasRoadmap || ctx.totalWorkItems > 0 ? "done" : "pending",
|
|
5644
|
+
evidence: ctx.hasRoadmap ? ["knowledge/delivery/roadmap.md"] : void 0,
|
|
5645
|
+
command: ctx.hasRoadmap ? void 0 : "kaddo roadmap",
|
|
5646
|
+
agent: ctx.hasRoadmap ? void 0 : "roadmap-agent"
|
|
5647
|
+
})
|
|
5648
|
+
};
|
|
5649
|
+
var materializeWorkItem = {
|
|
5650
|
+
id: "materialize-work-item",
|
|
5651
|
+
label: "Materialize first Work Item",
|
|
5652
|
+
evaluate: (ctx) => {
|
|
5653
|
+
if (ctx.totalWorkItems > 0) {
|
|
5654
|
+
return { status: "done", evidence: ["knowledge/delivery/work-items/"] };
|
|
5655
|
+
}
|
|
5656
|
+
if (ctx.roadmapCandidates > 0) {
|
|
5657
|
+
return { status: "current", command: "kaddo create --from roadmap", reason: "Roadmap has candidates but no Work Item exists." };
|
|
5658
|
+
}
|
|
5659
|
+
return { status: "pending" };
|
|
5660
|
+
}
|
|
5661
|
+
};
|
|
5662
|
+
var refineWorkItem = {
|
|
5663
|
+
id: "refine-work-item",
|
|
5664
|
+
label: "Refine Work Item",
|
|
5665
|
+
evaluate: (ctx) => {
|
|
5666
|
+
if (ctx.readyWorkItems > 0 || ctx.inProgressWorkItems > 0) return { status: "done" };
|
|
5667
|
+
if (ctx.draftWorkItems > 0) {
|
|
5668
|
+
return {
|
|
5669
|
+
status: "current",
|
|
5670
|
+
reason: `There ${ctx.draftWorkItems === 1 ? "is" : "are"} ${ctx.draftWorkItems} draft Work Item${ctx.draftWorkItems === 1 ? "" : "s"} and no Work Item is ready.`,
|
|
5671
|
+
agent: "work-item-agent",
|
|
5672
|
+
skill: "work-item-refinement"
|
|
5673
|
+
};
|
|
5674
|
+
}
|
|
5675
|
+
return { status: "pending" };
|
|
5676
|
+
}
|
|
5677
|
+
};
|
|
5678
|
+
var suggestOwnership = {
|
|
5679
|
+
id: "suggest-ownership",
|
|
5680
|
+
label: "Suggest ownership",
|
|
5681
|
+
evaluate: (ctx) => {
|
|
5682
|
+
if (ctx.totalWorkItems === 0) return { status: "pending" };
|
|
5683
|
+
if (ctx.ownershipComplete) return { status: "done" };
|
|
5684
|
+
return {
|
|
5685
|
+
status: "next",
|
|
5686
|
+
reason: `Ownership coverage is ${ctx.ownershipCoverage}.`,
|
|
5687
|
+
command: "kaddo owners suggest"
|
|
5688
|
+
};
|
|
5689
|
+
}
|
|
5690
|
+
};
|
|
5691
|
+
var resolveAdrs = {
|
|
5692
|
+
id: "resolve-adrs",
|
|
5693
|
+
label: "Resolve ADRs if needed",
|
|
5694
|
+
evaluate: (ctx) => {
|
|
5695
|
+
if (ctx.decisionCandidates === 0 && ctx.totalAdrs === 0) return { status: "optional" };
|
|
5696
|
+
if (ctx.totalAdrs > 0) return { status: "done" };
|
|
5697
|
+
return {
|
|
5698
|
+
status: "warning",
|
|
5699
|
+
reason: `${ctx.decisionCandidates} decision candidate(s) without ADRs.`,
|
|
5700
|
+
command: "kaddo adr",
|
|
5701
|
+
skill: "adr-writing"
|
|
5702
|
+
};
|
|
5703
|
+
}
|
|
5704
|
+
};
|
|
5705
|
+
var prepareImplementation = {
|
|
5706
|
+
id: "prepare-implementation",
|
|
5707
|
+
label: "Prepare implementation",
|
|
5708
|
+
evaluate: (ctx) => {
|
|
5709
|
+
if (ctx.inProgressWorkItems > 0 || ctx.completedWorkItems > 0) return { status: "done" };
|
|
5710
|
+
if (ctx.readyWorkItems > 0) {
|
|
5711
|
+
if (ctx.adaptersInstalled === 0) {
|
|
5712
|
+
return { status: "current", reason: "Ready Work Items exist but no adapter is installed.", command: "kaddo adapters list" };
|
|
5713
|
+
}
|
|
5714
|
+
return { status: "current", agent: "implementation-agent" };
|
|
5715
|
+
}
|
|
5716
|
+
return { status: "pending" };
|
|
5717
|
+
}
|
|
5718
|
+
};
|
|
5719
|
+
var runGuard = {
|
|
5720
|
+
id: "run-guard",
|
|
5721
|
+
label: "Run guard",
|
|
5722
|
+
evaluate: (ctx) => {
|
|
5723
|
+
if (ctx.hasGuardHistory) return { status: "done", evidence: [".kaddo/history/guard-runs.jsonl"] };
|
|
5724
|
+
if (ctx.inProgressWorkItems > 0) return { status: "current", command: "kaddo guard" };
|
|
5725
|
+
return { status: "pending" };
|
|
5726
|
+
}
|
|
5727
|
+
};
|
|
5728
|
+
var captureLearning = {
|
|
5729
|
+
id: "capture-learning",
|
|
5730
|
+
label: "Capture learning",
|
|
5731
|
+
evaluate: (ctx) => {
|
|
5732
|
+
if (ctx.completedWorkItems > 0) return { status: "done" };
|
|
5733
|
+
if (ctx.totalWorkItems === 0) return { status: "optional", reason: "Project is still in early discovery." };
|
|
5734
|
+
return { status: "pending" };
|
|
5735
|
+
}
|
|
5736
|
+
};
|
|
5737
|
+
var identifyLegacyModules = {
|
|
5738
|
+
id: "identify-legacy-modules",
|
|
5739
|
+
label: "Identify legacy modules",
|
|
5740
|
+
evaluate: (ctx) => {
|
|
5741
|
+
const hasLegacy = exists(join(ctx.dir, "knowledge/legacy/risks.md"));
|
|
5742
|
+
return {
|
|
5743
|
+
status: hasLegacy ? "done" : "pending",
|
|
5744
|
+
evidence: hasLegacy ? ["knowledge/legacy/risks.md"] : void 0,
|
|
5745
|
+
agent: hasLegacy ? void 0 : "legacy-agent"
|
|
5746
|
+
};
|
|
5747
|
+
}
|
|
5748
|
+
};
|
|
5749
|
+
var identifyRisks = {
|
|
5750
|
+
id: "identify-risks",
|
|
5751
|
+
label: "Identify operational risks",
|
|
5752
|
+
evaluate: (ctx) => {
|
|
5753
|
+
const hasLegacy = exists(join(ctx.dir, "knowledge/legacy/risks.md"));
|
|
5754
|
+
return { status: hasLegacy ? "done" : "pending", agent: hasLegacy ? void 0 : "legacy-agent" };
|
|
5755
|
+
}
|
|
5756
|
+
};
|
|
5757
|
+
var NEW_STEPS = [
|
|
5758
|
+
enableKaddo,
|
|
5759
|
+
defineBusiness,
|
|
5760
|
+
defineProduct,
|
|
5761
|
+
{ ...discoverCapabilities, label: "Define initial capabilities" },
|
|
5762
|
+
{ ...describeArchitecture, label: "Define initial architecture" },
|
|
5763
|
+
{ ...createWorkSource, label: "Create initial work source" },
|
|
5764
|
+
{ ...materializeWorkItem, label: "Create first Work Item" },
|
|
5765
|
+
refineWorkItem,
|
|
5766
|
+
suggestOwnership,
|
|
5767
|
+
prepareImplementation,
|
|
5768
|
+
runGuard,
|
|
5769
|
+
captureLearning
|
|
5770
|
+
];
|
|
5771
|
+
var PRE_AI_STEPS = [
|
|
5772
|
+
enableKaddo,
|
|
5773
|
+
scanRepository,
|
|
5774
|
+
defineBusiness,
|
|
5775
|
+
defineProduct,
|
|
5776
|
+
discoverCapabilities,
|
|
5777
|
+
describeArchitecture,
|
|
5778
|
+
captureTechDecisions,
|
|
5779
|
+
createWorkSource,
|
|
5780
|
+
materializeWorkItem,
|
|
5781
|
+
refineWorkItem,
|
|
5782
|
+
suggestOwnership,
|
|
5783
|
+
resolveAdrs,
|
|
5784
|
+
prepareImplementation,
|
|
5785
|
+
runGuard,
|
|
5786
|
+
captureLearning
|
|
5787
|
+
];
|
|
5788
|
+
var LEGACY_STEPS = [
|
|
5789
|
+
enableKaddo,
|
|
5790
|
+
scanRepository,
|
|
5791
|
+
identifyLegacyModules,
|
|
5792
|
+
{ ...discoverCapabilities, label: "Discover critical capabilities" },
|
|
5793
|
+
describeArchitecture,
|
|
5794
|
+
identifyRisks,
|
|
5795
|
+
captureTechDecisions,
|
|
5796
|
+
{ ...createWorkSource, label: "Create modernization candidates" },
|
|
5797
|
+
{ ...materializeWorkItem, label: "Materialize safe Work Item" },
|
|
5798
|
+
refineWorkItem,
|
|
5799
|
+
suggestOwnership,
|
|
5800
|
+
resolveAdrs,
|
|
5801
|
+
{ ...prepareImplementation, label: "Prepare safe implementation" },
|
|
5802
|
+
runGuard,
|
|
5803
|
+
captureLearning
|
|
5804
|
+
];
|
|
5805
|
+
function stepsForState(state) {
|
|
5806
|
+
switch (state) {
|
|
5807
|
+
case "new":
|
|
5808
|
+
return NEW_STEPS;
|
|
5809
|
+
case "legacy":
|
|
5810
|
+
return LEGACY_STEPS;
|
|
5811
|
+
case "pre-ai":
|
|
5812
|
+
default:
|
|
5813
|
+
return PRE_AI_STEPS;
|
|
5814
|
+
}
|
|
5815
|
+
}
|
|
5816
|
+
function buildRouteContext(dir) {
|
|
5817
|
+
const config = loadConfig(dir);
|
|
5818
|
+
const hasScan = exists(join(dir, ".kaddo", "scan.json"));
|
|
5819
|
+
const hasInventory = exists(join(dir, "knowledge", "inventory.md"));
|
|
5820
|
+
const qa = (rel) => analyzeKnowledgeArtifact(dir, rel);
|
|
5821
|
+
const wis = discoverWorkItems(dir);
|
|
5822
|
+
const td = buildTechDecisions(dir);
|
|
5823
|
+
const roadmapPath = join(dir, "knowledge/delivery/roadmap.md");
|
|
5824
|
+
const hasRoadmap = exists(roadmapPath);
|
|
5825
|
+
let roadmapMd = null;
|
|
5826
|
+
if (hasRoadmap) {
|
|
5827
|
+
try {
|
|
5828
|
+
roadmapMd = readFile(roadmapPath);
|
|
5829
|
+
} catch {
|
|
5830
|
+
}
|
|
5831
|
+
}
|
|
5832
|
+
const stats = roadmapStats(roadmapMd, wis.length);
|
|
5833
|
+
const byState = (s) => wis.filter((w) => w.lifecycle === s).length;
|
|
5834
|
+
const total = wis.length;
|
|
5835
|
+
const withOwnership = wis.filter((w) => w.codeGlobs.length > 0).length;
|
|
5836
|
+
const adapters = installedAdapters(dir);
|
|
5837
|
+
const nextStep = resolveNextStep(dir);
|
|
5838
|
+
return {
|
|
5839
|
+
dir,
|
|
5840
|
+
hasConfig: config !== null,
|
|
5841
|
+
hasScan,
|
|
5842
|
+
hasInventory,
|
|
5843
|
+
qBusiness: qa("knowledge/business/business.md"),
|
|
5844
|
+
qProduct: qa("knowledge/product/product.md"),
|
|
5845
|
+
qCapabilities: qa("knowledge/product/capabilities.md"),
|
|
5846
|
+
qCurrentState: qa("knowledge/tech/current-state.md"),
|
|
5847
|
+
qCodebase: qa("knowledge/tech/codebase.md"),
|
|
5848
|
+
hasRoadmap,
|
|
5849
|
+
roadmapCandidates: stats.work_item_candidates,
|
|
5850
|
+
totalWorkItems: total,
|
|
5851
|
+
draftWorkItems: byState("draft"),
|
|
5852
|
+
readyWorkItems: byState("ready"),
|
|
5853
|
+
inProgressWorkItems: byState("in-progress"),
|
|
5854
|
+
completedWorkItems: byState("completed"),
|
|
5855
|
+
ownershipCoverage: `${withOwnership}/${total}`,
|
|
5856
|
+
ownershipComplete: total > 0 && withOwnership >= total,
|
|
5857
|
+
decisionCandidates: td.candidates,
|
|
5858
|
+
acceptedAdrs: td.accepted_adrs,
|
|
5859
|
+
draftAdrs: td.draft_adrs,
|
|
5860
|
+
totalAdrs: td.adrs,
|
|
5861
|
+
adaptersInstalled: adapters.length,
|
|
5862
|
+
hasGuardHistory: exists(join(dir, ".kaddo", "history", "guard-runs.jsonl")),
|
|
5863
|
+
hasScanWarnings: hasScan ? loadScanWarnings(dir) : false,
|
|
5864
|
+
nextStepId: mapNextStepId(nextStep.id)
|
|
5865
|
+
};
|
|
5866
|
+
}
|
|
5867
|
+
function loadScanWarnings(dir) {
|
|
5868
|
+
try {
|
|
5869
|
+
const parsed = JSON.parse(readFile(join(dir, ".kaddo", "scan.json")));
|
|
5870
|
+
return parsed.signals ? hasWarnings(parsed.signals) : false;
|
|
5871
|
+
} catch {
|
|
5872
|
+
return false;
|
|
5873
|
+
}
|
|
5874
|
+
}
|
|
5875
|
+
function mapNextStepId(id) {
|
|
5876
|
+
const MAP = {
|
|
5877
|
+
init: "enable-kaddo",
|
|
5878
|
+
bootstrap: "define-business",
|
|
5879
|
+
"add-agents": "enable-kaddo",
|
|
5880
|
+
"add-skills": "enable-kaddo",
|
|
5881
|
+
scan: "scan-repository",
|
|
5882
|
+
context: "scan-repository",
|
|
5883
|
+
understand: "scan-repository"
|
|
5884
|
+
};
|
|
5885
|
+
return MAP[id] ?? id;
|
|
5886
|
+
}
|
|
5887
|
+
function buildProjectRoute(dir) {
|
|
5888
|
+
const config = loadConfig(dir);
|
|
5889
|
+
const state = config?.project.state ?? "pre-ai";
|
|
5890
|
+
const defs = stepsForState(state);
|
|
5891
|
+
const ctx = buildRouteContext(dir);
|
|
5892
|
+
const steps = defs.map((d) => {
|
|
5893
|
+
const result = d.evaluate(ctx);
|
|
5894
|
+
return { id: d.id, label: d.label, ...result };
|
|
5895
|
+
});
|
|
5896
|
+
for (const s of steps) {
|
|
5897
|
+
if (s.id === ctx.nextStepId && s.status !== "done") {
|
|
5898
|
+
s.status = "current";
|
|
5899
|
+
}
|
|
5900
|
+
}
|
|
5901
|
+
let seenCurrent = false;
|
|
5902
|
+
for (const s of steps) {
|
|
5903
|
+
if (s.status === "current") seenCurrent = true;
|
|
5904
|
+
if (seenCurrent && s.status === "pending") {
|
|
5905
|
+
s.status = "next";
|
|
5906
|
+
break;
|
|
5907
|
+
}
|
|
5908
|
+
}
|
|
5909
|
+
const completed = steps.filter((s) => s.status === "done").length;
|
|
5910
|
+
const total = steps.length;
|
|
5911
|
+
const progressPercent = total > 0 ? Math.round(completed / total * 100) : 0;
|
|
5912
|
+
return {
|
|
5913
|
+
type: state,
|
|
5914
|
+
currentStep: steps.find((s) => s.status === "current")?.id ?? steps.find((s) => s.status !== "done")?.id ?? "complete",
|
|
5915
|
+
completed,
|
|
5916
|
+
total,
|
|
5917
|
+
progressPercent,
|
|
5918
|
+
steps
|
|
5919
|
+
};
|
|
5920
|
+
}
|
|
5921
|
+
var STATUS_MARKER = {
|
|
5922
|
+
done: "[x]",
|
|
5923
|
+
current: "[>]",
|
|
5924
|
+
next: "[ ]",
|
|
5925
|
+
pending: "[ ]",
|
|
5926
|
+
optional: "[o]",
|
|
5927
|
+
blocked: "[!]",
|
|
5928
|
+
warning: "[~]",
|
|
5929
|
+
skipped: "[-]"
|
|
5930
|
+
};
|
|
5931
|
+
function renderRouteMarkdown(route) {
|
|
5932
|
+
const lines = [];
|
|
5933
|
+
lines.push("## Project Route\n");
|
|
5934
|
+
lines.push(`Route: ${route.type}`);
|
|
5935
|
+
lines.push(`Progress: ${route.completed}/${route.total}
|
|
5936
|
+
`);
|
|
5937
|
+
for (const s of route.steps) {
|
|
5938
|
+
lines.push(`- ${STATUS_MARKER[s.status]} ${s.label}`);
|
|
5939
|
+
}
|
|
5940
|
+
lines.push("");
|
|
5941
|
+
return lines.join("\n");
|
|
5942
|
+
}
|
|
5943
|
+
function renderRouteCompact(route) {
|
|
5944
|
+
const lines = [];
|
|
5945
|
+
lines.push(`Route: ${route.type} \xB7 Progress: ${route.completed}/${route.total}
|
|
5946
|
+
`);
|
|
5947
|
+
const current = route.steps.find((s) => s.status === "current");
|
|
5948
|
+
if (current) {
|
|
5949
|
+
const agent = current.agent ? ` \u2014 ${current.agent}` : "";
|
|
5950
|
+
const skill2 = current.skill ? ` / ${current.skill}` : "";
|
|
5951
|
+
lines.push(`Current:
|
|
5952
|
+
- ${current.label}${agent}${skill2}
|
|
5953
|
+
`);
|
|
5954
|
+
}
|
|
5955
|
+
const warnings = route.steps.filter((s) => s.status === "warning");
|
|
5956
|
+
if (warnings.length > 0) {
|
|
5957
|
+
lines.push("Warnings:");
|
|
5958
|
+
for (const w of warnings) {
|
|
5959
|
+
lines.push(`- ${w.label}${w.reason ? ` \u2014 ${w.reason}` : ""}`);
|
|
5960
|
+
}
|
|
5961
|
+
lines.push("");
|
|
5962
|
+
}
|
|
5963
|
+
return lines.join("\n");
|
|
5964
|
+
}
|
|
5965
|
+
|
|
5519
5966
|
// ../cli/src/core/project-explain.ts
|
|
5520
5967
|
var ARCH_DIR2 = "knowledge";
|
|
5521
5968
|
function normalizeTitle(t) {
|
|
@@ -5571,6 +6018,16 @@ function loadScan(dir) {
|
|
|
5571
6018
|
return null;
|
|
5572
6019
|
}
|
|
5573
6020
|
}
|
|
6021
|
+
function loadScanSignals(dir) {
|
|
6022
|
+
const scanPath = join(dir, ".kaddo", "scan.json");
|
|
6023
|
+
if (!exists(scanPath)) return null;
|
|
6024
|
+
try {
|
|
6025
|
+
const parsed = JSON.parse(readFile(scanPath));
|
|
6026
|
+
return parsed.signals ?? null;
|
|
6027
|
+
} catch {
|
|
6028
|
+
return null;
|
|
6029
|
+
}
|
|
6030
|
+
}
|
|
5574
6031
|
function hasAgents(dir) {
|
|
5575
6032
|
const agentsDir = join(dir, ARCH_DIR2, "agents");
|
|
5576
6033
|
if (!exists(agentsDir)) return false;
|
|
@@ -5741,7 +6198,9 @@ function buildProjectExplanation(dir) {
|
|
|
5741
6198
|
}
|
|
5742
6199
|
},
|
|
5743
6200
|
installedAssets: installedAssetsSummary(dir),
|
|
5744
|
-
roadmapQuality: buildRoadmapQuality(dir)
|
|
6201
|
+
roadmapQuality: buildRoadmapQuality(dir),
|
|
6202
|
+
projectRoute: buildProjectRoute(dir),
|
|
6203
|
+
scanSignals: loadScanSignals(dir)
|
|
5745
6204
|
};
|
|
5746
6205
|
}
|
|
5747
6206
|
function stateLabel(state) {
|
|
@@ -5786,6 +6245,10 @@ function renderExplanationHuman(exp) {
|
|
|
5786
6245
|
lines.push(`- Infrastructure: ${exp.stack.infrastructureFiles.join(", ")}`);
|
|
5787
6246
|
lines.push("");
|
|
5788
6247
|
}
|
|
6248
|
+
if (exp.scanSignals && signalCount(exp.scanSignals) > 0) {
|
|
6249
|
+
lines.push("## Scan Signals");
|
|
6250
|
+
lines.push(renderSignalsCompact(exp.scanSignals));
|
|
6251
|
+
}
|
|
5789
6252
|
const ls = (name) => exp.layers.find((l) => l.layer === name)?.status ?? "Missing";
|
|
5790
6253
|
lines.push("## Knowledge Status");
|
|
5791
6254
|
lines.push(`- Inventory: ${exp.knowledge.hasInventory ? "available" : "missing"}`);
|
|
@@ -5916,6 +6379,7 @@ function renderExplanationHuman(exp) {
|
|
|
5916
6379
|
lines.push("Review before continuing (non-blocking).");
|
|
5917
6380
|
lines.push("");
|
|
5918
6381
|
}
|
|
6382
|
+
lines.push(renderRouteMarkdown(exp.projectRoute));
|
|
5919
6383
|
const assessment = assessPhase(exp);
|
|
5920
6384
|
lines.push("## Phase");
|
|
5921
6385
|
lines.push(`- Phase: ${assessment.phase}`);
|
|
@@ -7284,6 +7748,37 @@ var RESOURCES = [
|
|
|
7284
7748
|
const deliveryState = { ...buildDeliveryState(root), phase: nextStepRecommendation.phase };
|
|
7285
7749
|
return [{ uri: "kaddo://next-step", text: JSON.stringify({ nextStepRecommendation, deliveryState }, null, 2), mimeType: "application/json" }];
|
|
7286
7750
|
}
|
|
7751
|
+
},
|
|
7752
|
+
{
|
|
7753
|
+
uri: "kaddo://project-route",
|
|
7754
|
+
name: "Kaddo project route",
|
|
7755
|
+
description: "Project route progress map \u2014 where the project sits in its lifecycle (new/pre-ai/legacy), completed steps, current step, warnings (VS-080). Read-only.",
|
|
7756
|
+
mimeType: "application/json",
|
|
7757
|
+
read: (root) => {
|
|
7758
|
+
if (!hasKnowledge(root)) {
|
|
7759
|
+
return text("kaddo://project-route", "Knowledge repository not found. Run `kaddo bootstrap` first.", "text/plain");
|
|
7760
|
+
}
|
|
7761
|
+
return [{ uri: "kaddo://project-route", text: JSON.stringify(buildProjectRoute(root), null, 2), mimeType: "application/json" }];
|
|
7762
|
+
}
|
|
7763
|
+
},
|
|
7764
|
+
{
|
|
7765
|
+
uri: "kaddo://scan-signals",
|
|
7766
|
+
name: "Kaddo scan signals",
|
|
7767
|
+
description: "Actionable signals detected by `kaddo scan`: auth, payments, webhooks, storage, background jobs, email, database, migrations, API routes, tests, security, infrastructure, integrations, environment (VS-081). Read-only.",
|
|
7768
|
+
mimeType: "application/json",
|
|
7769
|
+
read: (root) => {
|
|
7770
|
+
const body = readText(root, ".kaddo/scan.json");
|
|
7771
|
+
if (body) {
|
|
7772
|
+
try {
|
|
7773
|
+
const parsed = JSON.parse(body);
|
|
7774
|
+
if (parsed.signals) {
|
|
7775
|
+
return [{ uri: "kaddo://scan-signals", text: JSON.stringify(parsed.signals, null, 2), mimeType: "application/json" }];
|
|
7776
|
+
}
|
|
7777
|
+
} catch {
|
|
7778
|
+
}
|
|
7779
|
+
}
|
|
7780
|
+
return text("kaddo://scan-signals", "Scan signals not found. Run `kaddo scan` first.", "text/plain");
|
|
7781
|
+
}
|
|
7287
7782
|
}
|
|
7288
7783
|
];
|
|
7289
7784
|
|
|
@@ -7625,6 +8120,8 @@ function buildContextPack(dir, config, now = /* @__PURE__ */ new Date()) {
|
|
|
7625
8120
|
graph: loadGraphSummary(dir),
|
|
7626
8121
|
graphHints: loadGraphHints(dir),
|
|
7627
8122
|
skills: discoverInstalledSkills(dir).map((s) => s.id),
|
|
8123
|
+
scanSignals: scanJson?.signals ?? null,
|
|
8124
|
+
projectRoute: buildProjectRoute(dir),
|
|
7628
8125
|
mappedModules,
|
|
7629
8126
|
missing,
|
|
7630
8127
|
// VS-052/VS-073.2: the handoff is driven by the unified next step, so the pack never contradicts
|
|
@@ -7701,6 +8198,8 @@ function renderContextPack(pack) {
|
|
|
7701
8198
|
parts.push(rec.secondary.map((s) => `- ${s.label}`).join("\n") + "\n");
|
|
7702
8199
|
}
|
|
7703
8200
|
}
|
|
8201
|
+
parts.push("## Project Route\n");
|
|
8202
|
+
parts.push(renderRouteCompact(pack.projectRoute));
|
|
7704
8203
|
parts.push("## Knowledge Layers\n");
|
|
7705
8204
|
parts.push(
|
|
7706
8205
|
"Project knowledge is organized in four layers: **Business \u2192 Product \u2192 Tech \u2192 Delivery**.\n"
|
|
@@ -7736,6 +8235,10 @@ function renderContextPack(pack) {
|
|
|
7736
8235
|
} else {
|
|
7737
8236
|
parts.push("Scan baseline missing. Run `kaddo scan` for better context.\n");
|
|
7738
8237
|
}
|
|
8238
|
+
if (pack.scanSignals && signalCount(pack.scanSignals) > 0) {
|
|
8239
|
+
parts.push("## Scan Signals\n");
|
|
8240
|
+
parts.push(renderSignalsCompact(pack.scanSignals));
|
|
8241
|
+
}
|
|
7739
8242
|
parts.push("## Current Knowledge\n");
|
|
7740
8243
|
parts.push((knowledge.summary || "No project knowledge summary found yet.") + "\n");
|
|
7741
8244
|
parts.push("## Roadmap Status\n");
|
|
@@ -8008,6 +8511,10 @@ function renderUnderstand(plan) {
|
|
|
8008
8511
|
].join("\n") + "\n"
|
|
8009
8512
|
);
|
|
8010
8513
|
}
|
|
8514
|
+
if (plan.projectRoute) {
|
|
8515
|
+
parts.push("## Project Route\n");
|
|
8516
|
+
parts.push(renderRouteCompact(plan.projectRoute));
|
|
8517
|
+
}
|
|
8011
8518
|
if (steps.length > 0) {
|
|
8012
8519
|
parts.push("## Recommended Agent Flow\n");
|
|
8013
8520
|
parts.push(`Recommended order for a ${stateLabel2(project.state)} project:
|
package/package.json
CHANGED