kibi-cli 2.21.0 → 2.22.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/cli-operation-metadata.d.ts +1 -1
- package/dist/cli-operation-metadata.js +1 -1
- package/dist/cli-register-foundation.d.ts.map +1 -1
- package/dist/cli-register-foundation.js +1 -0
- package/dist/commands/check.d.ts +0 -1
- package/dist/commands/check.d.ts.map +1 -1
- package/dist/commands/check.js +47 -111
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +107 -5
- package/dist/commands/init-helpers.d.ts +14 -1
- package/dist/commands/init-helpers.d.ts.map +1 -1
- package/dist/commands/init-helpers.js +49 -10
- package/dist/commands/init.d.ts +1 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +27 -4
- package/dist/commands/legacy-storage-migration.d.ts +46 -1
- package/dist/commands/legacy-storage-migration.d.ts.map +1 -1
- package/dist/commands/legacy-storage-migration.js +244 -9
- package/dist/commands/migrate.d.ts.map +1 -1
- package/dist/commands/migrate.js +150 -166
- package/dist/commands/sync/manifest.d.ts.map +1 -1
- package/dist/commands/sync/manifest.js +9 -0
- package/dist/commands/sync/persistence.d.ts.map +1 -1
- package/dist/commands/sync/persistence.js +4 -0
- package/dist/decision-firmness.d.ts +39 -0
- package/dist/decision-firmness.d.ts.map +1 -0
- package/dist/decision-firmness.js +115 -0
- package/dist/extractors/markdown.d.ts +2 -0
- package/dist/extractors/markdown.d.ts.map +1 -1
- package/dist/extractors/markdown.js +14 -0
- package/dist/extractors/symbols-coordinator.js +1 -0
- package/dist/intent-search.d.ts.map +1 -1
- package/dist/intent-search.js +28 -6
- package/dist/operations/migration/inventory-rederive.d.ts +40 -1
- package/dist/operations/migration/inventory-rederive.d.ts.map +1 -1
- package/dist/operations/migration/inventory-rederive.js +99 -8
- package/dist/operations/migration/requirement-status.d.ts +25 -0
- package/dist/operations/migration/requirement-status.d.ts.map +1 -0
- package/dist/operations/migration/requirement-status.js +105 -0
- package/dist/operations/migration/schema6.d.ts +27 -0
- package/dist/operations/migration/schema6.d.ts.map +1 -1
- package/dist/operations/migration/schema6.js +308 -7
- package/dist/operations/migration/supersedes-reason.d.ts +26 -0
- package/dist/operations/migration/supersedes-reason.d.ts.map +1 -0
- package/dist/operations/migration/supersedes-reason.js +69 -0
- package/dist/operations/migration/symbol-legacy-links.d.ts +51 -0
- package/dist/operations/migration/symbol-legacy-links.d.ts.map +1 -0
- package/dist/operations/migration/symbol-legacy-links.js +319 -0
- package/dist/operations/modeling/predicate-applyplan.d.ts.map +1 -1
- package/dist/operations/modeling/predicate-applyplan.js +10 -2
- package/dist/operations/modeling/predicate-loader.d.ts.map +1 -1
- package/dist/operations/modeling/predicate-loader.js +11 -0
- package/dist/operations/modeling/predicate-types.d.ts +32 -1
- package/dist/operations/modeling/predicate-types.d.ts.map +1 -1
- package/dist/operations/modeling/suggest-predicates.d.ts.map +1 -1
- package/dist/operations/modeling/suggest-predicates.js +175 -35
- package/dist/operations/mutation/context-warning.d.ts +12 -2
- package/dist/operations/mutation/context-warning.d.ts.map +1 -1
- package/dist/operations/mutation/context-warning.js +6 -6
- package/dist/operations/mutation/delete.d.ts +5 -1
- package/dist/operations/mutation/delete.d.ts.map +1 -1
- package/dist/operations/mutation/delete.js +223 -17
- package/dist/operations/mutation/serialization.d.ts.map +1 -1
- package/dist/operations/mutation/serialization.js +1 -0
- package/dist/operations/mutation/source-authoring.d.ts.map +1 -1
- package/dist/operations/mutation/source-authoring.js +130 -35
- package/dist/operations/mutation/types.d.ts +39 -1
- package/dist/operations/mutation/types.d.ts.map +1 -1
- package/dist/operations/mutation/upsert.d.ts +17 -2
- package/dist/operations/mutation/upsert.d.ts.map +1 -1
- package/dist/operations/mutation/upsert.js +82 -13
- package/dist/operations/mutation/validate-upsert.d.ts.map +1 -1
- package/dist/operations/mutation/validate-upsert.js +40 -8
- package/dist/operations/planning/apply-plan.d.ts +6 -1
- package/dist/operations/planning/apply-plan.d.ts.map +1 -1
- package/dist/operations/planning/apply-plan.js +26 -5
- package/dist/public/impact/diagnostics.d.ts.map +1 -1
- package/dist/public/impact/diagnostics.js +24 -14
- package/dist/public/operations/catalog.d.ts +14 -5
- package/dist/public/operations/catalog.d.ts.map +1 -1
- package/dist/public/operations/check-executor.d.ts.map +1 -1
- package/dist/public/operations/check-executor.js +6 -0
- package/dist/public/operations/contracts.d.ts.map +1 -1
- package/dist/public/operations/contracts.js +35 -2
- package/dist/public/operations/decision-firmness.d.ts +34 -0
- package/dist/public/operations/decision-firmness.d.ts.map +1 -0
- package/dist/public/operations/decision-firmness.js +216 -0
- package/dist/public/operations/discovery-executors.d.ts +2 -0
- package/dist/public/operations/discovery-executors.d.ts.map +1 -1
- package/dist/public/operations/discovery-executors.js +25 -4
- package/dist/public/operations/migration-plan.d.ts +2 -0
- package/dist/public/operations/migration-plan.d.ts.map +1 -1
- package/dist/public/operations/migration-plan.js +101 -16
- package/dist/public/operations/result-envelope.d.ts.map +1 -1
- package/dist/public/operations/result-envelope.js +27 -1
- package/dist/public/operations/specs/check-rules.generated.d.ts +1 -1
- package/dist/public/operations/specs/check-rules.generated.d.ts.map +1 -1
- package/dist/public/operations/specs/check-rules.generated.js +6 -1
- package/dist/public/operations/specs/check.d.ts +1 -1
- package/dist/public/operations/specs/mutation-schemas.d.ts +5 -0
- package/dist/public/operations/specs/mutation-schemas.d.ts.map +1 -1
- package/dist/public/operations/specs/mutation-schemas.js +5 -0
- package/dist/public/operations/specs/mutation.d.ts +6 -2
- package/dist/public/operations/specs/mutation.d.ts.map +1 -1
- package/dist/public/operations/specs/mutation.js +6 -2
- package/dist/public/operations/specs/planning.d.ts +2 -2
- package/dist/public/operations/specs/planning.js +2 -2
- package/dist/public/operations/specs/upsert.d.ts +5 -0
- package/dist/public/operations/specs/upsert.d.ts.map +1 -1
- package/dist/public/operations/symbol-granularity-check.d.ts +18 -0
- package/dist/public/operations/symbol-granularity-check.d.ts.map +1 -0
- package/dist/public/operations/symbol-granularity-check.js +175 -0
- package/dist/public/schemas/entity.d.ts.map +1 -1
- package/dist/public/schemas/entity.js +11 -0
- package/dist/public/skills/kibi-traceability/SKILL.md +6 -4
- package/dist/public/skills/kibi-usage/SKILL.md +50 -10
- package/dist/public/skills/kibi-usage/resources/source-authoring.md +4 -2
- package/dist/public/symbol-granularity.d.ts +17 -0
- package/dist/public/symbol-granularity.d.ts.map +1 -1
- package/dist/public/symbol-granularity.js +21 -0
- package/dist/relationships/shards.d.ts +10 -0
- package/dist/relationships/shards.d.ts.map +1 -1
- package/dist/relationships/shards.js +27 -11
- package/dist/schemas/entity.schema.json +28 -0
- package/dist/search-answer.d.ts +31 -2
- package/dist/search-answer.d.ts.map +1 -1
- package/dist/search-answer.js +115 -17
- package/dist/traceability/evidence-model.d.ts +7 -3
- package/dist/traceability/evidence-model.d.ts.map +1 -1
- package/dist/traceability/staged-symbols-manifest.js +6 -5
- package/dist/traceability/validate.d.ts +14 -1
- package/dist/traceability/validate.d.ts.map +1 -1
- package/dist/traceability/validate.js +41 -0
- package/dist/types/entities.d.ts +4 -0
- package/dist/types/entities.d.ts.map +1 -1
- package/dist/utils/kb-manifest.d.ts +6 -0
- package/dist/utils/kb-manifest.d.ts.map +1 -1
- package/dist/utils/kb-manifest.js +6 -0
- package/dist/utils/rule-registry.generated.d.ts +26 -0
- package/dist/utils/rule-registry.generated.d.ts.map +1 -1
- package/dist/utils/rule-registry.generated.js +31 -0
- package/dist/utils/schema-version.d.ts +1 -1
- package/dist/utils/schema-version.d.ts.map +1 -1
- package/dist/utils/schema-version.js +3 -1
- package/package.json +3 -3
- package/schema/entities.pl +6 -0
- package/src/public/impact/diagnostics.ts +29 -17
- package/src/public/operations/check-executor.ts +13 -0
- package/src/public/operations/contracts.ts +39 -2
- package/src/public/operations/decision-firmness.ts +280 -0
- package/src/public/operations/discovery-executors.ts +29 -4
- package/src/public/operations/migration-plan.ts +100 -19
- package/src/public/operations/result-envelope.ts +34 -1
- package/src/public/operations/specs/check-rules.generated.ts +6 -1
- package/src/public/operations/specs/mutation-schemas.ts +6 -0
- package/src/public/operations/specs/mutation.ts +7 -2
- package/src/public/operations/specs/planning.ts +2 -2
- package/src/public/operations/symbol-granularity-check.ts +233 -0
- package/src/public/schemas/entity.ts +12 -0
- package/src/public/skills/kibi-traceability/SKILL.md +6 -4
- package/src/public/skills/kibi-usage/SKILL.md +50 -10
- package/src/public/skills/kibi-usage/resources/source-authoring.md +4 -2
- package/src/public/symbol-granularity.ts +37 -0
- package/src/schemas/entity.schema.json +28 -0
|
@@ -75,7 +75,7 @@ export declare const CLI_OPERATION_METADATA: readonly [{
|
|
|
75
75
|
}, {
|
|
76
76
|
readonly name: "kb_delete";
|
|
77
77
|
readonly cliName: "delete";
|
|
78
|
-
readonly description: "Delete entities by ID. Use only for intentional removals after dependency checks. Do not use as a bulk cleanup shortcut. Side effects: mutates and saves KB; skips entities with dependents.";
|
|
78
|
+
readonly description: "Delete entities by ID, or exact relationship triples. Use only for intentional removals after dependency checks. Do not use as a bulk cleanup shortcut. An entity authored in a Markdown or YAML source is not deleted directly: the call writes nothing and returns outcome plan_returned with a hash-bound deletionPlan and a nextActions entry holding the exact kb_apply_plan input ({plan, approvedPlanHash}); apply that unmodified, or repeat this call with approvedPlanHash = deletionPlan.planHash to apply the freshly computed plan in one step (a stale or different hash fails with DELETE_PLAN_HASH_MISMATCH and writes nothing). Authored requirements are never deleted: outcome supersession_required points to kb_upsert with a supersedes relationship. dryRun:true previews any delete and writes nothing. Side effects: mutates and saves KB and authored sources; skips entities with dependents; dryRun and plan_returned write nothing.";
|
|
79
79
|
}, {
|
|
80
80
|
readonly name: "kb_check";
|
|
81
81
|
readonly cliName: "check";
|
|
@@ -90,7 +90,7 @@ export const CLI_OPERATION_METADATA = [
|
|
|
90
90
|
{
|
|
91
91
|
name: "kb_delete",
|
|
92
92
|
cliName: "delete",
|
|
93
|
-
description: "Delete entities by ID. Use only for intentional removals after dependency checks. Do not use as a bulk cleanup shortcut. Side effects: mutates and saves KB; skips entities with dependents.",
|
|
93
|
+
description: "Delete entities by ID, or exact relationship triples. Use only for intentional removals after dependency checks. Do not use as a bulk cleanup shortcut. An entity authored in a Markdown or YAML source is not deleted directly: the call writes nothing and returns outcome plan_returned with a hash-bound deletionPlan and a nextActions entry holding the exact kb_apply_plan input ({plan, approvedPlanHash}); apply that unmodified, or repeat this call with approvedPlanHash = deletionPlan.planHash to apply the freshly computed plan in one step (a stale or different hash fails with DELETE_PLAN_HASH_MISMATCH and writes nothing). Authored requirements are never deleted: outcome supersession_required points to kb_upsert with a supersedes relationship. dryRun:true previews any delete and writes nothing. Side effects: mutates and saves KB and authored sources; skips entities with dependents; dryRun and plan_returned write nothing.",
|
|
94
94
|
},
|
|
95
95
|
{
|
|
96
96
|
name: "kb_check",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli-register-foundation.d.ts","sourceRoot":"","sources":["../src/cli-register-foundation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAezC,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"cli-register-foundation.d.ts","sourceRoot":"","sources":["../src/cli-register-foundation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAezC,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAyJjE"}
|
|
@@ -12,6 +12,7 @@ export function registerFoundationCommands(program) {
|
|
|
12
12
|
.option("--no-hooks", "Do not install git hooks (hooks installed by default)")
|
|
13
13
|
.option("--github", "Scaffold the GitHub Pages badge + requirement-health report workflow")
|
|
14
14
|
.option("--badge-only", "With --github, publish only the badge (opt out of the full report)")
|
|
15
|
+
.option("--print-hook <hook>", "Print a snippet that delegates an existing hook (pre-commit, post-checkout, post-merge, post-rewrite) to kibi, and write nothing")
|
|
15
16
|
.action(withExitCode(async (options) => (await import("./commands/init.js")).initCommand(options)));
|
|
16
17
|
program
|
|
17
18
|
.command("migrate")
|
package/dist/commands/check.d.ts
CHANGED
|
@@ -25,5 +25,4 @@ export declare function checkDomainContradictions(prolog: PrologProcess): Promis
|
|
|
25
25
|
export declare function checkStrictFactShape(prolog: PrologProcess): Promise<Violation[]>;
|
|
26
26
|
export declare function checkStrictReqFactPairing(prolog: PrologProcess): Promise<Violation[]>;
|
|
27
27
|
export declare function checkStrictReadiness(prolog: PrologProcess): Promise<Violation[]>;
|
|
28
|
-
export declare function checkSymbolCoverage(prolog: PrologProcess): Promise<Violation[]>;
|
|
29
28
|
//# sourceMappingURL=check.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../src/commands/check.ts"],"names":[],"mappings":"AAqCA,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../src/commands/check.ts"],"names":[],"mappings":"AAqCA,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAgF7C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAE3D,YAAY,EAAE,SAAS,EAAE,CAAC;AAE1B,MAAM,WAAW,YAAY;IAC3B,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC3B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CAC1B;AA8gBD,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,CAAC,EACtC,MAAM,EAAE,CAAC,GAAG,IAAI,GAAG,SAAS,EAC5B,MAAM,EAAE,CAAC,GAAG,IAAI,GAAG,SAAS,GAC3B,WAAW,CAAC,CAAC,GAAG,CAAC,CAAC,CAMpB;AAGD,wBAAsB,YAAY,CAChC,OAAO,EAAE,YAAY,GACpB,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAqlB/B;AAED,wBAAsB,yBAAyB,CAC7C,MAAM,EAAE,aAAa,GACpB,OAAO,CAAC,SAAS,EAAE,CAAC,CAoDtB;AAID,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,aAAa,GACpB,OAAO,CAAC,MAAM,EAAE,CAAC,CAgBnB;AAED,wBAAsB,eAAe,CACnC,MAAM,EAAE,aAAa,EACrB,IAAI,CAAC,EAAE,MAAM,GACZ,OAAO,CAAC,MAAM,EAAE,CAAC,CAiBnB;AAED,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,aAAa,GACpB,OAAO,CAAC,SAAS,EAAE,CAAC,CAkEtB;AAID,wBAAsB,aAAa,CACjC,MAAM,EAAE,aAAa,GACpB,OAAO,CAAC,SAAS,EAAE,CAAC,CAmGtB;AAED,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,aAAa,EACrB,YAAY,EAAE,MAAM,EAAE,GACrB,OAAO,CAAC,SAAS,EAAE,CAAC,CAyCtB;AAED,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,aAAa,GACpB,OAAO,CAAC,SAAS,EAAE,CAAC,CAgDtB;AAED,wBAAsB,yBAAyB,CAC7C,MAAM,EAAE,aAAa,GACpB,OAAO,CAAC,SAAS,EAAE,CAAC,CA0BtB;AAED,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,aAAa,GACpB,OAAO,CAAC,SAAS,EAAE,CAAC,CAqBtB;AAED,wBAAsB,yBAAyB,CAC7C,MAAM,EAAE,aAAa,GACpB,OAAO,CAAC,SAAS,EAAE,CAAC,CAqBtB;AAED,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,aAAa,GACpB,OAAO,CAAC,SAAS,EAAE,CAAC,CAqBtB"}
|
package/dist/commands/check.js
CHANGED
|
@@ -41,7 +41,7 @@ import { classifyKibiImpactEvidence, isBehaviorSourceEdit, parseKibiImpactOverri
|
|
|
41
41
|
import { assessStagedSymbolsManifest, collectStagedAuthoredSymbolsManifestEvidence, } from "../traceability/staged-symbols-manifest.js";
|
|
42
42
|
import { createManifestLookupSentinelKey, extractSymbolsFromStagedFileAsync, } from "../traceability/symbol-extract.js";
|
|
43
43
|
import { cleanupTempKb, consultOverlay, createOverlayFacts, createTempKb, projectStagedEntities, } from "../traceability/temp-kb.js";
|
|
44
|
-
import { formatViolations as formatStagedViolations, validateStagedSymbols, } from "../traceability/validate.js";
|
|
44
|
+
import { formatCoverageViolations, formatViolations as formatStagedViolations, validateStagedSymbolCoverage, validateStagedSymbols, } from "../traceability/validate.js";
|
|
45
45
|
import { resolveReadBranchAttachment } from "../utils/branch-resolver.js";
|
|
46
46
|
import { CANONICAL_ENTITY_PATHS, isEntityLanePath } from "../utils/kb-paths.js";
|
|
47
47
|
import { safeCleanupProlog } from "../utils/prolog-cleanup.js";
|
|
@@ -708,122 +708,82 @@ export async function checkCommand(options) {
|
|
|
708
708
|
: {}),
|
|
709
709
|
symbolsByFile,
|
|
710
710
|
}), ...createSemanticReviewDiagnostics({ symbolsByFile }), ...createStagedEntityIdStyleDiagnostics(markdownFiles));
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
}
|
|
729
|
-
return { exitCode: blocking ? 1 : 0 };
|
|
730
|
-
}
|
|
731
|
-
printSnapshotResult({
|
|
732
|
-
format: options.format,
|
|
733
|
-
coverage: stagedCoverage,
|
|
734
|
-
messages: [noValidatedSymbolsMessage(sourceAnalysis)],
|
|
711
|
+
// Run the Prolog rules over the staged knowledge: the minLinks
|
|
712
|
+
// ownership gate for changed source symbols, and full-check
|
|
713
|
+
// symbol-coverage for every changed symbol (changed source symbols
|
|
714
|
+
// plus symbols whose staged manifest entry changed).
|
|
715
|
+
let violationsRaw = [];
|
|
716
|
+
let coverageViolations = [];
|
|
717
|
+
if (allSymbols.length > 0 || activeStagedSymbolEntityIds.size > 0) {
|
|
718
|
+
tempCtx = await createTempKb();
|
|
719
|
+
await projectStagedEntities(tempCtx.prolog, snapshotEntities);
|
|
720
|
+
const overlayFacts = createOverlayFacts(allSymbols);
|
|
721
|
+
const fs = await import("node:fs/promises");
|
|
722
|
+
await fs.writeFile(tempCtx.overlayPath, overlayFacts, "utf8");
|
|
723
|
+
await fs.cp(tempCtx.overlayPath, path.join(tempCtx.kbPath, "changed_symbols.pl"));
|
|
724
|
+
await consultOverlay(tempCtx);
|
|
725
|
+
violationsRaw = await validateStagedSymbols({
|
|
726
|
+
minLinks,
|
|
727
|
+
prolog: tempCtx.prolog,
|
|
735
728
|
});
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
if (stagedKibiDiagnostics.length > 0) {
|
|
740
|
-
const blocking = hasBlockingImpactDiagnostics(stagedKibiDiagnostics);
|
|
741
|
-
printStagedResult({
|
|
742
|
-
format: options.format,
|
|
743
|
-
coverage: stagedCoverage,
|
|
744
|
-
qualityDiagnostics: stagedKibiDiagnostics,
|
|
745
|
-
messages: [
|
|
746
|
-
formatStagedKibiDiagnostics(stagedKibiDiagnostics),
|
|
747
|
-
// Advisory-only findings still pass; say so explicitly.
|
|
748
|
-
...(!blocking
|
|
749
|
-
? ["✓ No violations found in staged files."]
|
|
750
|
-
: []),
|
|
751
|
-
],
|
|
752
|
-
});
|
|
753
|
-
if (options.dryRun) {
|
|
754
|
-
return { exitCode: 0 };
|
|
755
|
-
}
|
|
756
|
-
return { exitCode: blocking ? 1 : 0 };
|
|
757
|
-
}
|
|
758
|
-
printSnapshotResult({
|
|
759
|
-
format: options.format,
|
|
760
|
-
coverage: stagedCoverage,
|
|
761
|
-
messages: ["✓ No violations found in staged files."],
|
|
729
|
+
coverageViolations = await validateStagedSymbolCoverage({
|
|
730
|
+
prolog: tempCtx.prolog,
|
|
731
|
+
extraSymbolIds: [...activeStagedSymbolEntityIds],
|
|
762
732
|
});
|
|
763
|
-
|
|
733
|
+
await cleanupTempKb(tempCtx.tempDir);
|
|
764
734
|
}
|
|
765
|
-
//
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
const
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
const violationsRaw = await validateStagedSymbols({
|
|
774
|
-
minLinks,
|
|
775
|
-
prolog: tempCtx.prolog,
|
|
776
|
-
});
|
|
777
|
-
const violationsFormatted = formatStagedViolations(violationsRaw);
|
|
778
|
-
if (violationsRaw && violationsRaw.length > 0) {
|
|
779
|
-
printSnapshotResult({
|
|
735
|
+
// Without changed source symbols the result was historically printed
|
|
736
|
+
// without re-asserting the snapshot; keep that behavior.
|
|
737
|
+
const print = allSymbols.length === 0 ? printStagedResult : printSnapshotResult;
|
|
738
|
+
const passMessage = allSymbols.length === 0
|
|
739
|
+
? "✓ No violations found in staged files."
|
|
740
|
+
: "✓ No violations found in staged symbols.";
|
|
741
|
+
if (violationsRaw.length > 0 || coverageViolations.length > 0) {
|
|
742
|
+
print({
|
|
780
743
|
format: options.format,
|
|
781
744
|
coverage: stagedCoverage,
|
|
782
|
-
violations: violationsRaw,
|
|
745
|
+
violations: [...violationsRaw, ...coverageViolations],
|
|
783
746
|
qualityDiagnostics: stagedKibiDiagnostics,
|
|
784
747
|
messages: [
|
|
785
748
|
...(stagedKibiDiagnostics.length > 0
|
|
786
749
|
? [formatStagedKibiDiagnostics(stagedKibiDiagnostics)]
|
|
787
750
|
: []),
|
|
788
|
-
|
|
751
|
+
...(coverageViolations.length > 0
|
|
752
|
+
? [formatCoverageViolations(coverageViolations)]
|
|
753
|
+
: []),
|
|
754
|
+
...(violationsRaw.length > 0
|
|
755
|
+
? [formatStagedViolations(violationsRaw)]
|
|
756
|
+
: []),
|
|
789
757
|
],
|
|
790
758
|
});
|
|
791
|
-
|
|
792
|
-
if (options.dryRun) {
|
|
793
|
-
return { exitCode: 0 };
|
|
794
|
-
}
|
|
795
|
-
return { exitCode: 1 };
|
|
759
|
+
return { exitCode: options.dryRun ? 0 : 1 };
|
|
796
760
|
}
|
|
797
761
|
if (stagedKibiDiagnostics.length > 0) {
|
|
798
|
-
await cleanupTempKb(tempCtx.tempDir);
|
|
799
762
|
const blocking = hasBlockingImpactDiagnostics(stagedKibiDiagnostics);
|
|
800
|
-
|
|
763
|
+
print({
|
|
801
764
|
format: options.format,
|
|
802
765
|
coverage: stagedCoverage,
|
|
803
766
|
qualityDiagnostics: stagedKibiDiagnostics,
|
|
804
767
|
messages: [
|
|
805
768
|
formatStagedKibiDiagnostics(stagedKibiDiagnostics),
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
: []),
|
|
769
|
+
// Advisory-only findings still pass; say so explicitly.
|
|
770
|
+
...(!blocking ? [passMessage] : []),
|
|
809
771
|
],
|
|
810
772
|
});
|
|
811
773
|
if (options.dryRun) {
|
|
812
774
|
return { exitCode: 0 };
|
|
813
775
|
}
|
|
814
|
-
|
|
815
|
-
return { exitCode: 0 };
|
|
816
|
-
}
|
|
817
|
-
return {
|
|
818
|
-
exitCode: 1,
|
|
819
|
-
};
|
|
776
|
+
return { exitCode: blocking ? 1 : 0 };
|
|
820
777
|
}
|
|
821
778
|
printSnapshotResult({
|
|
822
779
|
format: options.format,
|
|
823
780
|
coverage: stagedCoverage,
|
|
824
|
-
messages: [
|
|
781
|
+
messages: [
|
|
782
|
+
allSymbols.length === 0 && stagedEntityResults.length === 0
|
|
783
|
+
? noValidatedSymbolsMessage(sourceAnalysis)
|
|
784
|
+
: passMessage,
|
|
785
|
+
],
|
|
825
786
|
});
|
|
826
|
-
await cleanupTempKb(tempCtx.tempDir);
|
|
827
787
|
return { exitCode: 0 };
|
|
828
788
|
}
|
|
829
789
|
catch (err) {
|
|
@@ -1293,27 +1253,3 @@ export async function checkStrictReadiness(prolog) {
|
|
|
1293
1253
|
}
|
|
1294
1254
|
return violations;
|
|
1295
1255
|
}
|
|
1296
|
-
export async function checkSymbolCoverage(prolog) {
|
|
1297
|
-
const violations = [];
|
|
1298
|
-
const uncoveredResult = await prolog.query("setof(Symbol, symbol_no_req_coverage(Symbol, _), Symbols)");
|
|
1299
|
-
if (uncoveredResult.success && uncoveredResult.bindings.Symbols) {
|
|
1300
|
-
const symbolsStr = uncoveredResult.bindings.Symbols;
|
|
1301
|
-
const match = symbolsStr.match(/\[(.*)\]/);
|
|
1302
|
-
const content = getMatchGroup(match)?.trim();
|
|
1303
|
-
if (content) {
|
|
1304
|
-
const symbolMatches = content.matchAll(/'([^']+)'/g);
|
|
1305
|
-
for (const symbolMatch of symbolMatches) {
|
|
1306
|
-
const symbolId = getMatchGroup(symbolMatch);
|
|
1307
|
-
if (!symbolId)
|
|
1308
|
-
continue;
|
|
1309
|
-
violations.push({
|
|
1310
|
-
rule: "symbol-coverage",
|
|
1311
|
-
entityId: symbolId,
|
|
1312
|
-
description: "Code symbol is not traceable to any functional requirement.",
|
|
1313
|
-
suggestion: "Update symbols.yaml to link this symbol to a related requirement.",
|
|
1314
|
-
});
|
|
1315
|
-
}
|
|
1316
|
-
}
|
|
1317
|
-
}
|
|
1318
|
-
return violations;
|
|
1319
|
-
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"AAgGA,MAAM,WAAW,aAAa;IAC5B,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CAC3B;AAGD,wBAAsB,aAAa,CACjC,OAAO,GAAE,aAAkB,GAC1B,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAmH/B;AAED,wBAAsB,4BAA4B,CAChD,IAAI,GAAE,MAAM,OAAO,CAAC;IAAE,gBAAgB,CAAC,EAAE,OAAO,CAAA;CAAE,CACT,GACxC,OAAO,CAAC,OAAO,CAAC,CAOlB;AAED,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;;;;;;;;;;;;;;;;MAkE3C;AAkGD,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAGzE;AAED,wBAAgB,2BAA2B,CACzC,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,GACX,MAAM,GAAG,SAAS,CAepB"}
|
package/dist/commands/doctor.js
CHANGED
|
@@ -29,7 +29,7 @@ import { resolveBranchAttachment, resolveReadBranchAttachment, } from "../utils/
|
|
|
29
29
|
import { branchStoreCompilation, inspectBranchStore, storeLockTakeoverReason, uncompiledBranchStoreReason, } from "../utils/branch-store.js";
|
|
30
30
|
import { resolveGitRepository, } from "../utils/git-repository-context.js";
|
|
31
31
|
import { readKbManifestStatus } from "../utils/kb-manifest.js";
|
|
32
|
-
import { hasManagedHooks, outdatedManagedHooks } from "./init-helpers.js";
|
|
32
|
+
import { KIBI_HOOK_BEGIN, hasManagedHooks, outdatedManagedHooks, } from "./init-helpers.js";
|
|
33
33
|
import { planLegacyStorageMigration } from "./legacy-storage-migration.js";
|
|
34
34
|
/**
|
|
35
35
|
* First-party plugin diagnostics known without importing the package.
|
|
@@ -598,10 +598,15 @@ function checkKbDirectory() {
|
|
|
598
598
|
function checkKbManifest() {
|
|
599
599
|
const status = readKbManifestStatus(process.cwd());
|
|
600
600
|
if (status.state === "missing") {
|
|
601
|
+
// 'kibi init' on a legacy layout would claim the latest schema and skip
|
|
602
|
+
// the legacy migration steps; migrate writes the manifest itself.
|
|
603
|
+
const legacy = planLegacyStorageMigration(process.cwd());
|
|
601
604
|
return {
|
|
602
605
|
passed: false,
|
|
603
606
|
message: "Not found",
|
|
604
|
-
remediation:
|
|
607
|
+
remediation: legacy.legacyConfig === "absent"
|
|
608
|
+
? "Run: kibi init"
|
|
609
|
+
: "Run: kibi migrate --yes (it creates the manifest from the legacy .kb/config.json; do not run kibi init first)",
|
|
605
610
|
};
|
|
606
611
|
}
|
|
607
612
|
if (status.state !== "ok") {
|
|
@@ -626,11 +631,21 @@ function checkLegacyStorage() {
|
|
|
626
631
|
"Repair or remove the legacy .kb/config.json, then run: kibi migrate --yes",
|
|
627
632
|
};
|
|
628
633
|
}
|
|
629
|
-
if (plan.
|
|
634
|
+
if (plan.blockers.length > 0) {
|
|
635
|
+
return {
|
|
636
|
+
passed: false,
|
|
637
|
+
message: `${plan.blockers.length} legacy knowledge file(s) outside .kb/ cannot be moved automatically`,
|
|
638
|
+
remediation: `${plan.blockers.join(" ")} Then run: kibi migrate --yes`,
|
|
639
|
+
};
|
|
640
|
+
}
|
|
641
|
+
if (plan.legacyConfig === "present" ||
|
|
642
|
+
plan.moves.length > 0 ||
|
|
643
|
+
plan.removals.length > 0) {
|
|
644
|
+
const outside = plan.moves.length + plan.removals.length;
|
|
630
645
|
return {
|
|
631
646
|
passed: false,
|
|
632
|
-
message:
|
|
633
|
-
? `${
|
|
647
|
+
message: outside > 0
|
|
648
|
+
? `${outside} legacy knowledge file(s) still outside .kb/${plan.removals.length > 0 ? ` (${plan.removals.length} identical to the .kb/ copy, which kibi migrate removes)` : ""}`
|
|
634
649
|
: "Legacy .kb/config.json still present",
|
|
635
650
|
remediation: "Run: kibi migrate --yes",
|
|
636
651
|
};
|
|
@@ -848,6 +863,66 @@ function checkGitHooks() {
|
|
|
848
863
|
remediation: "Run: kibi init",
|
|
849
864
|
};
|
|
850
865
|
}
|
|
866
|
+
/**
|
|
867
|
+
* Individual shell commands of a hook script, ignoring comments. Lines are
|
|
868
|
+
* split on command separators so `a && b` counts as two commands.
|
|
869
|
+
*/
|
|
870
|
+
// implements REQ-git-hook-effective-install
|
|
871
|
+
function hookCommands(content) {
|
|
872
|
+
return content
|
|
873
|
+
.split("\n")
|
|
874
|
+
.filter((line) => !line.trimStart().startsWith("#"))
|
|
875
|
+
.flatMap((line) => line.split(/&&|\|\||;|\|/))
|
|
876
|
+
.map((command) => command.trim())
|
|
877
|
+
.filter((command) => command.length > 0);
|
|
878
|
+
}
|
|
879
|
+
// Matches `kibi <sub>`, `npx kibi <sub>`, `node_modules/.bin/kibi <sub>` and
|
|
880
|
+
// the template's `"$KIBI_BIN" <sub>`.
|
|
881
|
+
// implements REQ-git-hook-effective-install
|
|
882
|
+
function invokesKibi(command, subcommand) {
|
|
883
|
+
return new RegExp(`(?:\\bkibi|\\bKIBI_BIN)["'}]*\\s+${subcommand}(?=\\s|$)`).test(command);
|
|
884
|
+
}
|
|
885
|
+
/** The pre-commit gate the managed template runs, as a custom hook must. */
|
|
886
|
+
const PRE_COMMIT_DELEGATIONS = [
|
|
887
|
+
{
|
|
888
|
+
label: "kibi check-generated --staged --changed-only",
|
|
889
|
+
matches: (command) => invokesKibi(command, "check-generated") &&
|
|
890
|
+
/\s--staged(?=\s|$)/.test(command) &&
|
|
891
|
+
/\s--changed-only(?=\s|$)/.test(command),
|
|
892
|
+
},
|
|
893
|
+
{
|
|
894
|
+
label: "kibi check --staged",
|
|
895
|
+
matches: (command) => invokesKibi(command, "check") && /\s--staged(?=\s|$)/.test(command),
|
|
896
|
+
},
|
|
897
|
+
];
|
|
898
|
+
// implements REQ-git-hook-effective-install
|
|
899
|
+
function checkCustomPreCommitHook(content, executable) {
|
|
900
|
+
const commands = hookCommands(content);
|
|
901
|
+
const missing = PRE_COMMIT_DELEGATIONS.filter((delegation) => !commands.some(delegation.matches)).map((delegation) => `'${delegation.label}'`);
|
|
902
|
+
if (missing.length > 0) {
|
|
903
|
+
// An unmarked file that still carries the old template header is a Kibi
|
|
904
|
+
// hook from before managed sections; removing it lets init reinstall it.
|
|
905
|
+
const oldTemplate = content.includes("# pre-commit hook for kibi")
|
|
906
|
+
? " If this file is an old Kibi template, delete it and run 'kibi init' instead."
|
|
907
|
+
: "";
|
|
908
|
+
return {
|
|
909
|
+
passed: false,
|
|
910
|
+
message: `Custom pre-commit hook (no kibi-managed section) does not run ${missing.join(" or ")}; commits skip Kibi enforcement${hooksPathSuffix()}`,
|
|
911
|
+
remediation: `Delegate from your hook to both 'kibi check-generated --staged --changed-only' and 'kibi check --staged'. Print a copy-paste snippet that resolves a project-local kibi with: kibi init --print-hook pre-commit (kibi init never edits a custom hook).${oldTemplate}`,
|
|
912
|
+
};
|
|
913
|
+
}
|
|
914
|
+
if (!executable) {
|
|
915
|
+
return {
|
|
916
|
+
passed: false,
|
|
917
|
+
message: `Installed but not executable${hooksPathSuffix()}`,
|
|
918
|
+
remediation: remediationHookPaths("pre-commit"),
|
|
919
|
+
};
|
|
920
|
+
}
|
|
921
|
+
return {
|
|
922
|
+
passed: true,
|
|
923
|
+
message: `Custom hook delegates to 'kibi check-generated --staged --changed-only' and 'kibi check --staged'${hooksPathSuffix()}`,
|
|
924
|
+
};
|
|
925
|
+
}
|
|
851
926
|
function checkPreCommitHook() {
|
|
852
927
|
const postCheckoutPath = path.join(effectiveHooksDir(), "post-checkout");
|
|
853
928
|
const postMergePath = path.join(effectiveHooksDir(), "post-merge");
|
|
@@ -873,6 +948,12 @@ function checkPreCommitHook() {
|
|
|
873
948
|
const preCommitExecutable = (preCommitStats.mode & 0o111) !== 0;
|
|
874
949
|
// Read hook content to determine whether it's using the new staged check
|
|
875
950
|
const content = readFileSync(preCommitPath, "utf-8");
|
|
951
|
+
// A hook without a kibi-managed section is the user's own (hand-written,
|
|
952
|
+
// husky, lefthook, ...). `kibi init` never edits it, so the only useful
|
|
953
|
+
// check is whether it delegates to the gate the managed template runs.
|
|
954
|
+
if (!content.includes(KIBI_HOOK_BEGIN)) {
|
|
955
|
+
return checkCustomPreCommitHook(content, preCommitExecutable);
|
|
956
|
+
}
|
|
876
957
|
// Current templates resolve the kibi binary into KIBI_BIN before invoking
|
|
877
958
|
// it (git hooks do not get node_modules/.bin on PATH); legacy templates
|
|
878
959
|
// invoked bare `kibi`.
|
|
@@ -951,6 +1032,27 @@ function checkPostRewriteHook() {
|
|
|
951
1032
|
// Read hook content to verify it invokes kibi. Current templates invoke
|
|
952
1033
|
// the resolved KIBI_BIN; legacy templates invoked bare `kibi sync`.
|
|
953
1034
|
const content = readFileSync(postRewritePath, "utf-8");
|
|
1035
|
+
// A custom hook (no kibi-managed section) is never edited by init.
|
|
1036
|
+
// implements REQ-git-hook-effective-install
|
|
1037
|
+
if (!content.includes(KIBI_HOOK_BEGIN)) {
|
|
1038
|
+
if (!hookCommands(content).some((cmd) => invokesKibi(cmd, "sync"))) {
|
|
1039
|
+
return {
|
|
1040
|
+
passed: false,
|
|
1041
|
+
message: `Custom post-rewrite hook (no kibi-managed section) does not run 'kibi sync'${hooksPathSuffix()}`,
|
|
1042
|
+
remediation: "Delegate from your hook to 'kibi sync' after rebases. Print a copy-paste snippet that resolves a project-local kibi with: kibi init --print-hook post-rewrite (kibi init never edits a custom hook).",
|
|
1043
|
+
};
|
|
1044
|
+
}
|
|
1045
|
+
return postRewriteExecutable
|
|
1046
|
+
? {
|
|
1047
|
+
passed: true,
|
|
1048
|
+
message: `Custom hook delegates to 'kibi sync'${hooksPathSuffix()}`,
|
|
1049
|
+
}
|
|
1050
|
+
: {
|
|
1051
|
+
passed: false,
|
|
1052
|
+
message: `Installed but not executable${hooksPathSuffix()}`,
|
|
1053
|
+
remediation: remediationHookPaths("post-rewrite"),
|
|
1054
|
+
};
|
|
1055
|
+
}
|
|
954
1056
|
const usesKibi = content.includes('"$KIBI_BIN" sync') || content.includes("kibi sync");
|
|
955
1057
|
const resolvesKibi = content.includes("KIBI_BIN=");
|
|
956
1058
|
if (!usesKibi) {
|
|
@@ -4,10 +4,23 @@ export declare function createManifestFile(kbDir: string): void;
|
|
|
4
4
|
export declare function updateGitIgnore(cwd: string): void;
|
|
5
5
|
export declare function ensureSymbolsManifestFile(cwd: string): void;
|
|
6
6
|
export declare function copySchemaFiles(kbDir: string, schemaSourceDir: string): Promise<void>;
|
|
7
|
+
export declare const KIBI_HOOK_BEGIN = "# BEGIN kibi-managed";
|
|
7
8
|
export type InstallHookResult = "installed" | "updated" | "skipped-foreign" | "skipped-symlink" | "skipped-unsupported";
|
|
9
|
+
/** Hook names `kibi init` manages, in install order. */
|
|
10
|
+
export declare const MANAGED_HOOK_NAMES: readonly ["post-checkout", "post-merge", "post-rewrite", "pre-commit"];
|
|
11
|
+
export type ManagedHookName = (typeof MANAGED_HOOK_NAMES)[number];
|
|
12
|
+
export declare function isManagedHookName(value: string): value is ManagedHookName;
|
|
13
|
+
/**
|
|
14
|
+
* A copy-paste snippet for wiring Kibi into a hook that Kibi does not own
|
|
15
|
+
* (hand-written, husky, lefthook, ...). It reuses the managed template's
|
|
16
|
+
* KIBI_BIN resolution, so a project-local kibi CLI is found even though git
|
|
17
|
+
* does not put node_modules/.bin on PATH, and every command propagates its
|
|
18
|
+
* failure so the delegation is never weaker than the template it replaces.
|
|
19
|
+
*/
|
|
20
|
+
export declare function hookDelegationSnippet(hook: ManagedHookName): string;
|
|
8
21
|
export declare function installHook(hookPath: string, content: string): InstallHookResult;
|
|
9
22
|
export interface GitHookInstallResult {
|
|
10
|
-
hook:
|
|
23
|
+
hook: ManagedHookName;
|
|
11
24
|
result: InstallHookResult;
|
|
12
25
|
}
|
|
13
26
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init-helpers.d.ts","sourceRoot":"","sources":["../../src/commands/init-helpers.ts"],"names":[],"mappings":"AA6IA,wBAAsB,gBAAgB,CACpC,GAAG,GAAE,MAAsB,GAC1B,OAAO,CAAC,MAAM,CAAC,CASjB;AAED,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,MAAM,EACb,aAAa,EAAE,MAAM,GACpB,IAAI,CA0BN;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAGtD;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CA6BjD;AAkDD,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAU3D;AAED,wBAAsB,eAAe,CACnC,KAAK,EAAE,MAAM,EACb,eAAe,EAAE,MAAM,GACtB,OAAO,CAAC,IAAI,CAAC,CAuBf;
|
|
1
|
+
{"version":3,"file":"init-helpers.d.ts","sourceRoot":"","sources":["../../src/commands/init-helpers.ts"],"names":[],"mappings":"AA6IA,wBAAsB,gBAAgB,CACpC,GAAG,GAAE,MAAsB,GAC1B,OAAO,CAAC,MAAM,CAAC,CASjB;AAED,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,MAAM,EACb,aAAa,EAAE,MAAM,GACpB,IAAI,CA0BN;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAGtD;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CA6BjD;AAkDD,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAU3D;AAED,wBAAsB,eAAe,CACnC,KAAK,EAAE,MAAM,EACb,eAAe,EAAE,MAAM,GACtB,OAAO,CAAC,IAAI,CAAC,CAuBf;AAED,eAAO,MAAM,eAAe,yBAAyB,CAAC;AAOtD,MAAM,MAAM,iBAAiB,GACzB,WAAW,GACX,SAAS,GACT,iBAAiB,GACjB,iBAAiB,GACjB,qBAAqB,CAAC;AAE1B,wDAAwD;AACxD,eAAO,MAAM,kBAAkB,wEAKrB,CAAC;AAEX,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,kBAAkB,CAAC,CAAC,MAAM,CAAC,CAAC;AAGlE,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,IAAI,eAAe,CAEzE;AAED;;;;;;GAMG;AAEH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,eAAe,GAAG,MAAM,CAqBnE;AAkBD,wBAAgB,WAAW,CACzB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,GACd,iBAAiB,CAwEnB;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,eAAe,CAAC;IACtB,MAAM,EAAE,iBAAiB,CAAC;CAC3B;AAiBD;;;;GAIG;AAEH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAU/D;AAED,wEAAwE;AAExE,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAQzD;AAED,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE;IAAE,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAO,GAChD,oBAAoB,EAAE,CA8CxB"}
|
|
@@ -258,26 +258,65 @@ export async function copySchemaFiles(kbDir, schemaSourceDir) {
|
|
|
258
258
|
}
|
|
259
259
|
console.log(`✓ Ensured ${schemaFiles.length} schema files`);
|
|
260
260
|
}
|
|
261
|
-
const KIBI_HOOK_BEGIN = "# BEGIN kibi-managed";
|
|
261
|
+
export const KIBI_HOOK_BEGIN = "# BEGIN kibi-managed";
|
|
262
262
|
const KIBI_HOOK_END = "# END kibi-managed";
|
|
263
263
|
function escapeRegex(s) {
|
|
264
264
|
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
265
265
|
}
|
|
266
|
+
/** Hook names `kibi init` manages, in install order. */
|
|
267
|
+
export const MANAGED_HOOK_NAMES = [
|
|
268
|
+
"post-checkout",
|
|
269
|
+
"post-merge",
|
|
270
|
+
"post-rewrite",
|
|
271
|
+
"pre-commit",
|
|
272
|
+
];
|
|
273
|
+
// implements REQ-git-hook-effective-install
|
|
274
|
+
export function isManagedHookName(value) {
|
|
275
|
+
return MANAGED_HOOK_NAMES.includes(value);
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* A copy-paste snippet for wiring Kibi into a hook that Kibi does not own
|
|
279
|
+
* (hand-written, husky, lefthook, ...). It reuses the managed template's
|
|
280
|
+
* KIBI_BIN resolution, so a project-local kibi CLI is found even though git
|
|
281
|
+
* does not put node_modules/.bin on PATH, and every command propagates its
|
|
282
|
+
* failure so the delegation is never weaker than the template it replaces.
|
|
283
|
+
*/
|
|
284
|
+
// implements REQ-git-hook-effective-install
|
|
285
|
+
export function hookDelegationSnippet(hook) {
|
|
286
|
+
const header = [
|
|
287
|
+
`# Kibi ${hook} delegation (printed by 'kibi init --print-hook ${hook}').`,
|
|
288
|
+
`# Paste into your existing ${hook} hook; it runs the same Kibi commands`,
|
|
289
|
+
"# as the Kibi-managed template.",
|
|
290
|
+
].join("\n");
|
|
291
|
+
const guarded = (condition, commands) => {
|
|
292
|
+
const body = `${KIBI_BIN_RESOLVER}\n${commands}`.replace(/^(?=.)/gm, " ");
|
|
293
|
+
return `${header}\nif ${condition}; then\n${body}\nfi\n`;
|
|
294
|
+
};
|
|
295
|
+
switch (hook) {
|
|
296
|
+
case "pre-commit":
|
|
297
|
+
return `${header}\n${KIBI_BIN_RESOLVER}\n"$KIBI_BIN" check-generated --staged --changed-only || exit $?\n"$KIBI_BIN" check --staged || exit $?\n`;
|
|
298
|
+
case "post-checkout":
|
|
299
|
+
// Only branch checkouts refresh the KB; file checkouts are skipped.
|
|
300
|
+
return guarded('[ "$3" = "1" ]', '"$KIBI_BIN" sync');
|
|
301
|
+
case "post-merge":
|
|
302
|
+
return `${header}\n${KIBI_BIN_RESOLVER}\n"$KIBI_BIN" sync\n`;
|
|
303
|
+
case "post-rewrite":
|
|
304
|
+
return guarded('[ "$1" = "rebase" ]', '"$KIBI_BIN" sync');
|
|
305
|
+
}
|
|
306
|
+
}
|
|
266
307
|
function hookIntegrationRecipe(hook) {
|
|
267
|
-
// Recipes must
|
|
268
|
-
//
|
|
269
|
-
|
|
308
|
+
// Recipes must name the exact checks the Kibi template runs for that hook;
|
|
309
|
+
// the printed snippet adds CLI resolution and failure propagation.
|
|
310
|
+
const printHook = `print a copy-paste snippet that resolves a project-local kibi with 'kibi init --print-hook ${hook}'`;
|
|
270
311
|
switch (hook) {
|
|
271
312
|
case "pre-commit":
|
|
272
|
-
return
|
|
313
|
+
return `delegate from that hook to both 'kibi check-generated --staged --changed-only' and 'kibi check --staged' (both must succeed); ${printHook}`;
|
|
273
314
|
case "post-checkout":
|
|
274
|
-
return
|
|
315
|
+
return `delegate from that hook to 'kibi sync' on branch checkouts (the template skips file checkouts); ${printHook}`;
|
|
275
316
|
case "post-merge":
|
|
276
|
-
return
|
|
317
|
+
return `delegate from that hook to 'kibi sync'; ${printHook}`;
|
|
277
318
|
case "post-rewrite":
|
|
278
|
-
return
|
|
279
|
-
default:
|
|
280
|
-
return "delegate to the matching Kibi template command";
|
|
319
|
+
return `delegate from that hook to 'kibi sync' after rebase rewrites; ${printHook}`;
|
|
281
320
|
}
|
|
282
321
|
}
|
|
283
322
|
export function installHook(hookPath, content) {
|
package/dist/commands/init.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAuGA,UAAU,WAAW;IACnB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAoDD,wBAAsB,WAAW,CAC/B,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAgK/B"}
|
package/dist/commands/init.js
CHANGED
|
@@ -21,9 +21,10 @@ import { fileURLToPath } from "node:url";
|
|
|
21
21
|
import { classifyActivation } from "../operations/bootstrap/activation.js";
|
|
22
22
|
import { nodeFilesystem } from "../public/operations/node-ports.js";
|
|
23
23
|
import { resolveBranchAttachment } from "../utils/branch-resolver.js";
|
|
24
|
+
import { readLegacyKbConfig } from "../utils/config.js";
|
|
24
25
|
import { resolveGitRepository, } from "../utils/git-repository-context.js";
|
|
25
26
|
import { scaffoldGitHubIntegration } from "./github-init.js";
|
|
26
|
-
import { copySchemaFiles, createKbDirectoryStructure, createManifestFile, ensureSymbolsManifestFile, installGitHooks, updateGitIgnore, } from "./init-helpers.js";
|
|
27
|
+
import { MANAGED_HOOK_NAMES, copySchemaFiles, createKbDirectoryStructure, createManifestFile, ensureSymbolsManifestFile, hookDelegationSnippet, installGitHooks, isManagedHookName, updateGitIgnore, } from "./init-helpers.js";
|
|
27
28
|
const __filename = fileURLToPath(import.meta.url);
|
|
28
29
|
const __dirname = path.dirname(__filename);
|
|
29
30
|
/**
|
|
@@ -120,6 +121,17 @@ async function initNextAction(projectRoot) {
|
|
|
120
121
|
// implements REQ-cli-init
|
|
121
122
|
// implements REQ-kibi-github-report-integration
|
|
122
123
|
export async function initCommand(options) {
|
|
124
|
+
if (options.printHook !== undefined) {
|
|
125
|
+
// Print-only mode: emit a delegation snippet for a hook Kibi does not
|
|
126
|
+
// own and touch nothing, not even the repository context.
|
|
127
|
+
// implements REQ-git-hook-effective-install
|
|
128
|
+
if (!isManagedHookName(options.printHook)) {
|
|
129
|
+
console.error(`Error: unknown hook '${options.printHook}' for --print-hook. Expected one of: ${MANAGED_HOOK_NAMES.join(", ")}.`);
|
|
130
|
+
return { exitCode: 1 };
|
|
131
|
+
}
|
|
132
|
+
process.stdout.write(hookDelegationSnippet(options.printHook));
|
|
133
|
+
return { exitCode: 0 };
|
|
134
|
+
}
|
|
123
135
|
if (options.badgeOnly === true && options.github !== true) {
|
|
124
136
|
console.error("Error: --badge-only requires --github. The recommended integration is `kibi init --github` (badge + full report).");
|
|
125
137
|
return { exitCode: 1 };
|
|
@@ -172,14 +184,23 @@ export async function initCommand(options) {
|
|
|
172
184
|
}
|
|
173
185
|
// A directory left by a tool or interrupted setup is not a complete KB.
|
|
174
186
|
// Reconcile missing infrastructure on every invocation, preserving sources.
|
|
187
|
+
// A legacy .kb/config.json belongs to 'kibi migrate': a fresh manifest
|
|
188
|
+
// would claim the latest schema (skipping the legacy steps) and a fresh
|
|
189
|
+
// symbols manifest would block the move of the real one.
|
|
190
|
+
const legacyConfig = readLegacyKbConfig(projectRoot).kind !== "none";
|
|
175
191
|
createKbDirectoryStructure(kbDir, currentBranch);
|
|
176
|
-
if (!existsSync(path.join(kbDir, "manifest.json"))) {
|
|
192
|
+
if (!legacyConfig && !existsSync(path.join(kbDir, "manifest.json"))) {
|
|
177
193
|
createManifestFile(kbDir);
|
|
178
194
|
}
|
|
179
195
|
updateGitIgnore(projectRoot);
|
|
180
196
|
const schemaSourceDir = path.resolve(__dirname, "..", "..", "schema");
|
|
181
197
|
await copySchemaFiles(kbDir, schemaSourceDir);
|
|
182
|
-
|
|
198
|
+
if (legacyConfig) {
|
|
199
|
+
console.log("! Legacy .kb/config.json found; left .kb/manifest.json and .kb/symbols.yaml to 'kibi migrate --yes', which moves the existing knowledge and runs every schema step.");
|
|
200
|
+
}
|
|
201
|
+
else {
|
|
202
|
+
ensureSymbolsManifestFile(projectRoot);
|
|
203
|
+
}
|
|
183
204
|
if (options.hooks) {
|
|
184
205
|
if (!repoContext) {
|
|
185
206
|
console.error("Warning: No git repository found, skipping hooks");
|
|
@@ -209,7 +230,9 @@ export async function initCommand(options) {
|
|
|
209
230
|
if (kbExists) {
|
|
210
231
|
console.log(" Existing Kibi source knowledge was preserved.");
|
|
211
232
|
}
|
|
212
|
-
console.log(
|
|
233
|
+
console.log(legacyConfig
|
|
234
|
+
? " Next: run 'kibi migrate --yes' to move the legacy knowledge into .kb/."
|
|
235
|
+
: (await initNextAction(projectRoot)).message);
|
|
213
236
|
console.log(" Optional diagnostic: run 'kibi doctor' if setup appears degraded.");
|
|
214
237
|
if (options.github === true) {
|
|
215
238
|
scaffoldGitHubIntegration({
|