@kaddo/mcp 3.62.0 → 3.64.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 +320 -63
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -168,7 +168,8 @@ var DERIVED_WRITE_FILES = /* @__PURE__ */ new Set([
|
|
|
168
168
|
".kaddo/graph.json",
|
|
169
169
|
".kaddo/graph.mmd",
|
|
170
170
|
".kaddo/graph-hints.md",
|
|
171
|
-
".kaddo/graph-hints.json"
|
|
171
|
+
".kaddo/graph-hints.json",
|
|
172
|
+
".kaddo/modules.yml"
|
|
172
173
|
]);
|
|
173
174
|
var DERIVED_EXPORTS_RE = /^\.kaddo\/exports\/[^/]+\.capsule\.(md|json)$/;
|
|
174
175
|
var DERIVED_REPORTS_RE = /^\.kaddo\/reports\/[^/]+\.(md|json)$/;
|
|
@@ -447,10 +448,14 @@ var configSchema = z.object({
|
|
|
447
448
|
team: z.object({
|
|
448
449
|
size: teamSizeSchema.default(DEFAULTS.teamSize)
|
|
449
450
|
}).passthrough().default({}),
|
|
451
|
+
system: z.object({
|
|
452
|
+
name: z.string().optional()
|
|
453
|
+
}).passthrough().optional(),
|
|
450
454
|
multirepo: z.object({
|
|
451
455
|
role: multirepoRoleSchema,
|
|
452
456
|
modules_file: z.string().optional(),
|
|
453
|
-
parent_system: z.string().optional()
|
|
457
|
+
parent_system: z.string().optional(),
|
|
458
|
+
workspace_roots: z.array(z.string()).optional()
|
|
454
459
|
}).passthrough().optional(),
|
|
455
460
|
module: z.object({
|
|
456
461
|
id: z.string().optional()
|
|
@@ -489,6 +494,9 @@ function projectRole(config) {
|
|
|
489
494
|
function isModule(config) {
|
|
490
495
|
return projectRole(config) === "module";
|
|
491
496
|
}
|
|
497
|
+
function isCore(config) {
|
|
498
|
+
return projectRole(config) === "core";
|
|
499
|
+
}
|
|
492
500
|
|
|
493
501
|
// ../cli/src/services/artifact-reader.ts
|
|
494
502
|
import matter3 from "gray-matter";
|
|
@@ -685,6 +693,34 @@ function firstUnrefinedLayerAgent(layers) {
|
|
|
685
693
|
return { agent: "architecture-agent", step: "Use architecture-agent to complete knowledge/tech/current-state.md" };
|
|
686
694
|
}
|
|
687
695
|
function assessPhase(input) {
|
|
696
|
+
if (input.isModuleRepo) {
|
|
697
|
+
const techStatus = layer(input.layers, "Tech");
|
|
698
|
+
const techReady = !NOT_READY_LAYER.includes(techStatus);
|
|
699
|
+
if (techReady) {
|
|
700
|
+
return {
|
|
701
|
+
phase: "Active Delivery",
|
|
702
|
+
reasons: ["Module repo \u2014 Tech layer ready", "Business/Product managed by core"],
|
|
703
|
+
recommendedAgents: [],
|
|
704
|
+
nextStep: "Module knowledge is ready for core orchestration.",
|
|
705
|
+
llmInstructions: [
|
|
706
|
+
"This is a module repo. Business, Product, and Delivery are managed by the core repo.",
|
|
707
|
+
"Do not create business, product, roadmap or Work Items here."
|
|
708
|
+
]
|
|
709
|
+
};
|
|
710
|
+
}
|
|
711
|
+
return {
|
|
712
|
+
phase: "Knowledge Refinement",
|
|
713
|
+
reasons: ["Module repo \u2014 Tech layer incomplete", "Business/Product managed by core"],
|
|
714
|
+
recommendedAgents: ["module-context-agent"],
|
|
715
|
+
nextStep: "Use module-context-agent to refine knowledge/tech/module/module-context.md",
|
|
716
|
+
llmInstructions: [
|
|
717
|
+
"Use the module-context-agent to refine the module context.",
|
|
718
|
+
"Do not create business, product, roadmap or Work Items in this module.",
|
|
719
|
+
"Do not install agents or skills.",
|
|
720
|
+
"Do not write application code."
|
|
721
|
+
]
|
|
722
|
+
};
|
|
723
|
+
}
|
|
688
724
|
const phase = determinePhase(input);
|
|
689
725
|
const reasons = buildReasons(input);
|
|
690
726
|
const bs = input.workItems.byState;
|
|
@@ -790,7 +826,7 @@ function assessPhase(input) {
|
|
|
790
826
|
|
|
791
827
|
// ../cli/src/core/capsule.ts
|
|
792
828
|
import matter4 from "gray-matter";
|
|
793
|
-
import { parse as
|
|
829
|
+
import { parse as parseYaml7, stringify as stringifyYaml3 } from "yaml";
|
|
794
830
|
|
|
795
831
|
// ../cli/src/services/owners.ts
|
|
796
832
|
import { parse as parseYaml3 } from "yaml";
|
|
@@ -847,7 +883,7 @@ function loadMappedModules(dir) {
|
|
|
847
883
|
modules.push({
|
|
848
884
|
id,
|
|
849
885
|
name: typeof m2.name === "string" ? m2.name : void 0,
|
|
850
|
-
repoPath: typeof m2.repoPath === "string" ? m2.repoPath : "",
|
|
886
|
+
repoPath: typeof m2.repoPath === "string" ? m2.repoPath : typeof m2.path === "string" ? m2.path : "",
|
|
851
887
|
type: typeof m2.type === "string" ? m2.type : void 0,
|
|
852
888
|
mainTechnology: typeof m2.mainTechnology === "string" ? m2.mainTechnology : void 0,
|
|
853
889
|
owner: typeof m2.owner === "string" ? m2.owner : void 0,
|
|
@@ -896,13 +932,15 @@ function detectModuleStatus(coreDir, repoPath) {
|
|
|
896
932
|
status: "configured",
|
|
897
933
|
configured: true,
|
|
898
934
|
role: "module",
|
|
899
|
-
moduleContext: exists(join(moduleDir, "knowledge", "module", "module-context.md")),
|
|
935
|
+
moduleContext: exists(join(moduleDir, "knowledge", "tech", "module", "module-context.md")) || exists(join(moduleDir, "knowledge", "module", "module-context.md")),
|
|
900
936
|
currentState: exists(join(moduleDir, "knowledge", "tech", "current-state.md")),
|
|
901
937
|
codebase: exists(join(moduleDir, "knowledge", "tech", "codebase.md"))
|
|
902
938
|
};
|
|
903
939
|
}
|
|
904
940
|
function readModuleContext(coreDir, repoPath) {
|
|
905
|
-
const
|
|
941
|
+
const newPath = join(coreDir, repoPath, "knowledge", "tech", "module", "module-context.md");
|
|
942
|
+
const legacyPath = join(coreDir, repoPath, "knowledge", "module", "module-context.md");
|
|
943
|
+
const p = exists(newPath) ? newPath : legacyPath;
|
|
906
944
|
if (!exists(p)) return null;
|
|
907
945
|
try {
|
|
908
946
|
return readFile(p);
|
|
@@ -1042,7 +1080,7 @@ var Q2 = o("\u25B2", "!");
|
|
|
1042
1080
|
var ee = o("\u25A0", "x");
|
|
1043
1081
|
|
|
1044
1082
|
// ../cli/src/commands/modules-map.ts
|
|
1045
|
-
import { parse as
|
|
1083
|
+
import { parse as parseYaml6, stringify as stringifyYaml2 } from "yaml";
|
|
1046
1084
|
|
|
1047
1085
|
// ../cli/src/templates/registry.ts
|
|
1048
1086
|
var QUALITY = "## Quality checklist";
|
|
@@ -2153,6 +2191,9 @@ ${QUALITY}
|
|
|
2153
2191
|
- [ ] The next step is clear.
|
|
2154
2192
|
`;
|
|
2155
2193
|
|
|
2194
|
+
// ../cli/src/commands/modules-discover.ts
|
|
2195
|
+
import { parse as parseYaml5, stringify as stringifyYaml } from "yaml";
|
|
2196
|
+
|
|
2156
2197
|
// ../cli/src/core/capsule.ts
|
|
2157
2198
|
var KNOWLEDGE2 = "knowledge";
|
|
2158
2199
|
function today() {
|
|
@@ -2252,7 +2293,7 @@ function loadExternalRegistry(dir) {
|
|
|
2252
2293
|
const p = join(dir, EXTERNAL_PATH);
|
|
2253
2294
|
if (!exists(p)) return [];
|
|
2254
2295
|
try {
|
|
2255
|
-
const parsed =
|
|
2296
|
+
const parsed = parseYaml7(readFile(p));
|
|
2256
2297
|
return Array.isArray(parsed?.external) ? parsed.external : [];
|
|
2257
2298
|
} catch {
|
|
2258
2299
|
return [];
|
|
@@ -2996,6 +3037,21 @@ function layerQuality(dir, layer2) {
|
|
|
2996
3037
|
return worst;
|
|
2997
3038
|
}
|
|
2998
3039
|
function knowledgeLayers(dir) {
|
|
3040
|
+
const config = loadConfig(dir);
|
|
3041
|
+
if (config && isModule(config)) {
|
|
3042
|
+
return [
|
|
3043
|
+
{ layer: "Business", status: "Not applicable", detected: [] },
|
|
3044
|
+
{ layer: "Product", status: "Not applicable", detected: [] },
|
|
3045
|
+
...discoverLayers(dir).filter((l2) => l2.layer === "Tech").map((l2) => {
|
|
3046
|
+
if (l2.status !== "Consolidated" && l2.status !== "Structured") return l2;
|
|
3047
|
+
const q3 = layerQuality(dir, l2.layer);
|
|
3048
|
+
if (q3 === "placeholder") return { ...l2, status: "Placeholder" };
|
|
3049
|
+
if (q3 === "weak") return { ...l2, status: "Weak" };
|
|
3050
|
+
return l2;
|
|
3051
|
+
}),
|
|
3052
|
+
{ layer: "Delivery", status: "Managed by core", detected: [] }
|
|
3053
|
+
];
|
|
3054
|
+
}
|
|
2999
3055
|
return discoverLayers(dir).map((l2) => {
|
|
3000
3056
|
if (l2.status !== "Consolidated" && l2.status !== "Structured") return l2;
|
|
3001
3057
|
const q3 = layerQuality(dir, l2.layer);
|
|
@@ -3693,6 +3749,9 @@ function buildAdapterStatuses(dir) {
|
|
|
3693
3749
|
});
|
|
3694
3750
|
}
|
|
3695
3751
|
|
|
3752
|
+
// ../cli/src/core/next-step.ts
|
|
3753
|
+
import { parse as parseYaml8 } from "yaml";
|
|
3754
|
+
|
|
3696
3755
|
// ../cli/src/agents/groups.ts
|
|
3697
3756
|
var AGENT_GROUPS = {
|
|
3698
3757
|
business: ["business-agent.md"],
|
|
@@ -3845,6 +3904,14 @@ function buildDeliveryState(dir) {
|
|
|
3845
3904
|
adapters_installed: adapters.length
|
|
3846
3905
|
};
|
|
3847
3906
|
}
|
|
3907
|
+
function hasRegisteredModules(modulesYmlPath) {
|
|
3908
|
+
try {
|
|
3909
|
+
const parsed = parseYaml8(readFile(modulesYmlPath));
|
|
3910
|
+
return Array.isArray(parsed?.modules) && parsed.modules.length > 0;
|
|
3911
|
+
} catch {
|
|
3912
|
+
return false;
|
|
3913
|
+
}
|
|
3914
|
+
}
|
|
3848
3915
|
function safeRead(p) {
|
|
3849
3916
|
try {
|
|
3850
3917
|
return readFile(p);
|
|
@@ -3894,12 +3961,20 @@ function resolveNextStep(dir, now = /* @__PURE__ */ new Date()) {
|
|
|
3894
3961
|
}
|
|
3895
3962
|
const state = config.project.state;
|
|
3896
3963
|
const q3 = (rel) => analyzeKnowledgeArtifact(dir, rel);
|
|
3964
|
+
const resolveAgent = (agent) => {
|
|
3965
|
+
const file = agent.endsWith(".md") ? agent : `${agent}.md`;
|
|
3966
|
+
const path4 = agentInstallPath(file);
|
|
3967
|
+
const installed = isFile(join(dir, path4));
|
|
3968
|
+
const group = agentGroupOf(file);
|
|
3969
|
+
return { agentPath: path4, agentInstalled: installed, installCommand: installed ? void 0 : `kaddo add agents --group ${group}` };
|
|
3970
|
+
};
|
|
3897
3971
|
const moduleRepo = isModule(config);
|
|
3898
|
-
const
|
|
3972
|
+
const coreRepo = isCore(config);
|
|
3973
|
+
const MC = exists(join(dir, "knowledge/tech/module/module-context.md")) ? "knowledge/tech/module/module-context.md" : "knowledge/module/module-context.md";
|
|
3899
3974
|
if (moduleRepo) {
|
|
3900
3975
|
const qMC = q3(MC);
|
|
3901
3976
|
if (qMC === "missing") {
|
|
3902
|
-
return { id: "init-module-context", phase: "Setup", label: "Create `knowledge/module/module-context.md` for this module.", command: "kaddo init", reason: "Module context file is missing. Re-run `kaddo init` as a multirepo module." };
|
|
3977
|
+
return { id: "init-module-context", phase: "Setup", label: "Create `knowledge/tech/module/module-context.md` for this module.", command: "kaddo init", reason: "Module context file is missing. Re-run `kaddo init` as a multirepo module." };
|
|
3903
3978
|
}
|
|
3904
3979
|
if ((state === "pre-ai" || state === "legacy") && !exists(join(dir, ".kaddo", "scan.json"))) {
|
|
3905
3980
|
return { id: "scan", phase: "Discovery", label: "Run `kaddo scan` to capture deterministic signals from the existing code.", command: "kaddo scan", reason: "No scan baseline exists for this existing project yet." };
|
|
@@ -3908,15 +3983,26 @@ function resolveNextStep(dir, now = /* @__PURE__ */ new Date()) {
|
|
|
3908
3983
|
return { id: "context", phase: "Discovery", label: "Run `kaddo context` to prepare the LLM context pack.", command: "kaddo context", reason: "No context pack has been generated yet." };
|
|
3909
3984
|
}
|
|
3910
3985
|
if (qMC !== "useful") {
|
|
3986
|
+
const ar = resolveAgent("module-context-agent");
|
|
3911
3987
|
return {
|
|
3912
3988
|
id: "refine-module-context",
|
|
3913
3989
|
phase: "Knowledge Refinement",
|
|
3914
|
-
label: "Use module-context-agent to refine `knowledge/module/module-context.md`.",
|
|
3990
|
+
label: "Use module-context-agent to refine `knowledge/tech/module/module-context.md`.",
|
|
3915
3991
|
agent: "module-context-agent",
|
|
3916
3992
|
skill: "module-context-refinement",
|
|
3917
3993
|
target: MC,
|
|
3994
|
+
agentPath: ar.agentPath,
|
|
3995
|
+
agentInstalled: ar.agentInstalled,
|
|
3996
|
+
installCommand: ar.installCommand,
|
|
3918
3997
|
reason: "Module context is still a placeholder.",
|
|
3919
|
-
instructions: [
|
|
3998
|
+
instructions: [
|
|
3999
|
+
"Refine the module context using evidence from this repository.",
|
|
4000
|
+
"Use the parent system context when available.",
|
|
4001
|
+
"Do not create business, product, roadmap or Work Items in this module.",
|
|
4002
|
+
"Do not install agents or skills in this module.",
|
|
4003
|
+
"Do not write application code.",
|
|
4004
|
+
"Preserve frontmatter and record unknowns as open questions."
|
|
4005
|
+
]
|
|
3920
4006
|
};
|
|
3921
4007
|
}
|
|
3922
4008
|
const qCurrentState2 = q3(CS), qCodebase2 = q3(CB);
|
|
@@ -3945,12 +4031,18 @@ function resolveNextStep(dir, now = /* @__PURE__ */ new Date()) {
|
|
|
3945
4031
|
if (!exists(join(dir, ".kaddo", "understand.md"))) {
|
|
3946
4032
|
return { id: "understand", phase: "Discovery", label: "Run `kaddo understand` to summarize the project context.", command: "kaddo understand", reason: "No understand handoff has been generated yet." };
|
|
3947
4033
|
}
|
|
3948
|
-
return { id: "module-ready", phase: "
|
|
4034
|
+
return { id: "module-ready", phase: "Ready for Core Orchestration", label: "Module knowledge is complete. Create and manage Work Items from the core repository.", reason: "This module's knowledge is ready for core orchestration. Work Items are created and tracked in the core." };
|
|
3949
4035
|
}
|
|
3950
4036
|
const qBusiness = q3(B2), qProduct = q3(P2), qCap = q3(CAP), qCurrentState = q3(CS), qCodebase = q3(CB);
|
|
3951
|
-
if (qBusiness === "missing" || qProduct === "missing") {
|
|
4037
|
+
if (!coreRepo && (qBusiness === "missing" || qProduct === "missing")) {
|
|
3952
4038
|
return { id: "bootstrap", phase: "Setup", label: "Run `kaddo bootstrap` to create the project knowledge baseline.", command: "kaddo bootstrap", reason: "The knowledge baseline is incomplete." };
|
|
3953
4039
|
}
|
|
4040
|
+
if (coreRepo) {
|
|
4041
|
+
const modulesYmlPath = join(dir, ".kaddo", "modules.yml");
|
|
4042
|
+
if (!exists(modulesYmlPath) || !hasRegisteredModules(modulesYmlPath)) {
|
|
4043
|
+
return { id: "modules-discover", phase: "Setup", label: "Run `kaddo modules discover` to find sibling module repositories.", command: "kaddo modules discover", reason: "No modules are mapped for this core repository." };
|
|
4044
|
+
}
|
|
4045
|
+
}
|
|
3954
4046
|
const ctx = buildCodexAdapterContext(dir);
|
|
3955
4047
|
if (!ctx.hasAgents) {
|
|
3956
4048
|
return { id: "add-agents", phase: "Setup", label: "Run `kaddo add agents` to install the Kaddo agent prompt packs.", command: "kaddo add agents", reason: "No Kaddo agents are installed yet." };
|
|
@@ -3965,13 +4057,6 @@ function resolveNextStep(dir, now = /* @__PURE__ */ new Date()) {
|
|
|
3965
4057
|
return { id: "context", phase: "Discovery", label: "Run `kaddo context` to prepare the LLM context pack.", command: "kaddo context", reason: "No context pack has been generated yet." };
|
|
3966
4058
|
}
|
|
3967
4059
|
const discovery = state === "pre-ai" || state === "legacy";
|
|
3968
|
-
const resolveAgent = (agent) => {
|
|
3969
|
-
const file = agent.endsWith(".md") ? agent : `${agent}.md`;
|
|
3970
|
-
const path4 = agentInstallPath(file);
|
|
3971
|
-
const installed = isFile(join(dir, path4));
|
|
3972
|
-
const group = agentGroupOf(file);
|
|
3973
|
-
return { agentPath: path4, agentInstalled: installed, installCommand: installed ? void 0 : `kaddo add agents --group ${group}` };
|
|
3974
|
-
};
|
|
3975
4060
|
const refine = (id, agent, target, quality, verb = "complete") => {
|
|
3976
4061
|
const ar = resolveAgent(agent);
|
|
3977
4062
|
return {
|
|
@@ -7571,6 +7656,67 @@ var identifyRisks = {
|
|
|
7571
7656
|
return { status: hasLegacy ? "done" : "pending", agent: hasLegacy ? void 0 : "legacy-agent" };
|
|
7572
7657
|
}
|
|
7573
7658
|
};
|
|
7659
|
+
var refineModuleContext = {
|
|
7660
|
+
id: "refine-module-context",
|
|
7661
|
+
label: "Refine module context",
|
|
7662
|
+
evaluate: (ctx) => {
|
|
7663
|
+
const newPath = join(ctx.dir, "knowledge/tech/module/module-context.md");
|
|
7664
|
+
const legacyPath = join(ctx.dir, "knowledge/module/module-context.md");
|
|
7665
|
+
const mcPath = exists(newPath) ? "knowledge/tech/module/module-context.md" : exists(legacyPath) ? "knowledge/module/module-context.md" : null;
|
|
7666
|
+
if (!mcPath) return { status: "pending", agent: "module-context-agent", skill: "module-context-refinement" };
|
|
7667
|
+
const q3 = analyzeKnowledgeArtifact(ctx.dir, mcPath);
|
|
7668
|
+
if (q3 === "useful") return { status: "done", evidence: [mcPath] };
|
|
7669
|
+
return { status: "current", agent: "module-context-agent", skill: "module-context-refinement", evidence: [mcPath], reason: "Module context is still a placeholder." };
|
|
7670
|
+
}
|
|
7671
|
+
};
|
|
7672
|
+
var describeModuleCurrentState = {
|
|
7673
|
+
id: "describe-current-state",
|
|
7674
|
+
label: "Describe current state",
|
|
7675
|
+
evaluate: (ctx) => ({
|
|
7676
|
+
status: isUseful(ctx.qCurrentState) ? "done" : "pending",
|
|
7677
|
+
evidence: isUseful(ctx.qCurrentState) ? ["knowledge/tech/current-state.md"] : void 0,
|
|
7678
|
+
agent: isUseful(ctx.qCurrentState) ? void 0 : "architecture-agent"
|
|
7679
|
+
})
|
|
7680
|
+
};
|
|
7681
|
+
var mapModuleCodebase = {
|
|
7682
|
+
id: "map-codebase",
|
|
7683
|
+
label: "Map codebase",
|
|
7684
|
+
evaluate: (ctx) => ({
|
|
7685
|
+
status: isUseful(ctx.qCodebase) ? "done" : "pending",
|
|
7686
|
+
evidence: isUseful(ctx.qCodebase) ? ["knowledge/tech/codebase.md"] : void 0,
|
|
7687
|
+
agent: isUseful(ctx.qCodebase) ? void 0 : "architecture-agent"
|
|
7688
|
+
})
|
|
7689
|
+
};
|
|
7690
|
+
var validateModuleKnowledge = {
|
|
7691
|
+
id: "validate-module-knowledge",
|
|
7692
|
+
label: "Validate module knowledge",
|
|
7693
|
+
evaluate: (ctx) => {
|
|
7694
|
+
const hasUnderstand = exists(join(ctx.dir, ".kaddo/understand.md"));
|
|
7695
|
+
if (hasUnderstand) return { status: "done", evidence: [".kaddo/understand.md"] };
|
|
7696
|
+
return { status: "pending", command: "kaddo understand" };
|
|
7697
|
+
}
|
|
7698
|
+
};
|
|
7699
|
+
var readyForCoreOrchestration = {
|
|
7700
|
+
id: "ready-for-core-orchestration",
|
|
7701
|
+
label: "Ready for core orchestration",
|
|
7702
|
+
evaluate: (ctx) => {
|
|
7703
|
+
const newPath = join(ctx.dir, "knowledge/tech/module/module-context.md");
|
|
7704
|
+
const legacyPath = join(ctx.dir, "knowledge/module/module-context.md");
|
|
7705
|
+
const mcPath = exists(newPath) ? "knowledge/tech/module/module-context.md" : exists(legacyPath) ? "knowledge/module/module-context.md" : null;
|
|
7706
|
+
const mcUseful = mcPath ? analyzeKnowledgeArtifact(ctx.dir, mcPath) === "useful" : false;
|
|
7707
|
+
const allDone = mcUseful && isUseful(ctx.qCurrentState) && isUseful(ctx.qCodebase);
|
|
7708
|
+
return { status: allDone ? "done" : "pending", reason: allDone ? void 0 : "Module knowledge is not yet complete." };
|
|
7709
|
+
}
|
|
7710
|
+
};
|
|
7711
|
+
var MODULE_STEPS = [
|
|
7712
|
+
enableKaddo,
|
|
7713
|
+
scanRepository,
|
|
7714
|
+
refineModuleContext,
|
|
7715
|
+
describeModuleCurrentState,
|
|
7716
|
+
mapModuleCodebase,
|
|
7717
|
+
validateModuleKnowledge,
|
|
7718
|
+
readyForCoreOrchestration
|
|
7719
|
+
];
|
|
7574
7720
|
var NEW_STEPS = [
|
|
7575
7721
|
enableKaddo,
|
|
7576
7722
|
defineBusiness,
|
|
@@ -7711,17 +7857,18 @@ function mapNextStepId(id) {
|
|
|
7711
7857
|
"review-work-item": "refine-work-item",
|
|
7712
7858
|
"prepare-implementation": "prepare-implementation",
|
|
7713
7859
|
"implement-work-item": "prepare-implementation",
|
|
7714
|
-
"refine-module-context": "refine-
|
|
7860
|
+
"refine-module-context": "refine-module-context",
|
|
7715
7861
|
"init-module-context": "enable-kaddo",
|
|
7716
|
-
"module-ready": "
|
|
7717
|
-
"validate-work-item-modules": "
|
|
7862
|
+
"module-ready": "ready-for-core-orchestration",
|
|
7863
|
+
"validate-work-item-modules": "validate-module-knowledge",
|
|
7864
|
+
"modules-discover": "enable-kaddo"
|
|
7718
7865
|
};
|
|
7719
7866
|
return MAP[id] ?? id;
|
|
7720
7867
|
}
|
|
7721
7868
|
function buildProjectRoute(dir) {
|
|
7722
7869
|
const config = loadConfig(dir);
|
|
7723
7870
|
const state = config?.project.state ?? "pre-ai";
|
|
7724
|
-
const defs = stepsForState(state);
|
|
7871
|
+
const defs = config && isModule(config) ? MODULE_STEPS : stepsForState(state);
|
|
7725
7872
|
const ctx = buildRouteContext(dir);
|
|
7726
7873
|
const steps = defs.map((d3) => {
|
|
7727
7874
|
const result = d3.evaluate(ctx);
|
|
@@ -8108,7 +8255,8 @@ function buildProjectExplanation(dir) {
|
|
|
8108
8255
|
roadmapQuality: buildRoadmapQuality(dir),
|
|
8109
8256
|
projectRoute: buildProjectRoute(dir),
|
|
8110
8257
|
scanSignals: loadScanSignals(dir),
|
|
8111
|
-
metadataHealth: analyzeMetadataHealth(dir)
|
|
8258
|
+
metadataHealth: analyzeMetadataHealth(dir),
|
|
8259
|
+
isModuleRepo: config != null && isModule(config)
|
|
8112
8260
|
};
|
|
8113
8261
|
}
|
|
8114
8262
|
function stateLabel(state) {
|
|
@@ -8981,7 +9129,7 @@ function serializeImpactJson(r2) {
|
|
|
8981
9129
|
}
|
|
8982
9130
|
|
|
8983
9131
|
// ../cli/src/core/savings.ts
|
|
8984
|
-
import { parse as
|
|
9132
|
+
import { parse as parseYaml9 } from "yaml";
|
|
8985
9133
|
var DEFAULT_ASSUMPTIONS = {
|
|
8986
9134
|
currency: "USD",
|
|
8987
9135
|
hourly_cost: 40,
|
|
@@ -8999,7 +9147,7 @@ function loadAssumptions(dir) {
|
|
|
8999
9147
|
const p = join(dir, SAVINGS_PATH);
|
|
9000
9148
|
if (!exists(p)) return { assumptions: { ...DEFAULT_ASSUMPTIONS }, source: "default" };
|
|
9001
9149
|
try {
|
|
9002
|
-
const raw =
|
|
9150
|
+
const raw = parseYaml9(readFile(p));
|
|
9003
9151
|
const a2 = raw?.assumptions ?? {};
|
|
9004
9152
|
const t = raw?.team ?? {};
|
|
9005
9153
|
const num = (v, d3) => typeof v === "number" && Number.isFinite(v) ? v : d3;
|
|
@@ -9837,7 +9985,7 @@ function getWorkItem(root, id) {
|
|
|
9837
9985
|
const content = readText(root, item.path);
|
|
9838
9986
|
return ok({ ...item, content: content ?? "" });
|
|
9839
9987
|
}
|
|
9840
|
-
function markWorkItemReady(root, id,
|
|
9988
|
+
function markWorkItemReady(root, id, confirm2) {
|
|
9841
9989
|
const item = listWorkItems(root).find((w3) => w3.id === id);
|
|
9842
9990
|
if (!item) return fail(`Work Item "${id}" not found.`);
|
|
9843
9991
|
if (item.status === "ready") {
|
|
@@ -9847,7 +9995,7 @@ function markWorkItemReady(root, id, confirm) {
|
|
|
9847
9995
|
return fail(`Work Item ${item.id} is in state "${item.status}", not "draft". Only draft Work Items can be marked as ready.`);
|
|
9848
9996
|
}
|
|
9849
9997
|
const warnings = item.readiness?.warnings ?? [];
|
|
9850
|
-
if (!
|
|
9998
|
+
if (!confirm2) {
|
|
9851
9999
|
return ok({
|
|
9852
10000
|
status: "needs_confirmation",
|
|
9853
10001
|
workItem: {
|
|
@@ -9937,9 +10085,12 @@ function listGraphHints(root, filter = {}) {
|
|
|
9937
10085
|
import fs3 from "fs";
|
|
9938
10086
|
import path3 from "path";
|
|
9939
10087
|
import matter11 from "gray-matter";
|
|
9940
|
-
import { parse as
|
|
10088
|
+
import { parse as parseYaml10, stringify as stringifyYaml4 } from "yaml";
|
|
9941
10089
|
var ok2 = (data) => ({ ok: true, data });
|
|
9942
10090
|
var fail2 = (message) => ({ ok: false, message });
|
|
10091
|
+
function moduleRepoPath(m2) {
|
|
10092
|
+
return m2.path ?? m2.repoPath ?? "";
|
|
10093
|
+
}
|
|
9943
10094
|
function loadModulesDescriptor(root) {
|
|
9944
10095
|
return readYaml(root, ".kaddo/modules.yml") ?? { modules: [] };
|
|
9945
10096
|
}
|
|
@@ -9949,7 +10100,7 @@ function loadConfig2(root) {
|
|
|
9949
10100
|
function projectRole2(config) {
|
|
9950
10101
|
return config.project?.role ?? config.multirepo?.role;
|
|
9951
10102
|
}
|
|
9952
|
-
function
|
|
10103
|
+
function isCore2(config) {
|
|
9953
10104
|
return projectRole2(config) === "core";
|
|
9954
10105
|
}
|
|
9955
10106
|
function readModuleFile(root, repoPath, relFile) {
|
|
@@ -9970,7 +10121,7 @@ function detectModuleStatus2(root, repoPath) {
|
|
|
9970
10121
|
}
|
|
9971
10122
|
let parsed = null;
|
|
9972
10123
|
try {
|
|
9973
|
-
parsed =
|
|
10124
|
+
parsed = parseYaml10(fs3.readFileSync(configPath, "utf-8"));
|
|
9974
10125
|
} catch {
|
|
9975
10126
|
}
|
|
9976
10127
|
const role = parsed?.project?.role ?? parsed?.multirepo?.role;
|
|
@@ -9981,11 +10132,18 @@ function detectModuleStatus2(root, repoPath) {
|
|
|
9981
10132
|
status: "configured",
|
|
9982
10133
|
configured: true,
|
|
9983
10134
|
role: "module",
|
|
9984
|
-
moduleContext: fs3.existsSync(path3.join(moduleDir, "knowledge", "module", "module-context.md")),
|
|
10135
|
+
moduleContext: fs3.existsSync(path3.join(moduleDir, "knowledge", "tech", "module", "module-context.md")) || fs3.existsSync(path3.join(moduleDir, "knowledge", "module", "module-context.md")),
|
|
9985
10136
|
currentState: fs3.existsSync(path3.join(moduleDir, "knowledge", "tech", "current-state.md")),
|
|
9986
10137
|
codebase: fs3.existsSync(path3.join(moduleDir, "knowledge", "tech", "codebase.md"))
|
|
9987
10138
|
};
|
|
9988
10139
|
}
|
|
10140
|
+
function resolveModuleContextPath(root, repoPath) {
|
|
10141
|
+
const moduleDir = path3.resolve(root, repoPath);
|
|
10142
|
+
if (fs3.existsSync(path3.join(moduleDir, "knowledge", "tech", "module", "module-context.md"))) {
|
|
10143
|
+
return "knowledge/tech/module/module-context.md";
|
|
10144
|
+
}
|
|
10145
|
+
return "knowledge/module/module-context.md";
|
|
10146
|
+
}
|
|
9989
10147
|
function isPlaceholder(content) {
|
|
9990
10148
|
const body = content.replace(/^---[\s\S]*?---\n?/, "");
|
|
9991
10149
|
return /^_[^_]+_$/m.test(body) && !body.split("\n").some((l2) => l2.trim().length > 0 && !l2.startsWith("#") && !l2.startsWith("_") && !l2.startsWith("-") && !l2.startsWith(">"));
|
|
@@ -10004,13 +10162,14 @@ function slugify2(s) {
|
|
|
10004
10162
|
function modulesListTool(root, args) {
|
|
10005
10163
|
const config = loadConfig2(root);
|
|
10006
10164
|
if (!config) return fail2("No Kaddo config found. Run `kaddo init` first.");
|
|
10007
|
-
if (!
|
|
10165
|
+
if (!isCore2(config)) return fail2("kaddo_modules_list can only be called from a core repository (project.role: core).");
|
|
10008
10166
|
const descriptor = loadModulesDescriptor(root);
|
|
10009
10167
|
const modules = (descriptor.modules ?? []).map((m2) => {
|
|
10010
|
-
const
|
|
10168
|
+
const rp = moduleRepoPath(m2);
|
|
10169
|
+
const st = detectModuleStatus2(root, rp);
|
|
10011
10170
|
const entry = {
|
|
10012
10171
|
id: m2.id,
|
|
10013
|
-
repo:
|
|
10172
|
+
repo: rp,
|
|
10014
10173
|
status: st.status,
|
|
10015
10174
|
kaddo: {
|
|
10016
10175
|
configured: st.configured,
|
|
@@ -10034,7 +10193,8 @@ function getModuleContextTool(root, args) {
|
|
|
10034
10193
|
const descriptor = loadModulesDescriptor(root);
|
|
10035
10194
|
const mod = (descriptor.modules ?? []).find((m2) => m2.id === args.module);
|
|
10036
10195
|
if (!mod) return fail2(`Module "${args.module}" not found in .kaddo/modules.yml.`);
|
|
10037
|
-
const
|
|
10196
|
+
const rp = moduleRepoPath(mod);
|
|
10197
|
+
const st = detectModuleStatus2(root, rp);
|
|
10038
10198
|
const warnings = [];
|
|
10039
10199
|
if (st.status !== "configured") {
|
|
10040
10200
|
if (st.warning) warnings.push(st.warning);
|
|
@@ -10045,26 +10205,27 @@ function getModuleContextTool(root, args) {
|
|
|
10045
10205
|
recommendedNextStep: { label: "Initialize module repository with Kaddo.", command: "kaddo init" }
|
|
10046
10206
|
});
|
|
10047
10207
|
}
|
|
10048
|
-
const
|
|
10208
|
+
const mcRelPath = resolveModuleContextPath(root, rp);
|
|
10209
|
+
const mcContent = readModuleFile(root, rp, mcRelPath);
|
|
10049
10210
|
const context = {
|
|
10050
|
-
moduleContextPath: `${
|
|
10211
|
+
moduleContextPath: `${rp}/${mcRelPath}`,
|
|
10051
10212
|
moduleContext: mcContent ?? null
|
|
10052
10213
|
};
|
|
10053
10214
|
if (mcContent && isPlaceholder(mcContent)) {
|
|
10054
10215
|
warnings.push("module-context.md still contains placeholder sections.");
|
|
10055
10216
|
}
|
|
10056
10217
|
if (args.includeTech) {
|
|
10057
|
-
const cs = readModuleFile(root,
|
|
10058
|
-
const cb = readModuleFile(root,
|
|
10059
|
-
context.currentStatePath = `${
|
|
10218
|
+
const cs = readModuleFile(root, rp, "knowledge/tech/current-state.md");
|
|
10219
|
+
const cb = readModuleFile(root, rp, "knowledge/tech/codebase.md");
|
|
10220
|
+
context.currentStatePath = `${rp}/knowledge/tech/current-state.md`;
|
|
10060
10221
|
context.currentStateSummary = cs ? firstParagraph3(cs) : null;
|
|
10061
|
-
context.codebasePath = `${
|
|
10222
|
+
context.codebasePath = `${rp}/knowledge/tech/codebase.md`;
|
|
10062
10223
|
context.codebaseSummary = cb ? firstParagraph3(cb) : null;
|
|
10063
10224
|
if (!cs) warnings.push("current-state.md not found in module repository.");
|
|
10064
10225
|
if (!cb) warnings.push("codebase.md not found in module repository.");
|
|
10065
10226
|
}
|
|
10066
10227
|
return ok2({
|
|
10067
|
-
module: { id: mod.id, repo:
|
|
10228
|
+
module: { id: mod.id, repo: rp, status: "configured" },
|
|
10068
10229
|
context,
|
|
10069
10230
|
warnings: args.includeWarnings ? warnings : []
|
|
10070
10231
|
});
|
|
@@ -10092,15 +10253,17 @@ function validateWorkItemModulesTool(root, args) {
|
|
|
10092
10253
|
return { id: modId, status: "not_mapped", hasModuleContext: false, hasCurrentState: false, hasCodebase: false, hasOwnership: false };
|
|
10093
10254
|
}
|
|
10094
10255
|
const mod = (descriptor.modules ?? []).find((m2) => m2.id === modId);
|
|
10095
|
-
const
|
|
10256
|
+
const rp = moduleRepoPath(mod);
|
|
10257
|
+
const st = detectModuleStatus2(root, rp);
|
|
10096
10258
|
if (st.status !== "configured") {
|
|
10097
10259
|
warnings.push(`Module "${modId}" is ${st.status}.`);
|
|
10098
10260
|
}
|
|
10099
|
-
const
|
|
10261
|
+
const mcRelPath = resolveModuleContextPath(root, rp);
|
|
10262
|
+
const mcContent = st.moduleContext ? readModuleFile(root, rp, mcRelPath) : null;
|
|
10100
10263
|
if (mcContent && isPlaceholder(mcContent)) {
|
|
10101
10264
|
warnings.push(`Module "${modId}" has placeholder module-context.`);
|
|
10102
10265
|
}
|
|
10103
|
-
const hasOwnership = codeEntries.some((c) => c.repo && (c.repo ===
|
|
10266
|
+
const hasOwnership = codeEntries.some((c) => c.repo && (c.repo === rp || c.repo.endsWith(`/${modId}`) || c.repo.includes(modId)));
|
|
10104
10267
|
return { id: modId, status: st.status, hasModuleContext: st.moduleContext, hasCurrentState: st.currentState, hasCodebase: st.codebase, hasOwnership };
|
|
10105
10268
|
});
|
|
10106
10269
|
for (const ce of codeEntries) {
|
|
@@ -10138,12 +10301,14 @@ function getWorkItemContextTool(root, args) {
|
|
|
10138
10301
|
warnings.push(`Module "${modId}" not in modules.yml.`);
|
|
10139
10302
|
return { id: modId, repo: null, moduleContext: null, currentStateSummary: null, codebaseSummary: null };
|
|
10140
10303
|
}
|
|
10141
|
-
const
|
|
10304
|
+
const rp = moduleRepoPath(mod);
|
|
10305
|
+
const st = detectModuleStatus2(root, rp);
|
|
10142
10306
|
if (st.status !== "configured") warnings.push(`Module "${modId}" is ${st.status}.`);
|
|
10143
|
-
const
|
|
10144
|
-
const
|
|
10145
|
-
const
|
|
10146
|
-
|
|
10307
|
+
const mcRelPath = resolveModuleContextPath(root, rp);
|
|
10308
|
+
const mc = args.includeModuleContexts !== false ? readModuleFile(root, rp, mcRelPath) : null;
|
|
10309
|
+
const cs = readModuleFile(root, rp, "knowledge/tech/current-state.md");
|
|
10310
|
+
const cb = readModuleFile(root, rp, "knowledge/tech/codebase.md");
|
|
10311
|
+
return { id: modId, repo: rp, moduleContext: mc, currentStateSummary: cs ? firstParagraph3(cs) : null, codebaseSummary: cb ? firstParagraph3(cb) : null };
|
|
10147
10312
|
});
|
|
10148
10313
|
const ownership = { crossRepo: codeEntries.length > 1, items: codeEntries.filter((c) => c.repo).map((c) => ({ repo: c.repo, paths: c.paths ?? [] })) };
|
|
10149
10314
|
const result = {
|
|
@@ -10185,7 +10350,7 @@ function buildBranchStrategy(wi, affectedModules, codeEntries, descriptor) {
|
|
|
10185
10350
|
const commitMessages = {};
|
|
10186
10351
|
for (const modId of affectedModules) {
|
|
10187
10352
|
const mod = (descriptor.modules ?? []).find((m2) => m2.id === modId);
|
|
10188
|
-
const repo = mod
|
|
10353
|
+
const repo = mod ? moduleRepoPath(mod) || modId : modId;
|
|
10189
10354
|
moduleBranches[repo] = `feature/${wiLower}-${modId}-${slug4.slice(0, 20)}`;
|
|
10190
10355
|
commitMessages[repo] = `fix(${wiLower}): update ${modId}`;
|
|
10191
10356
|
}
|
|
@@ -10235,7 +10400,9 @@ function exportCapsuleTool(root, args) {
|
|
|
10235
10400
|
const descriptor = loadModulesDescriptor(root);
|
|
10236
10401
|
const mod = (descriptor.modules ?? []).find((m2) => m2.id === args.module);
|
|
10237
10402
|
if (!mod) return fail2(`Module "${args.module}" not found in .kaddo/modules.yml.`);
|
|
10238
|
-
const
|
|
10403
|
+
const rp = moduleRepoPath(mod);
|
|
10404
|
+
const mcRelPath = resolveModuleContextPath(root, rp);
|
|
10405
|
+
const mc = readModuleFile(root, rp, mcRelPath);
|
|
10239
10406
|
if (!mc) warnings.push("module-context.md not found for this module.");
|
|
10240
10407
|
if (mc && isPlaceholder(mc)) warnings.push("module-context.md contains placeholder sections.");
|
|
10241
10408
|
capsuleType = "module";
|
|
@@ -10256,7 +10423,7 @@ function exportCapsuleTool(root, args) {
|
|
|
10256
10423
|
owners: mod.owner ? [mod.owner] : []
|
|
10257
10424
|
};
|
|
10258
10425
|
} else if (role === "module") {
|
|
10259
|
-
const mc = readText(root, "knowledge/module/module-context.md");
|
|
10426
|
+
const mc = readText(root, "knowledge/tech/module/module-context.md") ?? readText(root, "knowledge/module/module-context.md");
|
|
10260
10427
|
if (!mc) warnings.push("module-context.md not found.");
|
|
10261
10428
|
if (mc && isPlaceholder(mc)) warnings.push("module-context.md contains placeholder sections.");
|
|
10262
10429
|
const modId = config.module?.id ?? args.module;
|
|
@@ -10283,7 +10450,9 @@ function exportCapsuleTool(root, args) {
|
|
|
10283
10450
|
const descriptor = loadModulesDescriptor(root);
|
|
10284
10451
|
const responsibilities = [];
|
|
10285
10452
|
for (const m2 of descriptor.modules ?? []) {
|
|
10286
|
-
const
|
|
10453
|
+
const rp = moduleRepoPath(m2);
|
|
10454
|
+
const mcRelPath = resolveModuleContextPath(root, rp);
|
|
10455
|
+
const mc = readModuleFile(root, rp, mcRelPath);
|
|
10287
10456
|
responsibilities.push(mc ? `[${m2.id}] ${firstParagraph3(mc) || m2.name || m2.id}` : `[${m2.id}] ${m2.name || m2.id} (no module-context)`);
|
|
10288
10457
|
}
|
|
10289
10458
|
capsuleType = "system";
|
|
@@ -10303,7 +10472,7 @@ function exportCapsuleTool(root, args) {
|
|
|
10303
10472
|
};
|
|
10304
10473
|
} else {
|
|
10305
10474
|
if (role === "module") {
|
|
10306
|
-
const mc = readText(root, "knowledge/module/module-context.md");
|
|
10475
|
+
const mc = readText(root, "knowledge/tech/module/module-context.md") ?? readText(root, "knowledge/module/module-context.md");
|
|
10307
10476
|
if (!mc) warnings.push("module-context.md not found.");
|
|
10308
10477
|
if (mc && isPlaceholder(mc)) warnings.push("module-context.md contains placeholder sections.");
|
|
10309
10478
|
const modId = config.module?.id ?? "module";
|
|
@@ -10348,6 +10517,70 @@ function exportCapsuleTool(root, args) {
|
|
|
10348
10517
|
writeDerived(root, mdPath, mdContent);
|
|
10349
10518
|
return ok2({ exported: true, type: capsuleType, module: args.module ?? void 0, paths: { json: jsonPath, md: mdPath }, warnings });
|
|
10350
10519
|
}
|
|
10520
|
+
function modulesDiscoverTool(root, args) {
|
|
10521
|
+
const config = loadConfig2(root);
|
|
10522
|
+
if (!config) return fail2("No Kaddo config found.");
|
|
10523
|
+
if (!isCore2(config)) return fail2("Module discovery is only available from a core repository.");
|
|
10524
|
+
const sysName = config.system?.name ?? config.project?.name ?? "";
|
|
10525
|
+
const workspaceRoots2 = config.multirepo?.workspace_roots ?? [".."];
|
|
10526
|
+
const IGNORED = /* @__PURE__ */ new Set([".git", "node_modules", "dist", "build", "coverage", "vendor", ".next", "out", "tmp", "temp", ".kaddo"]);
|
|
10527
|
+
const coreAbs = path3.resolve(root);
|
|
10528
|
+
const discovered = [];
|
|
10529
|
+
for (const wr of workspaceRoots2) {
|
|
10530
|
+
const rootAbs = path3.resolve(root, wr);
|
|
10531
|
+
if (!fs3.existsSync(rootAbs) || !fs3.statSync(rootAbs).isDirectory()) continue;
|
|
10532
|
+
let entries;
|
|
10533
|
+
try {
|
|
10534
|
+
entries = fs3.readdirSync(rootAbs);
|
|
10535
|
+
} catch {
|
|
10536
|
+
continue;
|
|
10537
|
+
}
|
|
10538
|
+
for (const entry of entries) {
|
|
10539
|
+
if (IGNORED.has(entry)) continue;
|
|
10540
|
+
const candidateAbs = path3.resolve(rootAbs, entry);
|
|
10541
|
+
if (!fs3.statSync(candidateAbs).isDirectory()) continue;
|
|
10542
|
+
if (candidateAbs === coreAbs) continue;
|
|
10543
|
+
const relPath = path3.relative(root, candidateAbs).replace(/\\/g, "/");
|
|
10544
|
+
const cfgPath = path3.join(candidateAbs, ".kaddo", "config.yml");
|
|
10545
|
+
if (!fs3.existsSync(cfgPath)) {
|
|
10546
|
+
discovered.push({ id: entry, path: relPath, status: "not_configured", eligibleForMapping: false });
|
|
10547
|
+
continue;
|
|
10548
|
+
}
|
|
10549
|
+
let parsed = null;
|
|
10550
|
+
try {
|
|
10551
|
+
parsed = parseYaml10(fs3.readFileSync(cfgPath, "utf-8"));
|
|
10552
|
+
} catch {
|
|
10553
|
+
}
|
|
10554
|
+
const role = parsed?.project?.role ?? parsed?.multirepo?.role;
|
|
10555
|
+
if (role !== "module") {
|
|
10556
|
+
discovered.push({ id: entry, path: relPath, status: "invalid", eligibleForMapping: false, warning: "Not configured as module." });
|
|
10557
|
+
continue;
|
|
10558
|
+
}
|
|
10559
|
+
const modParent = parsed?.multirepo?.parent_system ?? "";
|
|
10560
|
+
if (modParent && modParent !== sysName) {
|
|
10561
|
+
discovered.push({ id: parsed?.module?.id ?? entry, path: relPath, status: "foreign_system", eligibleForMapping: false, parentSystem: modParent });
|
|
10562
|
+
continue;
|
|
10563
|
+
}
|
|
10564
|
+
discovered.push({ id: parsed?.module?.id ?? entry, path: relPath, status: "configured", eligibleForMapping: true });
|
|
10565
|
+
}
|
|
10566
|
+
}
|
|
10567
|
+
if (args.apply) {
|
|
10568
|
+
if (!args.confirm) {
|
|
10569
|
+
return ok2({ discovered, applied: false, message: "Set confirm: true to apply discovered modules." });
|
|
10570
|
+
}
|
|
10571
|
+
const descriptor = loadModulesDescriptor(root);
|
|
10572
|
+
for (const d3 of discovered.filter((dd) => dd.eligibleForMapping)) {
|
|
10573
|
+
if (!(descriptor.modules ?? []).some((m2) => m2.id === d3.id)) {
|
|
10574
|
+
if (!descriptor.modules) descriptor.modules = [];
|
|
10575
|
+
descriptor.modules.push({ id: d3.id, name: d3.id, path: d3.path, parent_system: sysName, status: "configured" });
|
|
10576
|
+
}
|
|
10577
|
+
}
|
|
10578
|
+
const ymlContent = stringifyYaml4({ version: descriptor.version ?? 1, system: sysName, workspace_roots: workspaceRoots2, modules: descriptor.modules ?? [] });
|
|
10579
|
+
writeDerived(root, ".kaddo/modules.yml", ymlContent);
|
|
10580
|
+
return ok2({ discovered, applied: true });
|
|
10581
|
+
}
|
|
10582
|
+
return ok2({ discovered, applied: false });
|
|
10583
|
+
}
|
|
10351
10584
|
function renderCapsuleMd(data) {
|
|
10352
10585
|
const fm = ["---", `type: knowledge-capsule`, `system: ${data.system}`, `version: ${data.version}`, `updated_at: ${data.updated_at}`, "---", ""].join("\n");
|
|
10353
10586
|
const list2 = (items) => items.length === 0 ? "_To be completed._" : items.map((i) => `- ${i}`).join("\n");
|
|
@@ -10471,15 +10704,16 @@ function buildContextPack(dir, config, now = /* @__PURE__ */ new Date()) {
|
|
|
10471
10704
|
if (!knowledgeSummary) {
|
|
10472
10705
|
missing.push("No project knowledge summary found yet.");
|
|
10473
10706
|
}
|
|
10707
|
+
const moduleRepo = config != null && isModule(config);
|
|
10474
10708
|
const roadmapSummary = readMarkdownSummary(dir, "delivery/roadmap.md") ?? "";
|
|
10475
|
-
if (!roadmapSummary) {
|
|
10709
|
+
if (!roadmapSummary && !moduleRepo) {
|
|
10476
10710
|
missing.push("No roadmap baseline found.");
|
|
10477
10711
|
}
|
|
10478
10712
|
const allArtifacts = discoverKnowledge(dir);
|
|
10479
10713
|
const workItems = allArtifacts.filter(
|
|
10480
10714
|
(a2) => isDeliveryWorkItem(a2) && isActiveState(lifecycleStateOf({ status: a2.status, filePath: a2.filePath }))
|
|
10481
10715
|
);
|
|
10482
|
-
if (workItems.length === 0) {
|
|
10716
|
+
if (workItems.length === 0 && !moduleRepo) {
|
|
10483
10717
|
missing.push("No work items found.");
|
|
10484
10718
|
}
|
|
10485
10719
|
const state = config.project.state;
|
|
@@ -10511,8 +10745,8 @@ function buildContextPack(dir, config, now = /* @__PURE__ */ new Date()) {
|
|
|
10511
10745
|
tech: { status: layerStatusOf("Tech"), artifacts: { "knowledge/tech/codebase.md": qCodebase, "knowledge/tech/current-state.md": qCurrentState } },
|
|
10512
10746
|
delivery: { status: layerStatusOf("Delivery"), artifacts: { "knowledge/delivery/roadmap.md": qRoadmap } }
|
|
10513
10747
|
};
|
|
10514
|
-
if (qBusiness === "placeholder") missing.push("Business context exists but still looks like a bootstrap placeholder.");
|
|
10515
|
-
if (qProduct === "placeholder" || qCapabilities === "placeholder") missing.push("Product capabilities exist but still look like a bootstrap placeholder.");
|
|
10748
|
+
if (qBusiness === "placeholder" && !moduleRepo) missing.push("Business context exists but still looks like a bootstrap placeholder.");
|
|
10749
|
+
if ((qProduct === "placeholder" || qCapabilities === "placeholder") && !moduleRepo) missing.push("Product capabilities exist but still look like a bootstrap placeholder.");
|
|
10516
10750
|
if (qCurrentState === "placeholder") missing.push("Current state exists but still looks like a bootstrap placeholder.");
|
|
10517
10751
|
if (qCodebase === "placeholder") missing.push("Codebase map exists but still looks like a bootstrap placeholder.");
|
|
10518
10752
|
const allWorkItems = allArtifacts.filter((a2) => a2.isWorkItem);
|
|
@@ -10535,7 +10769,8 @@ function buildContextPack(dir, config, now = /* @__PURE__ */ new Date()) {
|
|
|
10535
10769
|
workItemsTotal: allWorkItems.length,
|
|
10536
10770
|
workItemsWithOwnership: wiWithOwnership,
|
|
10537
10771
|
workItemsMissingOwnership: allWorkItems.length - wiWithOwnership
|
|
10538
|
-
}
|
|
10772
|
+
},
|
|
10773
|
+
isModuleRepo: config != null && isModule(config)
|
|
10539
10774
|
});
|
|
10540
10775
|
const nextStepRecommendation = resolveNextStep(dir, now);
|
|
10541
10776
|
const techDecisions = buildTechDecisions(dir);
|
|
@@ -11017,6 +11252,16 @@ function flowForState(state) {
|
|
|
11017
11252
|
}
|
|
11018
11253
|
function buildUnderstandPlan(dir, config) {
|
|
11019
11254
|
const state = config.project.state;
|
|
11255
|
+
if (isModule(config)) {
|
|
11256
|
+
return {
|
|
11257
|
+
project: { name: config.project.name, state, teamSize: config.team.size, structure: config.project.structure, language: "English" },
|
|
11258
|
+
steps: [],
|
|
11259
|
+
missingAgents: [],
|
|
11260
|
+
agentsInstalled: true,
|
|
11261
|
+
scanAvailable: exists(join(dir, ".kaddo", "scan.json")),
|
|
11262
|
+
contextPackPath: ".kaddo/context-pack.md"
|
|
11263
|
+
};
|
|
11264
|
+
}
|
|
11020
11265
|
const flow = flowForState(state).filter((s) => !exists(join(dir, s.output)));
|
|
11021
11266
|
const steps = flow.map((s) => {
|
|
11022
11267
|
const installed = agentIsInstalled(dir, s.agent);
|
|
@@ -11641,6 +11886,18 @@ function createServer(root) {
|
|
|
11641
11886
|
},
|
|
11642
11887
|
async (args) => toolText(guarded(root, () => exportCapsuleTool(root, args)))
|
|
11643
11888
|
);
|
|
11889
|
+
server.registerTool(
|
|
11890
|
+
"kaddo_modules_discover",
|
|
11891
|
+
{
|
|
11892
|
+
title: "Discover multirepo modules",
|
|
11893
|
+
description: "Discover sibling repositories configured as Kaddo modules. Does not persist without apply+confirm. Core only.",
|
|
11894
|
+
inputSchema: {
|
|
11895
|
+
apply: z3.boolean().optional(),
|
|
11896
|
+
confirm: z3.boolean().optional()
|
|
11897
|
+
}
|
|
11898
|
+
},
|
|
11899
|
+
async (args) => toolText(guarded(root, () => modulesDiscoverTool(root, args)))
|
|
11900
|
+
);
|
|
11644
11901
|
let installedSkills = [];
|
|
11645
11902
|
try {
|
|
11646
11903
|
assertKaddoProject(root);
|
package/package.json
CHANGED