@kaddo/cli 3.4.0 → 3.5.1
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 +2 -0
- package/dist/index.js +187 -57
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -436,6 +436,8 @@ create --from roadmap → owners → guard → explain`.
|
|
|
436
436
|
| v3.2 | New-project flow hardening: agents in per-layer folders; `new` recommends capability+architecture agents; explain Work Item parser fix; intent vs reality (codebase vs current-state) |
|
|
437
437
|
| v3.3 | Work Item delivery lifecycle: `understand` shows branch → scan → ownership → guard → knowledge → commit for active Work Items (suggestions only; Kaddo never runs git) |
|
|
438
438
|
| v3.4 | Delivery protocol in the `work-item-agent`: branch first per the Git strategy, commit only with human confirmation (CLI never touches git) |
|
|
439
|
+
| v3.5 | Knowledge discovery by front-matter type with per-layer maturity (explain/understand/context); context pack carries Operating Rules so agents never commit without confirmation |
|
|
440
|
+
| v3.5.1 | Author attribution & knowledge identity: Kaddo as a practical implementation of KDD for AI-assisted development (docs/README) |
|
|
439
441
|
|
|
440
442
|
**Optional modules (installed with `kaddo add`):**
|
|
441
443
|
|
package/dist/index.js
CHANGED
|
@@ -2592,6 +2592,14 @@ var agentReadme = {
|
|
|
2592
2592
|
"",
|
|
2593
2593
|
"**Kaddo does not execute these agents.** The CLI prepares context; the LLM interprets.",
|
|
2594
2594
|
"",
|
|
2595
|
+
"## Operating rules (apply to every agent)",
|
|
2596
|
+
"",
|
|
2597
|
+
"- **Never run `git commit`, `git push` or `git merge` without explicit human confirmation.**",
|
|
2598
|
+
"- Never push or merge automatically. Suggest a Conventional Commit message and wait.",
|
|
2599
|
+
"- When implementing a Work Item, create a branch first (per the Git strategy in",
|
|
2600
|
+
" `.kaddo/git.yml`); never work directly on `main`.",
|
|
2601
|
+
"- The Kaddo CLI never calls an LLM and never runs git \u2014 every git action is the human\u2019s.",
|
|
2602
|
+
"",
|
|
2595
2603
|
"## How to use",
|
|
2596
2604
|
"",
|
|
2597
2605
|
"1. Run `kaddo scan` then `kaddo context` to generate `.kaddo/context-pack.md`.",
|
|
@@ -4263,59 +4271,158 @@ function runIgnoreRemove(artifactId) {
|
|
|
4263
4271
|
import matter2 from "gray-matter";
|
|
4264
4272
|
import { parse as parseYaml8 } from "yaml";
|
|
4265
4273
|
|
|
4266
|
-
// src/core/
|
|
4274
|
+
// src/core/knowledge-discovery.ts
|
|
4267
4275
|
var KNOWLEDGE = "knowledge";
|
|
4268
|
-
var
|
|
4269
|
-
|
|
4270
|
-
|
|
4271
|
-
|
|
4272
|
-
|
|
4273
|
-
|
|
4274
|
-
|
|
4275
|
-
|
|
4276
|
-
|
|
4277
|
-
|
|
4278
|
-
|
|
4279
|
-
|
|
4280
|
-
|
|
4281
|
-
|
|
4282
|
-
|
|
4283
|
-
|
|
4284
|
-
|
|
4285
|
-
|
|
4286
|
-
|
|
4287
|
-
|
|
4288
|
-
|
|
4289
|
-
|
|
4290
|
-
|
|
4291
|
-
|
|
4292
|
-
|
|
4293
|
-
|
|
4294
|
-
|
|
4295
|
-
|
|
4296
|
-
|
|
4297
|
-
|
|
4298
|
-
|
|
4299
|
-
|
|
4276
|
+
var CONSOLIDATED_TYPE = {
|
|
4277
|
+
Business: "business",
|
|
4278
|
+
Product: "product",
|
|
4279
|
+
Tech: "codebase"
|
|
4280
|
+
};
|
|
4281
|
+
var STRUCTURED_TYPES = {
|
|
4282
|
+
Business: /* @__PURE__ */ new Set(["problem", "users", "value-proposition", "business-rules", "constraints", "glossary"]),
|
|
4283
|
+
Product: /* @__PURE__ */ new Set(["product-brief", "capabilities"]),
|
|
4284
|
+
Tech: /* @__PURE__ */ new Set([
|
|
4285
|
+
"current-state",
|
|
4286
|
+
"architecture-notes",
|
|
4287
|
+
"decision-candidates",
|
|
4288
|
+
"quality-attributes",
|
|
4289
|
+
"stack",
|
|
4290
|
+
"standards",
|
|
4291
|
+
"security",
|
|
4292
|
+
"git-strategy",
|
|
4293
|
+
"module-design",
|
|
4294
|
+
"adr",
|
|
4295
|
+
"decision"
|
|
4296
|
+
]),
|
|
4297
|
+
Delivery: /* @__PURE__ */ new Set([])
|
|
4298
|
+
};
|
|
4299
|
+
var WORK_ITEM_TYPES = /* @__PURE__ */ new Set([
|
|
4300
|
+
"work-item",
|
|
4301
|
+
"feature",
|
|
4302
|
+
"bugfix",
|
|
4303
|
+
"hotfix",
|
|
4304
|
+
"spike"
|
|
4305
|
+
]);
|
|
4306
|
+
function layerForType(type) {
|
|
4307
|
+
if (!type) return null;
|
|
4308
|
+
if (type === CONSOLIDATED_TYPE.Business || STRUCTURED_TYPES.Business.has(type)) return "Business";
|
|
4309
|
+
if (type === CONSOLIDATED_TYPE.Product || STRUCTURED_TYPES.Product.has(type)) return "Product";
|
|
4310
|
+
if (type === CONSOLIDATED_TYPE.Tech || STRUCTURED_TYPES.Tech.has(type) || type === "knowledge")
|
|
4311
|
+
return "Tech";
|
|
4312
|
+
if (type === "roadmap" || WORK_ITEM_TYPES.has(type)) return "Delivery";
|
|
4313
|
+
return null;
|
|
4314
|
+
}
|
|
4315
|
+
function layerFromPath(filePath) {
|
|
4316
|
+
const p2 = filePath.replace(/\\/g, "/");
|
|
4317
|
+
if (p2.includes(`/${KNOWLEDGE}/business/`)) return "Business";
|
|
4318
|
+
if (p2.includes(`/${KNOWLEDGE}/product/`)) return "Product";
|
|
4319
|
+
if (p2.includes(`/${KNOWLEDGE}/tech/`)) return "Tech";
|
|
4320
|
+
if (p2.includes(`/${KNOWLEDGE}/delivery/`)) return "Delivery";
|
|
4321
|
+
return null;
|
|
4322
|
+
}
|
|
4323
|
+
function basename(p2) {
|
|
4324
|
+
return p2.replace(/\\/g, "/").split("/").pop() ?? p2;
|
|
4325
|
+
}
|
|
4326
|
+
function discoverLayers(dir) {
|
|
4327
|
+
const acc = {
|
|
4328
|
+
Business: blank(),
|
|
4329
|
+
Product: blank(),
|
|
4330
|
+
Tech: blank(),
|
|
4331
|
+
Delivery: blank()
|
|
4332
|
+
};
|
|
4333
|
+
const archDir = join(dir, KNOWLEDGE);
|
|
4334
|
+
const artifacts = exists(archDir) ? readArtifacts(archDir) : [];
|
|
4335
|
+
for (const a of artifacts) {
|
|
4336
|
+
const type = a.type;
|
|
4337
|
+
const layer = layerForType(type) ?? layerFromPath(a.filePath);
|
|
4338
|
+
if (!layer) continue;
|
|
4339
|
+
const slot = acc[layer];
|
|
4340
|
+
slot.detected.add(basename(a.filePath));
|
|
4341
|
+
if (layer === "Delivery") {
|
|
4342
|
+
if (type === "roadmap" || basename(a.filePath) === "roadmap.md") slot.hasRoadmap = true;
|
|
4343
|
+
if (WORK_ITEM_TYPES.has(type) || a.filePath.replace(/\\/g, "/").includes("/delivery/work-items/")) {
|
|
4344
|
+
if (a.filePath.replace(/\\/g, "/").includes("/delivery/work-items/")) slot.hasWorkItem = true;
|
|
4345
|
+
}
|
|
4346
|
+
continue;
|
|
4347
|
+
}
|
|
4348
|
+
if (type === CONSOLIDATED_TYPE[layer]) slot.consolidated = true;
|
|
4349
|
+
else if (STRUCTURED_TYPES[layer].has(type)) slot.structured = true;
|
|
4350
|
+
else if (!type) {
|
|
4351
|
+
slot.consolidated = true;
|
|
4352
|
+
}
|
|
4353
|
+
if (type === "adr" || type === "decision") slot.hasDecision = true;
|
|
4300
4354
|
}
|
|
4301
|
-
|
|
4302
|
-
|
|
4303
|
-
return LAYER_SPEC.map(({ layer, items }) => ({
|
|
4355
|
+
if (existsDirWithMd(join(dir, KNOWLEDGE, "tech", "decisions"))) acc.Tech.structured = true;
|
|
4356
|
+
return ["Business", "Product", "Tech", "Delivery"].map((layer) => ({
|
|
4304
4357
|
layer,
|
|
4305
|
-
|
|
4358
|
+
status: statusFor(layer, acc[layer]),
|
|
4359
|
+
detected: [...acc[layer].detected].sort()
|
|
4306
4360
|
}));
|
|
4307
4361
|
}
|
|
4362
|
+
function blank() {
|
|
4363
|
+
return {
|
|
4364
|
+
consolidated: false,
|
|
4365
|
+
structured: false,
|
|
4366
|
+
hasRoadmap: false,
|
|
4367
|
+
hasWorkItem: false,
|
|
4368
|
+
hasDecision: false,
|
|
4369
|
+
detected: /* @__PURE__ */ new Set()
|
|
4370
|
+
};
|
|
4371
|
+
}
|
|
4372
|
+
function existsDirWithMd(d) {
|
|
4373
|
+
if (!exists(d)) return false;
|
|
4374
|
+
try {
|
|
4375
|
+
return readDir(d).some((e) => e.endsWith(".md") && isFile(join(d, e)));
|
|
4376
|
+
} catch {
|
|
4377
|
+
return false;
|
|
4378
|
+
}
|
|
4379
|
+
}
|
|
4380
|
+
function statusFor(layer, a) {
|
|
4381
|
+
if (layer === "Delivery") {
|
|
4382
|
+
if (a.hasWorkItem) return "Traceable";
|
|
4383
|
+
if (a.hasRoadmap) return "Partial";
|
|
4384
|
+
return "Missing";
|
|
4385
|
+
}
|
|
4386
|
+
if (a.structured) return "Structured";
|
|
4387
|
+
if (a.consolidated) return "Consolidated";
|
|
4388
|
+
return "Missing";
|
|
4389
|
+
}
|
|
4390
|
+
function roadmapHasUnmaterializedCandidates(dir) {
|
|
4391
|
+
const roadmap = join(dir, KNOWLEDGE, "delivery", "roadmap.md");
|
|
4392
|
+
if (!exists(roadmap)) return false;
|
|
4393
|
+
let hasCandidates = false;
|
|
4394
|
+
try {
|
|
4395
|
+
hasCandidates = /WI-[A-Z0-9-]*\d/i.test(readFile(roadmap));
|
|
4396
|
+
} catch {
|
|
4397
|
+
return false;
|
|
4398
|
+
}
|
|
4399
|
+
if (!hasCandidates) return false;
|
|
4400
|
+
const wiDir = join(dir, KNOWLEDGE, "delivery", "work-items");
|
|
4401
|
+
return !existsDirWithMd(wiDir);
|
|
4402
|
+
}
|
|
4403
|
+
|
|
4404
|
+
// src/core/layers.ts
|
|
4405
|
+
function knowledgeLayers(dir) {
|
|
4406
|
+
return discoverLayers(dir);
|
|
4407
|
+
}
|
|
4408
|
+
var COMPLETE = {
|
|
4409
|
+
Business: (s) => s !== "Missing",
|
|
4410
|
+
Product: (s) => s !== "Missing",
|
|
4411
|
+
Tech: (s) => s !== "Missing",
|
|
4412
|
+
Delivery: (s) => s === "Traceable"
|
|
4413
|
+
};
|
|
4308
4414
|
function currentPhase(layers) {
|
|
4309
|
-
for (const
|
|
4310
|
-
if (
|
|
4415
|
+
for (const l of layers) {
|
|
4416
|
+
if (!COMPLETE[l.layer](l.status)) return l.layer;
|
|
4311
4417
|
}
|
|
4312
4418
|
return "Delivery";
|
|
4313
4419
|
}
|
|
4314
4420
|
function renderLayersMarkdown(layers) {
|
|
4315
4421
|
const lines = [];
|
|
4316
|
-
for (const { layer,
|
|
4317
|
-
lines.push(`### ${layer}`);
|
|
4318
|
-
for (const
|
|
4422
|
+
for (const { layer, status, detected } of layers) {
|
|
4423
|
+
lines.push(`### ${layer} \u2014 ${status}`);
|
|
4424
|
+
if (detected.length > 0) for (const d of detected) lines.push(`- \u2713 ${d}`);
|
|
4425
|
+
else lines.push("- \u2717 none");
|
|
4319
4426
|
lines.push("");
|
|
4320
4427
|
}
|
|
4321
4428
|
return lines.join("\n").trimEnd();
|
|
@@ -4386,14 +4493,16 @@ function buildProjectExplanation(dir) {
|
|
|
4386
4493
|
contractFiles: scan2.contractFiles,
|
|
4387
4494
|
infrastructureFiles: scan2.infrastructureFiles
|
|
4388
4495
|
} : null;
|
|
4496
|
+
const layers = knowledgeLayers(dir);
|
|
4497
|
+
const layerStatus = (name) => layers.find((l) => l.layer === name)?.status ?? "Missing";
|
|
4389
4498
|
const knowledge = {
|
|
4390
4499
|
hasScan: scan2 !== null,
|
|
4391
4500
|
hasInventory: exists(join(dir, ARCH_DIR3, "inventory.md")),
|
|
4392
4501
|
hasContextPack: exists(join(dir, ".kaddo", "context-pack.md")),
|
|
4393
4502
|
hasUnderstand: exists(join(dir, ".kaddo", "understand.md")),
|
|
4394
|
-
hasCapabilities:
|
|
4395
|
-
hasArchitecture:
|
|
4396
|
-
hasRoadmap:
|
|
4503
|
+
hasCapabilities: layerStatus("Product") !== "Missing",
|
|
4504
|
+
hasArchitecture: layerStatus("Tech") !== "Missing",
|
|
4505
|
+
hasRoadmap: layerStatus("Delivery") !== "Missing",
|
|
4397
4506
|
hasAgents: hasAgents(dir)
|
|
4398
4507
|
};
|
|
4399
4508
|
const archDir = join(dir, ARCH_DIR3);
|
|
@@ -4429,10 +4538,8 @@ function buildProjectExplanation(dir) {
|
|
|
4429
4538
|
if (!knowledge.hasScan) missingKnowledge.push("Scan baseline (.kaddo/scan.json)");
|
|
4430
4539
|
if (!knowledge.hasContextPack) missingKnowledge.push("Context pack (.kaddo/context-pack.md)");
|
|
4431
4540
|
if (!knowledge.hasInventory) missingKnowledge.push("Inventory (knowledge/inventory.md)");
|
|
4432
|
-
if (!knowledge.hasCapabilities)
|
|
4433
|
-
|
|
4434
|
-
if (!knowledge.hasArchitecture)
|
|
4435
|
-
missingKnowledge.push("Architecture baseline (knowledge/tech/current-state.md)");
|
|
4541
|
+
if (!knowledge.hasCapabilities) missingKnowledge.push("Product knowledge (knowledge/product/)");
|
|
4542
|
+
if (!knowledge.hasArchitecture) missingKnowledge.push("Tech knowledge (knowledge/tech/)");
|
|
4436
4543
|
if (!knowledge.hasRoadmap) missingKnowledge.push("Roadmap (knowledge/delivery/roadmap.md)");
|
|
4437
4544
|
if (!knowledge.hasAgents) missingKnowledge.push("Agents (knowledge/agents/)");
|
|
4438
4545
|
if (items.length === 0) missingKnowledge.push("Work items (knowledge/delivery/work-items/)");
|
|
@@ -4468,7 +4575,7 @@ function buildProjectExplanation(dir) {
|
|
|
4468
4575
|
workItems,
|
|
4469
4576
|
ownership,
|
|
4470
4577
|
domains,
|
|
4471
|
-
layers
|
|
4578
|
+
layers,
|
|
4472
4579
|
mappedModules,
|
|
4473
4580
|
missingKnowledge,
|
|
4474
4581
|
suggestedNextSteps
|
|
@@ -4503,14 +4610,14 @@ function renderExplanationHuman(exp) {
|
|
|
4503
4610
|
lines.push(`- Infrastructure: ${exp.stack.infrastructureFiles.join(", ")}`);
|
|
4504
4611
|
lines.push("");
|
|
4505
4612
|
}
|
|
4613
|
+
const ls = (name) => exp.layers.find((l) => l.layer === name)?.status ?? "Missing";
|
|
4506
4614
|
lines.push("## Knowledge Status");
|
|
4507
4615
|
lines.push(`- Inventory: ${exp.knowledge.hasInventory ? "available" : "missing"}`);
|
|
4508
4616
|
lines.push(`- Context pack: ${exp.knowledge.hasContextPack ? "available" : "missing"}`);
|
|
4509
|
-
lines.push(`-
|
|
4510
|
-
lines.push(
|
|
4511
|
-
|
|
4512
|
-
);
|
|
4513
|
-
lines.push(`- Roadmap: ${exp.knowledge.hasRoadmap ? "available" : "missing"}`);
|
|
4617
|
+
lines.push(`- Business: ${ls("Business")}`);
|
|
4618
|
+
lines.push(`- Product: ${ls("Product")}`);
|
|
4619
|
+
lines.push(`- Tech: ${ls("Tech")}`);
|
|
4620
|
+
lines.push(`- Delivery: ${ls("Delivery")}`);
|
|
4514
4621
|
lines.push(`- Agents: ${exp.knowledge.hasAgents ? "available" : "missing"}`);
|
|
4515
4622
|
lines.push(`- Work items: ${exp.workItems.total}`);
|
|
4516
4623
|
lines.push(
|
|
@@ -4818,6 +4925,13 @@ var LLM_INSTRUCTIONS = [
|
|
|
4818
4925
|
"First extract: system capabilities, architecture notes, risks, open questions and roadmap candidates.",
|
|
4819
4926
|
"This pack is deterministic CLI output \u2014 it does not interpret the system. That is your job."
|
|
4820
4927
|
];
|
|
4928
|
+
var OPERATING_RULES = [
|
|
4929
|
+
"**Never run `git commit`, `git push` or `git merge` without explicit human confirmation.**",
|
|
4930
|
+
"Never push or merge automatically \u2014 ever. Suggest a Conventional Commit message and wait.",
|
|
4931
|
+
"When implementing a Work Item, create a branch FIRST (per the project Git strategy, `.kaddo/git.yml`, default `feature/<id>-<slug>`). Never work directly on `main`.",
|
|
4932
|
+
"After significant changes run `kaddo scan`, `kaddo owners suggest` and `kaddo guard`, and update the affected knowledge (ADR / capabilities / current-state).",
|
|
4933
|
+
"Kaddo itself never calls an LLM and never runs git \u2014 every git action is the human\u2019s."
|
|
4934
|
+
];
|
|
4821
4935
|
function toContextWorkItem(a) {
|
|
4822
4936
|
return {
|
|
4823
4937
|
id: a.id,
|
|
@@ -4893,7 +5007,8 @@ function buildContextPack(dir, config, now = /* @__PURE__ */ new Date()) {
|
|
|
4893
5007
|
handoff: {
|
|
4894
5008
|
recommendedAgents: recommendedAgentsForState(state),
|
|
4895
5009
|
nextSteps: nextStepsForState2(state),
|
|
4896
|
-
instructions: LLM_INSTRUCTIONS
|
|
5010
|
+
instructions: LLM_INSTRUCTIONS,
|
|
5011
|
+
operatingRules: OPERATING_RULES
|
|
4897
5012
|
}
|
|
4898
5013
|
};
|
|
4899
5014
|
}
|
|
@@ -4912,6 +5027,8 @@ function renderContextPack(pack) {
|
|
|
4912
5027
|
parts.push(
|
|
4913
5028
|
"> Generated by `kaddo context`. Deterministic CLI output \u2014 not an interpretation of the system.\n"
|
|
4914
5029
|
);
|
|
5030
|
+
parts.push("## Operating Rules (read first)\n");
|
|
5031
|
+
parts.push(handoff.operatingRules.map((r) => `- ${r}`).join("\n") + "\n");
|
|
4915
5032
|
parts.push("## Project Metadata\n");
|
|
4916
5033
|
parts.push(
|
|
4917
5034
|
[
|
|
@@ -4925,6 +5042,9 @@ function renderContextPack(pack) {
|
|
|
4925
5042
|
parts.push(
|
|
4926
5043
|
"Project knowledge is organized in four layers: **Business \u2192 Product \u2192 Tech \u2192 Delivery**.\n"
|
|
4927
5044
|
);
|
|
5045
|
+
const maturity = pack.layers.map((l) => `${l.layer}: ${l.status}`).join(" \xB7 ");
|
|
5046
|
+
parts.push(`Knowledge maturity \u2014 ${maturity}
|
|
5047
|
+
`);
|
|
4928
5048
|
parts.push(renderLayersMarkdown(pack.layers) + "\n");
|
|
4929
5049
|
parts.push("## Technical Inventory\n");
|
|
4930
5050
|
if (scan2.available) {
|
|
@@ -5318,6 +5438,12 @@ function runUnderstand() {
|
|
|
5318
5438
|
],
|
|
5319
5439
|
utilities: ["Use legacy-agent to surface risks and unknowns"]
|
|
5320
5440
|
};
|
|
5441
|
+
if (roadmapHasUnmaterializedCandidates(dir)) {
|
|
5442
|
+
console.log("");
|
|
5443
|
+
console.log("The roadmap has Work Item candidates that are not materialized yet.");
|
|
5444
|
+
console.log(" \u2192 Run `kaddo create --from roadmap`, or use the work-item-agent to");
|
|
5445
|
+
console.log(" materialize them into knowledge/delivery/work-items/.");
|
|
5446
|
+
}
|
|
5321
5447
|
console.log("");
|
|
5322
5448
|
console.log(`Current phase: ${phase}`);
|
|
5323
5449
|
console.log("Recommended next steps:");
|
|
@@ -8008,6 +8134,10 @@ async function runBootstrap(dir = cwd()) {
|
|
|
8008
8134
|
for (const p2 of result.skipped) console.log(` - ${p2}`);
|
|
8009
8135
|
}
|
|
8010
8136
|
console.log("");
|
|
8137
|
+
console.log("");
|
|
8138
|
+
log2.info(
|
|
8139
|
+
"When you pass the context pack to your LLM/coding agent, it must never commit, push or merge without your confirmation \u2014 and create a branch before implementing."
|
|
8140
|
+
);
|
|
8011
8141
|
outro2(
|
|
8012
8142
|
"Minimal knowledge base ready (Business \u2192 Product \u2192 Tech). Run `kaddo context` and `kaddo add agents`, then refine with the business-agent, bootstrap-agent and codebase-agent. Roadmap and work items come next under knowledge/delivery/."
|
|
8013
8143
|
);
|
|
@@ -8015,7 +8145,7 @@ async function runBootstrap(dir = cwd()) {
|
|
|
8015
8145
|
|
|
8016
8146
|
// src/index.ts
|
|
8017
8147
|
var program = new Command();
|
|
8018
|
-
program.name("kaddo").description("Knowledge Driven Development toolkit").version("3.
|
|
8148
|
+
program.name("kaddo").description("Knowledge Driven Development toolkit").version("3.5.1");
|
|
8019
8149
|
program.command("init").description("Initialize Kaddo in the current project").action(async () => {
|
|
8020
8150
|
await runInit();
|
|
8021
8151
|
});
|