kibi-cli 2.3.0 → 2.5.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-json-command.d.ts +6 -0
- package/dist/cli-json-command.d.ts.map +1 -1
- package/dist/cli-json-command.js +39 -11
- package/dist/cli-operation-loader.d.ts.map +1 -1
- package/dist/cli-operation-loader.js +7 -0
- package/dist/cli-operation-metadata.d.ts +13 -5
- package/dist/cli-operation-metadata.d.ts.map +1 -1
- package/dist/cli-operation-metadata.js +15 -5
- package/dist/cli-protocol.d.ts +14 -0
- package/dist/cli-protocol.d.ts.map +1 -1
- package/dist/cli-protocol.js +31 -2
- package/dist/cli-register-maintenance.d.ts.map +1 -1
- package/dist/cli-register-maintenance.js +7 -0
- package/dist/cli-register-proof.d.ts.map +1 -1
- package/dist/cli-register-proof.js +13 -0
- package/dist/commands/check.d.ts.map +1 -1
- package/dist/commands/check.js +11 -2
- package/dist/commands/discovery-shared.d.ts.map +1 -1
- package/dist/commands/discovery-shared.js +8 -2
- package/dist/commands/engine.d.ts.map +1 -1
- package/dist/commands/engine.js +4 -2
- package/dist/commands/gc.d.ts.map +1 -1
- package/dist/commands/gc.js +7 -0
- package/dist/commands/init-helpers.d.ts.map +1 -1
- package/dist/commands/init-helpers.js +0 -1
- package/dist/commands/merge-driver.d.ts +31 -0
- package/dist/commands/merge-driver.d.ts.map +1 -0
- package/dist/commands/merge-driver.js +268 -0
- package/dist/commands/migrate.d.ts.map +1 -1
- package/dist/commands/migrate.js +281 -14
- package/dist/commands/proof-compact.d.ts +9 -0
- package/dist/commands/proof-compact.d.ts.map +1 -0
- package/dist/commands/proof-compact.js +58 -0
- package/dist/commands/prove.d.ts +38 -0
- package/dist/commands/prove.d.ts.map +1 -1
- package/dist/commands/prove.js +222 -47
- package/dist/commands/sync/persistence.d.ts.map +1 -1
- package/dist/commands/sync/persistence.js +61 -16
- package/dist/commands/sync.d.ts +8 -0
- package/dist/commands/sync.d.ts.map +1 -1
- package/dist/commands/sync.js +42 -16
- package/dist/diagnostics.js +1 -1
- package/dist/engine-limits.d.ts +74 -0
- package/dist/engine-limits.d.ts.map +1 -0
- package/dist/engine-limits.js +201 -0
- package/dist/engine.d.ts +10 -0
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +57 -9
- package/dist/extractors/manifest.d.ts +8 -0
- package/dist/extractors/manifest.d.ts.map +1 -1
- package/dist/extractors/manifest.js +34 -5
- package/dist/extractors/markdown.d.ts +8 -0
- package/dist/extractors/markdown.d.ts.map +1 -1
- package/dist/extractors/markdown.js +57 -0
- package/dist/extractors/relationships.d.ts.map +1 -1
- package/dist/extractors/relationships.js +2 -0
- package/dist/intent-search.d.ts +4 -1
- package/dist/intent-search.d.ts.map +1 -1
- package/dist/intent-search.js +186 -33
- package/dist/operations/bootstrap/candidate-helpers.d.ts.map +1 -1
- package/dist/operations/bootstrap/candidate-helpers.js +8 -1
- package/dist/operations/bootstrap/candidates.d.ts.map +1 -1
- package/dist/operations/bootstrap/candidates.js +55 -39
- package/dist/operations/bootstrap/discovery.js +1 -1
- package/dist/operations/bootstrap/generate.d.ts +2 -0
- package/dist/operations/bootstrap/generate.d.ts.map +1 -1
- package/dist/operations/bootstrap/generate.js +107 -37
- package/dist/operations/bootstrap/guidance-actions.d.ts.map +1 -1
- package/dist/operations/bootstrap/guidance-actions.js +3 -0
- package/dist/operations/bootstrap/guidance.d.ts.map +1 -1
- package/dist/operations/bootstrap/guidance.js +7 -1
- package/dist/operations/bootstrap/intent-claims.d.ts +17 -0
- package/dist/operations/bootstrap/intent-claims.d.ts.map +1 -0
- package/dist/operations/bootstrap/intent-claims.js +103 -0
- package/dist/operations/bootstrap/markdown-candidates.d.ts +2 -0
- package/dist/operations/bootstrap/markdown-candidates.d.ts.map +1 -1
- package/dist/operations/bootstrap/markdown-candidates.js +32 -10
- package/dist/operations/bootstrap/presentation.d.ts +2 -0
- package/dist/operations/bootstrap/presentation.d.ts.map +1 -1
- package/dist/operations/bootstrap/presentation.js +66 -3
- package/dist/operations/bootstrap/requirement-claims.d.ts +1 -0
- package/dist/operations/bootstrap/requirement-claims.d.ts.map +1 -1
- package/dist/operations/bootstrap/requirement-claims.js +13 -1
- package/dist/operations/bootstrap/types.d.ts +28 -0
- package/dist/operations/bootstrap/types.d.ts.map +1 -1
- package/dist/operations/bootstrap/types.js +16 -0
- package/dist/operations/bootstrap/validation.d.ts +4 -0
- package/dist/operations/bootstrap/validation.d.ts.map +1 -0
- package/dist/operations/bootstrap/validation.js +20 -0
- package/dist/operations/migration/inventory-rederive.d.ts +81 -0
- package/dist/operations/migration/inventory-rederive.d.ts.map +1 -0
- package/dist/operations/migration/inventory-rederive.js +484 -0
- package/dist/operations/migration/kb-sources.d.ts +53 -0
- package/dist/operations/migration/kb-sources.d.ts.map +1 -0
- package/dist/operations/migration/kb-sources.js +233 -0
- package/dist/operations/migration/origin-backfill.d.ts +39 -0
- package/dist/operations/migration/origin-backfill.d.ts.map +1 -0
- package/dist/operations/migration/origin-backfill.js +164 -0
- package/dist/operations/migration/polarity-values.d.ts +10 -0
- package/dist/operations/migration/polarity-values.d.ts.map +1 -0
- package/dist/operations/migration/polarity-values.js +60 -0
- package/dist/operations/migration/schema6.d.ts +59 -0
- package/dist/operations/migration/schema6.d.ts.map +1 -0
- package/dist/operations/migration/schema6.js +379 -0
- package/dist/operations/migration/source-paths.d.ts +131 -0
- package/dist/operations/migration/source-paths.d.ts.map +1 -0
- package/dist/operations/migration/source-paths.js +308 -0
- package/dist/operations/migration/superseded-closure.d.ts +54 -0
- package/dist/operations/migration/superseded-closure.d.ts.map +1 -0
- package/dist/operations/migration/superseded-closure.js +187 -0
- package/dist/operations/modeling/logic-modeling.d.ts.map +1 -1
- package/dist/operations/modeling/logic-modeling.js +3 -5
- package/dist/operations/modeling/model-requirement.d.ts.map +1 -1
- package/dist/operations/modeling/model-requirement.js +225 -67
- package/dist/operations/mutation/contradictions.d.ts +16 -0
- package/dist/operations/mutation/contradictions.d.ts.map +1 -1
- package/dist/operations/mutation/contradictions.js +32 -0
- package/dist/operations/mutation/delete.d.ts.map +1 -1
- package/dist/operations/mutation/delete.js +15 -7
- package/dist/operations/mutation/origin.d.ts +21 -0
- package/dist/operations/mutation/origin.d.ts.map +1 -0
- package/dist/operations/mutation/origin.js +78 -0
- package/dist/operations/mutation/plan-apply-journal.d.ts +182 -0
- package/dist/operations/mutation/plan-apply-journal.d.ts.map +1 -0
- package/dist/operations/mutation/plan-apply-journal.js +613 -0
- package/dist/operations/mutation/predicate-vocabulary-guard.d.ts +3 -1
- package/dist/operations/mutation/predicate-vocabulary-guard.d.ts.map +1 -1
- package/dist/operations/mutation/predicate-vocabulary-guard.js +13 -2
- package/dist/operations/mutation/relationships.d.ts +5 -5
- package/dist/operations/mutation/relationships.d.ts.map +1 -1
- package/dist/operations/mutation/relationships.js +31 -11
- package/dist/operations/mutation/serialization.d.ts.map +1 -1
- package/dist/operations/mutation/serialization.js +3 -1
- package/dist/operations/mutation/source-authoring.d.ts +6 -0
- package/dist/operations/mutation/source-authoring.d.ts.map +1 -1
- package/dist/operations/mutation/source-authoring.js +7 -1
- package/dist/operations/mutation/symbol-refresh.d.ts.map +1 -1
- package/dist/operations/mutation/symbol-refresh.js +4 -1
- package/dist/operations/mutation/types.d.ts +14 -0
- package/dist/operations/mutation/types.d.ts.map +1 -1
- package/dist/operations/mutation/upsert.d.ts +30 -3
- package/dist/operations/mutation/upsert.d.ts.map +1 -1
- package/dist/operations/mutation/upsert.js +105 -35
- package/dist/operations/mutation/validate-upsert.d.ts +6 -0
- package/dist/operations/mutation/validate-upsert.d.ts.map +1 -1
- package/dist/operations/mutation/validate-upsert.js +34 -30
- package/dist/operations/planning/apply-plan.d.ts.map +1 -1
- package/dist/operations/planning/apply-plan.js +751 -144
- package/dist/operations/planning/compile-intent.d.ts +34 -1
- package/dist/operations/planning/compile-intent.d.ts.map +1 -1
- package/dist/operations/planning/compile-intent.js +314 -98
- package/dist/operations/proof/code-scope.d.ts +28 -0
- package/dist/operations/proof/code-scope.d.ts.map +1 -1
- package/dist/operations/proof/code-scope.js +72 -0
- package/dist/operations/proof/compact-receipts.d.ts +49 -0
- package/dist/operations/proof/compact-receipts.d.ts.map +1 -0
- package/dist/operations/proof/compact-receipts.js +160 -0
- package/dist/operations/proof/ingest-proof.d.ts +2 -0
- package/dist/operations/proof/ingest-proof.d.ts.map +1 -1
- package/dist/operations/proof/ingest-proof.js +44 -23
- package/dist/operations/proof/prune-receipts.d.ts.map +1 -1
- package/dist/operations/proof/prune-receipts.js +5 -9
- package/dist/operations/proof/receipt-compaction.d.ts +48 -0
- package/dist/operations/proof/receipt-compaction.d.ts.map +1 -0
- package/dist/operations/proof/receipt-compaction.js +121 -0
- package/dist/operations/semantic-advisor/analysis-receipt.d.ts.map +1 -1
- package/dist/operations/semantic-advisor/analysis-receipt.js +12 -1
- package/dist/operations/semantic-advisor/analyze-prose.d.ts +2 -1
- package/dist/operations/semantic-advisor/analyze-prose.d.ts.map +1 -1
- package/dist/operations/semantic-advisor/analyze-prose.js +51 -5
- package/dist/operations/semantic-advisor/clauses.d.ts +1 -0
- package/dist/operations/semantic-advisor/clauses.d.ts.map +1 -1
- package/dist/operations/semantic-advisor/clauses.js +11 -1
- package/dist/operations/semantic-advisor/conditional-rules.d.ts +33 -0
- package/dist/operations/semantic-advisor/conditional-rules.d.ts.map +1 -0
- package/dist/operations/semantic-advisor/conditional-rules.js +262 -0
- package/dist/operations/semantic-advisor/ingestion-boundary.d.ts +3 -1
- package/dist/operations/semantic-advisor/ingestion-boundary.d.ts.map +1 -1
- package/dist/operations/semantic-advisor/ingestion-boundary.js +14 -6
- package/dist/operations/semantic-advisor/plugin-orchestration.js +1 -1
- package/dist/prolog/codec.d.ts.map +1 -1
- package/dist/prolog/codec.js +2 -1
- package/dist/prolog.d.ts +9 -0
- package/dist/prolog.d.ts.map +1 -1
- package/dist/prolog.js +56 -10
- package/dist/proof/command-test-report.d.ts +74 -0
- package/dist/proof/command-test-report.d.ts.map +1 -0
- package/dist/proof/command-test-report.js +206 -0
- package/dist/public/branch-resolver.d.ts +1 -0
- package/dist/public/branch-resolver.d.ts.map +1 -1
- package/dist/public/branch-resolver.js +1 -0
- package/dist/public/diagnostic-usage.d.ts +14 -0
- package/dist/public/diagnostic-usage.d.ts.map +1 -1
- package/dist/public/diagnostic-usage.js +55 -1
- package/dist/public/entity-origin.d.ts +69 -0
- package/dist/public/entity-origin.d.ts.map +1 -0
- package/dist/public/entity-origin.js +142 -0
- package/dist/public/impact/full-kb-quality.d.ts.map +1 -1
- package/dist/public/impact/full-kb-quality.js +1 -0
- package/dist/public/impact/requirement-quality.js +1 -1
- package/dist/public/operations/catalog.d.ts +203 -20
- package/dist/public/operations/catalog.d.ts.map +1 -1
- package/dist/public/operations/catalog.js +3 -0
- package/dist/public/operations/check-executor.d.ts.map +1 -1
- package/dist/public/operations/check-executor.js +8 -0
- package/dist/public/operations/contracts.d.ts +0 -5
- package/dist/public/operations/contracts.d.ts.map +1 -1
- package/dist/public/operations/contracts.js +63 -14
- package/dist/public/operations/discovery-entities.d.ts +15 -0
- package/dist/public/operations/discovery-entities.d.ts.map +1 -1
- package/dist/public/operations/discovery-entities.js +59 -0
- package/dist/public/operations/discovery-executors.d.ts +6 -1
- package/dist/public/operations/discovery-executors.d.ts.map +1 -1
- package/dist/public/operations/discovery-executors.js +65 -6
- package/dist/public/operations/index.d.ts +1 -0
- package/dist/public/operations/index.d.ts.map +1 -1
- package/dist/public/operations/index.js +1 -0
- package/dist/public/operations/migration-plan.d.ts +5 -0
- package/dist/public/operations/migration-plan.d.ts.map +1 -1
- package/dist/public/operations/migration-plan.js +26 -1
- package/dist/public/operations/node-ports.d.ts.map +1 -1
- package/dist/public/operations/node-ports.js +24 -3
- package/dist/public/operations/origin-review.d.ts +51 -0
- package/dist/public/operations/origin-review.d.ts.map +1 -0
- package/dist/public/operations/origin-review.js +307 -0
- package/dist/public/operations/predicate-schema-conformance.js +1 -1
- package/dist/public/operations/repair-plan.d.ts.map +1 -1
- package/dist/public/operations/repair-plan.js +4 -0
- package/dist/public/operations/result-envelope.d.ts.map +1 -1
- package/dist/public/operations/result-envelope.js +17 -5
- package/dist/public/operations/runtime-types.d.ts +9 -0
- package/dist/public/operations/runtime-types.d.ts.map +1 -1
- package/dist/public/operations/schema6-check-actions.d.ts +127 -0
- package/dist/public/operations/schema6-check-actions.d.ts.map +1 -0
- package/dist/public/operations/schema6-check-actions.js +575 -0
- package/dist/public/operations/source-path-dangling.d.ts +17 -0
- package/dist/public/operations/source-path-dangling.d.ts.map +1 -0
- package/dist/public/operations/source-path-dangling.js +66 -0
- package/dist/public/operations/specs/bootstrap.d.ts +73 -1
- package/dist/public/operations/specs/bootstrap.d.ts.map +1 -1
- package/dist/public/operations/specs/bootstrap.js +66 -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 +15 -1
- package/dist/public/operations/specs/check.d.ts +2 -2
- package/dist/public/operations/specs/check.js +1 -1
- package/dist/public/operations/specs/composite.d.ts +351 -0
- package/dist/public/operations/specs/composite.d.ts.map +1 -0
- package/dist/public/operations/specs/composite.js +96 -0
- package/dist/public/operations/specs/discovery.d.ts +8 -3
- package/dist/public/operations/specs/discovery.d.ts.map +1 -1
- package/dist/public/operations/specs/discovery.js +8 -3
- package/dist/public/operations/specs/modeling.d.ts +2 -2
- package/dist/public/operations/specs/modeling.js +2 -2
- package/dist/public/operations/specs/mutation-schemas.d.ts +73 -8
- package/dist/public/operations/specs/mutation-schemas.d.ts.map +1 -1
- package/dist/public/operations/specs/mutation-schemas.js +43 -7
- package/dist/public/operations/specs/mutation.d.ts +1 -1
- package/dist/public/operations/specs/mutation.js +1 -1
- package/dist/public/operations/specs/planning.d.ts +2 -2
- package/dist/public/operations/specs/planning.js +4 -4
- package/dist/public/operations/specs/reporting.d.ts.map +1 -1
- package/dist/public/operations/specs/reporting.js +13 -26
- package/dist/public/operations/specs/upsert.d.ts +79 -9
- package/dist/public/operations/specs/upsert.d.ts.map +1 -1
- package/dist/public/operations/specs/upsert.js +6 -1
- package/dist/public/operations/symbol-repair-plan.d.ts.map +1 -1
- package/dist/public/operations/symbol-repair-plan.js +3 -1
- package/dist/public/operations/types.d.ts +1 -1
- package/dist/public/operations/types.d.ts.map +1 -1
- package/dist/public/proof-receipt.d.ts +1 -0
- package/dist/public/proof-receipt.d.ts.map +1 -1
- package/dist/public/schemas/entity.d.ts.map +1 -1
- package/dist/public/schemas/entity.js +52 -0
- package/dist/public/schemas/relationship.d.ts.map +1 -1
- package/dist/public/schemas/relationship.js +2 -0
- package/dist/public/skills/kibi-bootstrap/SKILL.md +52 -11
- package/dist/public/skills/kibi-bootstrap/resources/bootstrap.md +12 -1
- package/dist/public/skills/kibi-usage/SKILL.md +82 -18
- package/dist/public/skills/kibi-usage/resources/fact-lanes.md +5 -5
- package/dist/public/skills/kibi-usage/resources/kb-improvement.md +1 -1
- package/dist/public/skills/kibi-usage/resources/logic-ir.md +2 -2
- package/dist/public/skills/kibi-usage/resources/operation-access.md +29 -1
- package/dist/public/skills/kibi-usage/resources/ui-requirements.md +4 -4
- package/dist/public/skills/kibi-usage/resources/workflows.md +42 -25
- package/dist/public/telemetry-acceptance.d.ts +64 -0
- package/dist/public/telemetry-acceptance.d.ts.map +1 -1
- package/dist/public/telemetry-acceptance.js +143 -7
- package/dist/public/telemetry-remediation.d.ts.map +1 -1
- package/dist/public/telemetry-remediation.js +26 -10
- package/dist/relationships/shards.d.ts +13 -0
- package/dist/relationships/shards.d.ts.map +1 -1
- package/dist/relationships/shards.js +54 -28
- package/dist/runtime/cli-runtime.d.ts.map +1 -1
- package/dist/runtime/cli-runtime.js +44 -3
- package/dist/runtime/detached-snapshot.d.ts +38 -0
- package/dist/runtime/detached-snapshot.d.ts.map +1 -0
- package/dist/runtime/detached-snapshot.js +92 -0
- package/dist/schemas/entity.schema.json +122 -0
- package/dist/search-answer.d.ts +157 -0
- package/dist/search-answer.d.ts.map +1 -0
- package/dist/search-answer.js +846 -0
- package/dist/traceability/impact-knowledge.d.ts.map +1 -1
- package/dist/traceability/impact-knowledge.js +7 -0
- package/dist/traceability/symbol-extract.js +3 -3
- package/dist/traceability/temp-kb.d.ts.map +1 -1
- package/dist/traceability/temp-kb.js +12 -0
- package/dist/types/entities.d.ts +13 -0
- package/dist/types/entities.d.ts.map +1 -1
- package/dist/types/relationships.d.ts +1 -1
- package/dist/types/relationships.d.ts.map +1 -1
- package/dist/utils/branch-resolver.d.ts +37 -1
- package/dist/utils/branch-resolver.d.ts.map +1 -1
- package/dist/utils/branch-resolver.js +130 -3
- package/dist/utils/repo-relative-path.d.ts +18 -0
- package/dist/utils/repo-relative-path.d.ts.map +1 -0
- package/dist/utils/repo-relative-path.js +58 -0
- package/dist/utils/rule-registry.generated.d.ts +75 -3
- package/dist/utils/rule-registry.generated.d.ts.map +1 -1
- package/dist/utils/rule-registry.generated.js +89 -3
- 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 +4 -3
- package/dist/utils/strict-modeling.d.ts +1 -1
- package/dist/utils/strict-modeling.d.ts.map +1 -1
- package/dist/utils/strict-modeling.js +23 -3
- package/package.json +3 -3
- package/schema/entities.pl +22 -0
- package/schema/relationships.pl +14 -0
- package/schema/validation.pl +45 -1
- package/src/public/branch-resolver.ts +1 -0
- package/src/public/diagnostic-usage.ts +59 -1
- package/src/public/entity-origin.ts +175 -0
- package/src/public/impact/full-kb-quality.ts +1 -0
- package/src/public/impact/requirement-quality.ts +1 -1
- package/src/public/operations/catalog.ts +3 -0
- package/src/public/operations/check-executor.ts +15 -0
- package/src/public/operations/contracts.ts +75 -15
- package/src/public/operations/discovery-entities.ts +74 -0
- package/src/public/operations/discovery-executors.ts +88 -10
- package/src/public/operations/index.ts +1 -0
- package/src/public/operations/migration-plan.ts +30 -1
- package/src/public/operations/node-ports.ts +24 -3
- package/src/public/operations/origin-review.ts +375 -0
- package/src/public/operations/predicate-schema-conformance.ts +1 -1
- package/src/public/operations/repair-plan.ts +4 -0
- package/src/public/operations/result-envelope.ts +18 -6
- package/src/public/operations/runtime-types.ts +9 -0
- package/src/public/operations/schema6-check-actions.ts +699 -0
- package/src/public/operations/source-path-dangling.ts +81 -0
- package/src/public/operations/specs/bootstrap.ts +78 -4
- package/src/public/operations/specs/check-rules.generated.ts +15 -1
- package/src/public/operations/specs/check.ts +1 -1
- package/src/public/operations/specs/composite.ts +141 -0
- package/src/public/operations/specs/discovery.ts +9 -3
- package/src/public/operations/specs/modeling.ts +2 -2
- package/src/public/operations/specs/mutation-schemas.ts +49 -7
- package/src/public/operations/specs/mutation.ts +1 -1
- package/src/public/operations/specs/planning.ts +4 -4
- package/src/public/operations/specs/reporting.ts +13 -38
- package/src/public/operations/specs/upsert.ts +7 -1
- package/src/public/operations/symbol-repair-plan.ts +3 -1
- package/src/public/operations/types.ts +2 -0
- package/src/public/proof-receipt.ts +1 -0
- package/src/public/schemas/entity.ts +57 -0
- package/src/public/schemas/relationship.ts +2 -0
- package/src/public/skills/kibi-bootstrap/SKILL.md +52 -11
- package/src/public/skills/kibi-bootstrap/resources/bootstrap.md +12 -1
- package/src/public/skills/kibi-usage/SKILL.md +82 -18
- package/src/public/skills/kibi-usage/resources/fact-lanes.md +5 -5
- package/src/public/skills/kibi-usage/resources/kb-improvement.md +1 -1
- package/src/public/skills/kibi-usage/resources/logic-ir.md +2 -2
- package/src/public/skills/kibi-usage/resources/operation-access.md +29 -1
- package/src/public/skills/kibi-usage/resources/ui-requirements.md +4 -4
- package/src/public/skills/kibi-usage/resources/workflows.md +42 -25
- package/src/public/telemetry-acceptance-types.d.ts +4 -1
- package/src/public/telemetry-acceptance.ts +210 -7
- package/src/public/telemetry-remediation.ts +39 -10
- package/src/schemas/entity.schema.json +122 -0
- package/src/schemas/relationship.schema.json +2 -0
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Kibi — repo-local, per-branch, queryable long-term memory for software projects
|
|
3
|
+
Copyright (C) 2026 Piotr Franczyk
|
|
4
|
+
|
|
5
|
+
This program is free software: you can redistribute it and/or modify
|
|
6
|
+
it under the terms of the GNU Affero General Public License as published by
|
|
7
|
+
the Free Software Foundation, either version 3 of the License, or
|
|
8
|
+
(at your option) any later version.
|
|
9
|
+
|
|
10
|
+
This program is distributed in the hope that it will be useful,
|
|
11
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13
|
+
GNU Affero General Public License for more details.
|
|
14
|
+
|
|
15
|
+
You should have received a copy of the GNU Affero General Public License
|
|
16
|
+
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
17
|
+
*/
|
|
18
|
+
import { existsSync } from "node:fs";
|
|
19
|
+
import path from "node:path";
|
|
20
|
+
import { ENTITY_LANES, KB_PATHS, KB_ROOT } from "../../utils/kb-paths.js";
|
|
21
|
+
import { listLaneMarkdownFiles, readText, readTopLevelField, sliceFrontmatter, withTopLevelField, withoutTopLevelField, writeFileAtomically, } from "./kb-sources.js";
|
|
22
|
+
const URL_PATTERN = /^https?:\/\/\S+$/i;
|
|
23
|
+
const LEGACY_ROOT = "documentation/";
|
|
24
|
+
const SYMBOL_ID_LINE = /^[ \t]*-?[ \t]*id[ \t]*:[ \t]*(.+?)[ \t]*$/gm;
|
|
25
|
+
const SOURCE_EDIT_REFUSED = "the source field spans several lines, or editing it would change other frontmatter fields";
|
|
26
|
+
function scalarText(value) {
|
|
27
|
+
if (typeof value === "string")
|
|
28
|
+
return value.trim();
|
|
29
|
+
if (typeof value === "number")
|
|
30
|
+
return String(value);
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
function unquote(value) {
|
|
34
|
+
return value.replace(/^(['"])(.*)\1$/, "$2");
|
|
35
|
+
}
|
|
36
|
+
/** An authored value as plain text, the form plans record and compare. */
|
|
37
|
+
// implements REQ-core-validation-rules, REQ-kibi-schema6-migration, REQ-kibi-kb-lifecycle-integrity
|
|
38
|
+
export function shownSourceValue(value) {
|
|
39
|
+
return typeof value === "string" ? value : (JSON.stringify(value) ?? "");
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Read every authored entity's `source` field and id in one pass over the
|
|
43
|
+
* canonical lanes, plus the symbol ids of the symbols manifest. Only the id
|
|
44
|
+
* and source lines are parsed. Read-only.
|
|
45
|
+
*/
|
|
46
|
+
// implements REQ-core-validation-rules, REQ-cli-schema-migration, REQ-kibi-kb-lifecycle-integrity
|
|
47
|
+
export function scanAuthoredSources(workspaceRoot) {
|
|
48
|
+
const refs = [];
|
|
49
|
+
const entityIds = new Set();
|
|
50
|
+
for (const file of listLaneMarkdownFiles(workspaceRoot)) {
|
|
51
|
+
const content = readText(file.absolutePath);
|
|
52
|
+
if (content === null)
|
|
53
|
+
continue;
|
|
54
|
+
const slice = sliceFrontmatter(content);
|
|
55
|
+
if (slice === null)
|
|
56
|
+
continue;
|
|
57
|
+
const id = scalarText(readTopLevelField(slice.text, "id")) ||
|
|
58
|
+
path.basename(file.relativePath, ".md");
|
|
59
|
+
entityIds.add(id);
|
|
60
|
+
const value = readTopLevelField(slice.text, "source");
|
|
61
|
+
if (value === undefined || value === null)
|
|
62
|
+
continue;
|
|
63
|
+
if (typeof value === "string" && value.trim() === "")
|
|
64
|
+
continue;
|
|
65
|
+
refs.push({ entityId: id, file: file.relativePath, value });
|
|
66
|
+
}
|
|
67
|
+
const symbols = readText(path.join(workspaceRoot, KB_PATHS.symbolsManifest));
|
|
68
|
+
if (symbols !== null) {
|
|
69
|
+
for (const match of symbols.matchAll(SYMBOL_ID_LINE)) {
|
|
70
|
+
const id = unquote(match[1] ?? "");
|
|
71
|
+
if (id !== "")
|
|
72
|
+
entityIds.add(id);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return { refs, entityIds };
|
|
76
|
+
}
|
|
77
|
+
const LEGACY_LANE_ROOTS = new Set([...ENTITY_LANES, "symbols.yaml"]);
|
|
78
|
+
/**
|
|
79
|
+
* Resolve one authored `source` value: an existing workspace path (any
|
|
80
|
+
* `#anchor` suffix ignored), an existing entity id or an http(s) URL. With
|
|
81
|
+
* the entity's own `file`, a value naming that file (canonical or
|
|
82
|
+
* pre-canonical spelling, `./` and `#anchor` ignored, compared
|
|
83
|
+
* case-insensitively) resolves to `self`. A dangling
|
|
84
|
+
* `documentation/<lane>/...` or `<lane>/...` value carries the
|
|
85
|
+
* `.kb/<lane>/...` rewrite when that file exists.
|
|
86
|
+
*/
|
|
87
|
+
// implements REQ-core-validation-rules, REQ-kibi-schema6-migration, REQ-kibi-kb-lifecycle-integrity
|
|
88
|
+
export function resolveAuthoredSource(value, context) {
|
|
89
|
+
if (value === undefined || value === null)
|
|
90
|
+
return { kind: "missing" };
|
|
91
|
+
const text = scalarText(value);
|
|
92
|
+
if (text === undefined)
|
|
93
|
+
return { kind: "dangling" };
|
|
94
|
+
if (text === "")
|
|
95
|
+
return { kind: "missing" };
|
|
96
|
+
if (URL_PATTERN.test(text))
|
|
97
|
+
return { kind: "url" };
|
|
98
|
+
if (context.entityIds.has(text))
|
|
99
|
+
return { kind: "entity" };
|
|
100
|
+
const hash = text.indexOf("#");
|
|
101
|
+
const anchor = hash >= 0 ? text.slice(hash) : "";
|
|
102
|
+
const relative = (hash >= 0 ? text.slice(0, hash) : text)
|
|
103
|
+
.trim()
|
|
104
|
+
.replaceAll("\\", "/")
|
|
105
|
+
.replace(/^\.\//, "");
|
|
106
|
+
const own = context.file?.toLowerCase();
|
|
107
|
+
const exists = relative !== "" && context.exists(relative);
|
|
108
|
+
if (own !== undefined && relative.toLowerCase() === own) {
|
|
109
|
+
return { kind: "self", resolves: exists };
|
|
110
|
+
}
|
|
111
|
+
// Another existing file is provenance, even when its path would map onto
|
|
112
|
+
// the entity's own file under .kb/.
|
|
113
|
+
if (exists)
|
|
114
|
+
return { kind: "path" };
|
|
115
|
+
const lower = relative.toLowerCase();
|
|
116
|
+
const legacy = lower.startsWith(LEGACY_ROOT)
|
|
117
|
+
? lower.slice(LEGACY_ROOT.length)
|
|
118
|
+
: lower;
|
|
119
|
+
if (own !== undefined && `${KB_ROOT}/${legacy}` === own) {
|
|
120
|
+
return { kind: "self", resolves: false };
|
|
121
|
+
}
|
|
122
|
+
const rest = relative.startsWith(LEGACY_ROOT)
|
|
123
|
+
? relative.slice(LEGACY_ROOT.length)
|
|
124
|
+
: relative;
|
|
125
|
+
const lane = rest.split("/")[0] ?? "";
|
|
126
|
+
const target = `${KB_ROOT}/${rest}`;
|
|
127
|
+
if (LEGACY_LANE_ROOTS.has(lane) && context.exists(target)) {
|
|
128
|
+
return { kind: "dangling", rewrite: `${target}${anchor}` };
|
|
129
|
+
}
|
|
130
|
+
return { kind: "dangling" };
|
|
131
|
+
}
|
|
132
|
+
/** A memoized existence test confined to the workspace. */
|
|
133
|
+
// implements REQ-kibi-schema6-migration, REQ-kibi-kb-lifecycle-integrity
|
|
134
|
+
export function workspacePathExists(workspaceRoot) {
|
|
135
|
+
const root = path.resolve(workspaceRoot);
|
|
136
|
+
const cache = new Map();
|
|
137
|
+
return (relativePath) => {
|
|
138
|
+
const cached = cache.get(relativePath);
|
|
139
|
+
if (cached !== undefined)
|
|
140
|
+
return cached;
|
|
141
|
+
const absolute = path.resolve(root, relativePath);
|
|
142
|
+
const fromRoot = path.relative(root, absolute);
|
|
143
|
+
const exists = !fromRoot.startsWith("..") &&
|
|
144
|
+
!path.isAbsolute(fromRoot) &&
|
|
145
|
+
existsSync(absolute);
|
|
146
|
+
cache.set(relativePath, exists);
|
|
147
|
+
return exists;
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
function repairFor(ref, resolution) {
|
|
151
|
+
if (resolution.kind === "self") {
|
|
152
|
+
return {
|
|
153
|
+
...ref,
|
|
154
|
+
dangling: !resolution.resolves,
|
|
155
|
+
fix: { kind: "remove", reason: "self" },
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
if (resolution.kind !== "dangling")
|
|
159
|
+
return undefined;
|
|
160
|
+
return {
|
|
161
|
+
...ref,
|
|
162
|
+
dangling: true,
|
|
163
|
+
fix: resolution.rewrite !== undefined
|
|
164
|
+
? { kind: "rewrite", to: resolution.rewrite }
|
|
165
|
+
: { kind: "remove", reason: "dangling" },
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
function editedContent(content, fix) {
|
|
169
|
+
return fix.kind === "rewrite"
|
|
170
|
+
? withTopLevelField(content, "source", fix.to)
|
|
171
|
+
: withoutTopLevelField(content, "source");
|
|
172
|
+
}
|
|
173
|
+
/** Every repairable source value, sorted by entity id. Read-only. */
|
|
174
|
+
function classifySources(workspaceRoot) {
|
|
175
|
+
const scan = scanAuthoredSources(workspaceRoot);
|
|
176
|
+
const exists = workspacePathExists(workspaceRoot);
|
|
177
|
+
const repairs = [];
|
|
178
|
+
for (const ref of scan.refs) {
|
|
179
|
+
const repair = repairFor(ref, resolveAuthoredSource(ref.value, {
|
|
180
|
+
workspaceRoot,
|
|
181
|
+
entityIds: scan.entityIds,
|
|
182
|
+
exists,
|
|
183
|
+
file: ref.file,
|
|
184
|
+
}));
|
|
185
|
+
if (repair !== undefined)
|
|
186
|
+
repairs.push(repair);
|
|
187
|
+
}
|
|
188
|
+
return repairs.sort((left, right) => left.entityId.localeCompare(right.entityId) ||
|
|
189
|
+
left.file.localeCompare(right.file));
|
|
190
|
+
}
|
|
191
|
+
/** Mark the repairs whose edit would not read back as exactly that change. */
|
|
192
|
+
function withEditability(workspaceRoot, repairs) {
|
|
193
|
+
return repairs.map((repair) => {
|
|
194
|
+
const content = readText(path.join(workspaceRoot, repair.file));
|
|
195
|
+
if (content !== null && editedContent(content, repair.fix) !== null) {
|
|
196
|
+
return repair;
|
|
197
|
+
}
|
|
198
|
+
return {
|
|
199
|
+
...repair,
|
|
200
|
+
refused: content === null
|
|
201
|
+
? "the entity file cannot be read"
|
|
202
|
+
: SOURCE_EDIT_REFUSED,
|
|
203
|
+
};
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Every authored `source` value that resolves to nothing, sorted by entity
|
|
208
|
+
* id, with the fix `kibi migrate` makes and, when the edit is not safe, why.
|
|
209
|
+
* Each path is checked once per call. Read-only.
|
|
210
|
+
*/
|
|
211
|
+
// implements REQ-core-validation-rules, REQ-kibi-schema6-migration, REQ-kibi-kb-lifecycle-integrity
|
|
212
|
+
export function findDanglingSources(workspaceRoot) {
|
|
213
|
+
return withEditability(workspaceRoot, classifySources(workspaceRoot).filter((repair) => repair.dangling));
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Every authored `source` value `kibi migrate` rewrites or removes: the
|
|
217
|
+
* dangling ones plus existing values that name the entity's own file.
|
|
218
|
+
* Read-only.
|
|
219
|
+
*/
|
|
220
|
+
// implements REQ-kibi-schema6-migration, REQ-kibi-kb-lifecycle-integrity
|
|
221
|
+
export function findSourceRepairs(workspaceRoot) {
|
|
222
|
+
return withEditability(workspaceRoot, classifySources(workspaceRoot));
|
|
223
|
+
}
|
|
224
|
+
function plannedRepair(repair) {
|
|
225
|
+
const base = {
|
|
226
|
+
entityId: repair.entityId,
|
|
227
|
+
file: repair.file,
|
|
228
|
+
from: shownSourceValue(repair.value),
|
|
229
|
+
};
|
|
230
|
+
return repair.fix.kind === "rewrite"
|
|
231
|
+
? { ...base, to: repair.fix.to }
|
|
232
|
+
: { ...base, reason: repair.fix.reason };
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* The rewrite and removal records a migration plan lists for these repairs.
|
|
236
|
+
* Repairs Kibi cannot edit safely are left out; they need a person.
|
|
237
|
+
*/
|
|
238
|
+
// implements REQ-kibi-schema6-migration, REQ-kibi-kb-lifecycle-integrity
|
|
239
|
+
export function plannedSourcePathRepairs(repairs) {
|
|
240
|
+
const rewrites = [];
|
|
241
|
+
const removals = [];
|
|
242
|
+
for (const repair of repairs) {
|
|
243
|
+
if (repair.refused !== undefined)
|
|
244
|
+
continue;
|
|
245
|
+
const planned = plannedRepair(repair);
|
|
246
|
+
if ("to" in planned)
|
|
247
|
+
rewrites.push(planned);
|
|
248
|
+
else
|
|
249
|
+
removals.push(planned);
|
|
250
|
+
}
|
|
251
|
+
return { rewrites, removals };
|
|
252
|
+
}
|
|
253
|
+
function samePlannedRepair(left, right) {
|
|
254
|
+
if (left.entityId !== right.entityId || left.from !== right.from) {
|
|
255
|
+
return false;
|
|
256
|
+
}
|
|
257
|
+
if ("to" in left)
|
|
258
|
+
return "to" in right && left.to === right.to;
|
|
259
|
+
return "reason" in right && left.reason === right.reason;
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Repair each redundant or dead `source` value, editing only its line: a
|
|
263
|
+
* moved knowledge file is rewritten to its `.kb/` path, and a value naming
|
|
264
|
+
* the entity's own file or nothing Kibi can map is removed. With `planned`,
|
|
265
|
+
* only those repairs are applied, and only while the value still reads as
|
|
266
|
+
* planned. A value that cannot be edited safely is skipped with a reason.
|
|
267
|
+
* Idempotent: a repaired value is not found again.
|
|
268
|
+
*/
|
|
269
|
+
// implements REQ-kibi-schema6-migration, REQ-kibi-kb-lifecycle-integrity
|
|
270
|
+
export function applySourcePathRepairs(workspaceRoot, planned) {
|
|
271
|
+
const wanted = planned === undefined
|
|
272
|
+
? undefined
|
|
273
|
+
: new Map([...planned.rewrites, ...planned.removals].map((repair) => [
|
|
274
|
+
repair.file,
|
|
275
|
+
repair,
|
|
276
|
+
]));
|
|
277
|
+
const rewritten = [];
|
|
278
|
+
const removed = [];
|
|
279
|
+
const skipped = [];
|
|
280
|
+
for (const repair of classifySources(workspaceRoot)) {
|
|
281
|
+
const current = plannedRepair(repair);
|
|
282
|
+
if (wanted !== undefined) {
|
|
283
|
+
const plan = wanted.get(repair.file);
|
|
284
|
+
if (plan === undefined)
|
|
285
|
+
continue;
|
|
286
|
+
if (!samePlannedRepair(plan, current)) {
|
|
287
|
+
skipped.push({
|
|
288
|
+
file: repair.file,
|
|
289
|
+
reason: "source changed since planning",
|
|
290
|
+
});
|
|
291
|
+
continue;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
const absolute = path.join(workspaceRoot, repair.file);
|
|
295
|
+
const content = readText(absolute);
|
|
296
|
+
const next = content === null ? null : editedContent(content, repair.fix);
|
|
297
|
+
if (next === null) {
|
|
298
|
+
skipped.push({ file: repair.file, reason: SOURCE_EDIT_REFUSED });
|
|
299
|
+
continue;
|
|
300
|
+
}
|
|
301
|
+
writeFileAtomically(absolute, next);
|
|
302
|
+
if ("to" in current)
|
|
303
|
+
rewritten.push(current);
|
|
304
|
+
else
|
|
305
|
+
removed.push(current);
|
|
306
|
+
}
|
|
307
|
+
return { rewritten, removed, skipped };
|
|
308
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A requirement another requirement supersedes is retired and must be
|
|
3
|
+
* closed (the superseded-requirement-open rule). This module reads authored
|
|
4
|
+
* sources, so the migration can plan before the KB compiles: superseded
|
|
5
|
+
* requirements that are not closed, and supersession cycles, which no status
|
|
6
|
+
* edit can resolve.
|
|
7
|
+
*/
|
|
8
|
+
/** The terminal requirement status. */
|
|
9
|
+
export declare const CLOSED_REQUIREMENT_STATUS = "closed";
|
|
10
|
+
/** A superseded requirement whose status is not closed. */
|
|
11
|
+
export type SupersededClosure = Readonly<{
|
|
12
|
+
id: string;
|
|
13
|
+
/** Workspace-relative path of the requirement's file. */
|
|
14
|
+
path: string;
|
|
15
|
+
status: string;
|
|
16
|
+
supersededBy: readonly string[];
|
|
17
|
+
}>;
|
|
18
|
+
/** Requirements that supersede each other, directly or through a chain. */
|
|
19
|
+
export type SupersessionCycle = Readonly<{
|
|
20
|
+
members: readonly string[];
|
|
21
|
+
edges: readonly (readonly [string, string])[];
|
|
22
|
+
files: readonly string[];
|
|
23
|
+
}>;
|
|
24
|
+
export type SupersessionPlan = Readonly<{
|
|
25
|
+
closures: readonly SupersededClosure[];
|
|
26
|
+
cycles: readonly SupersessionCycle[];
|
|
27
|
+
}>;
|
|
28
|
+
/**
|
|
29
|
+
* Sets of nodes that reach each other through the given edges (every
|
|
30
|
+
* strongly connected component that contains a cycle), as sorted member
|
|
31
|
+
* lists sorted by first member.
|
|
32
|
+
*/
|
|
33
|
+
export declare function supersessionCycles(edges: readonly (readonly [string, string])[]): string[][];
|
|
34
|
+
/**
|
|
35
|
+
* Superseded requirements that are not closed, and supersession cycles,
|
|
36
|
+
* read from authored Markdown and relationship shards. Cycle members are
|
|
37
|
+
* listed only under their cycle. Read-only.
|
|
38
|
+
*/
|
|
39
|
+
export declare function planSupersededClosures(workspaceRoot: string): SupersessionPlan;
|
|
40
|
+
export type SupersededClosureResult = Readonly<{
|
|
41
|
+
closed: readonly SupersededClosure[];
|
|
42
|
+
skipped: readonly Readonly<{
|
|
43
|
+
path: string;
|
|
44
|
+
reason: string;
|
|
45
|
+
}>[];
|
|
46
|
+
}>;
|
|
47
|
+
/**
|
|
48
|
+
* Set `status: closed` on each superseded requirement that is not closed,
|
|
49
|
+
* editing only the status line (or appending it). Requirements in a
|
|
50
|
+
* supersession cycle are never touched. With `planned`, only those ids are
|
|
51
|
+
* closed. Idempotent: a closed requirement is not planned again.
|
|
52
|
+
*/
|
|
53
|
+
export declare function applySupersededClosures(workspaceRoot: string, planned?: ReadonlySet<string>): SupersededClosureResult;
|
|
54
|
+
//# sourceMappingURL=superseded-closure.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"superseded-closure.d.ts","sourceRoot":"","sources":["../../../src/operations/migration/superseded-closure.ts"],"names":[],"mappings":"AA+BA;;;;;;GAMG;AAEH,uCAAuC;AAEvC,eAAO,MAAM,yBAAyB,WAAW,CAAC;AAElD,2DAA2D;AAE3D,MAAM,MAAM,iBAAiB,GAAG,QAAQ,CAAC;IACvC,EAAE,EAAE,MAAM,CAAC;IACX,yDAAyD;IACzD,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;CACjC,CAAC,CAAC;AAEH,2EAA2E;AAE3E,MAAM,MAAM,iBAAiB,GAAG,QAAQ,CAAC;IACvC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3B,KAAK,EAAE,SAAS,CAAC,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EAAE,CAAC;IAC9C,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;CAC1B,CAAC,CAAC;AAGH,MAAM,MAAM,gBAAgB,GAAG,QAAQ,CAAC;IACtC,QAAQ,EAAE,SAAS,iBAAiB,EAAE,CAAC;IACvC,MAAM,EAAE,SAAS,iBAAiB,EAAE,CAAC;CACtC,CAAC,CAAC;AAmBH;;;;GAIG;AAEH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,SAAS,CAAC,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EAAE,GAC5C,MAAM,EAAE,EAAE,CA0BZ;AAgDD;;;;GAIG;AAEH,wBAAgB,sBAAsB,CACpC,aAAa,EAAE,MAAM,GACpB,gBAAgB,CA0ClB;AAGD,MAAM,MAAM,uBAAuB,GAAG,QAAQ,CAAC;IAC7C,MAAM,EAAE,SAAS,iBAAiB,EAAE,CAAC;IACrC,OAAO,EAAE,SAAS,QAAQ,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,EAAE,CAAC;CAChE,CAAC,CAAC;AAEH;;;;;GAKG;AAEH,wBAAgB,uBAAuB,CACrC,aAAa,EAAE,MAAM,EACrB,OAAO,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,GAC5B,uBAAuB,CAsBzB"}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Kibi — repo-local, per-branch, queryable long-term memory for software projects
|
|
3
|
+
Copyright (C) 2026 Piotr Franczyk
|
|
4
|
+
|
|
5
|
+
This program is free software: you can redistribute it and/or modify
|
|
6
|
+
it under the terms of the GNU Affero General Public License as published by
|
|
7
|
+
the Free Software Foundation, either version 3 of the License, or
|
|
8
|
+
(at your option) any later version.
|
|
9
|
+
|
|
10
|
+
This program is distributed in the hope that it will be useful,
|
|
11
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13
|
+
GNU Affero General Public License for more details.
|
|
14
|
+
|
|
15
|
+
You should have received a copy of the GNU Affero General Public License
|
|
16
|
+
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
17
|
+
*/
|
|
18
|
+
import path from "node:path";
|
|
19
|
+
import { extractFromMarkdown, } from "../../extractors/markdown.js";
|
|
20
|
+
import { readAllShards } from "../../relationships/shards.js";
|
|
21
|
+
import { listLaneMarkdownFiles, readText, withTopLevelField, writeFileAtomically, } from "./kb-sources.js";
|
|
22
|
+
/**
|
|
23
|
+
* A requirement another requirement supersedes is retired and must be
|
|
24
|
+
* closed (the superseded-requirement-open rule). This module reads authored
|
|
25
|
+
* sources, so the migration can plan before the KB compiles: superseded
|
|
26
|
+
* requirements that are not closed, and supersession cycles, which no status
|
|
27
|
+
* edit can resolve.
|
|
28
|
+
*/
|
|
29
|
+
/** The terminal requirement status. */
|
|
30
|
+
// implements REQ-cli-schema-migration, REQ-kibi-kb-lifecycle-integrity
|
|
31
|
+
export const CLOSED_REQUIREMENT_STATUS = "closed";
|
|
32
|
+
function reachable(adjacency, start) {
|
|
33
|
+
const seen = new Set();
|
|
34
|
+
const queue = [...(adjacency.get(start) ?? [])];
|
|
35
|
+
while (queue.length > 0) {
|
|
36
|
+
const node = queue.shift();
|
|
37
|
+
if (seen.has(node))
|
|
38
|
+
continue;
|
|
39
|
+
seen.add(node);
|
|
40
|
+
queue.push(...(adjacency.get(node) ?? []));
|
|
41
|
+
}
|
|
42
|
+
return seen;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Sets of nodes that reach each other through the given edges (every
|
|
46
|
+
* strongly connected component that contains a cycle), as sorted member
|
|
47
|
+
* lists sorted by first member.
|
|
48
|
+
*/
|
|
49
|
+
// implements REQ-core-validation-rules, REQ-kibi-kb-lifecycle-integrity
|
|
50
|
+
export function supersessionCycles(edges) {
|
|
51
|
+
const adjacency = new Map();
|
|
52
|
+
for (const [from, to] of edges) {
|
|
53
|
+
adjacency.set(from, [...(adjacency.get(from) ?? []), to]);
|
|
54
|
+
}
|
|
55
|
+
const reach = new Map();
|
|
56
|
+
const reachOf = (node) => {
|
|
57
|
+
let nodes = reach.get(node);
|
|
58
|
+
if (nodes === undefined) {
|
|
59
|
+
nodes = reachable(adjacency, node);
|
|
60
|
+
reach.set(node, nodes);
|
|
61
|
+
}
|
|
62
|
+
return nodes;
|
|
63
|
+
};
|
|
64
|
+
const components = new Map();
|
|
65
|
+
for (const start of [...adjacency.keys()].sort()) {
|
|
66
|
+
const fromStart = reachOf(start);
|
|
67
|
+
if (!fromStart.has(start))
|
|
68
|
+
continue;
|
|
69
|
+
const members = [...fromStart]
|
|
70
|
+
.filter((node) => reachOf(node).has(start))
|
|
71
|
+
.sort();
|
|
72
|
+
components.set(members.join("\u0000"), members);
|
|
73
|
+
}
|
|
74
|
+
return [...components.values()].sort((left, right) => (left[0] ?? "").localeCompare(right[0] ?? ""));
|
|
75
|
+
}
|
|
76
|
+
function readRequirementsAndEdges(workspaceRoot) {
|
|
77
|
+
const requirements = new Map();
|
|
78
|
+
const relationships = [];
|
|
79
|
+
for (const file of listLaneMarkdownFiles(workspaceRoot, ["requirements"])) {
|
|
80
|
+
try {
|
|
81
|
+
const result = extractFromMarkdown(file.absolutePath);
|
|
82
|
+
requirements.set(result.entity.id, {
|
|
83
|
+
id: result.entity.id,
|
|
84
|
+
status: String(result.entity.status ?? "").trim(),
|
|
85
|
+
path: file.relativePath,
|
|
86
|
+
});
|
|
87
|
+
relationships.push(...result.relationships);
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
// Unreadable requirements fail sync with their own diagnostic.
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
try {
|
|
94
|
+
relationships.push(...readAllShards(path.join(workspaceRoot, ".kb")));
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
// Malformed shards fail sync with their own diagnostic.
|
|
98
|
+
}
|
|
99
|
+
const edges = new Map();
|
|
100
|
+
for (const relationship of relationships) {
|
|
101
|
+
if (relationship.type !== "supersedes" ||
|
|
102
|
+
!requirements.has(relationship.to)) {
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
edges.set(`${relationship.from}\u0000${relationship.to}`, [
|
|
106
|
+
relationship.from,
|
|
107
|
+
relationship.to,
|
|
108
|
+
]);
|
|
109
|
+
}
|
|
110
|
+
return {
|
|
111
|
+
requirements,
|
|
112
|
+
edges: [...edges.values()].sort(([leftFrom, leftTo], [rightFrom, rightTo]) => leftFrom.localeCompare(rightFrom) || leftTo.localeCompare(rightTo)),
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Superseded requirements that are not closed, and supersession cycles,
|
|
117
|
+
* read from authored Markdown and relationship shards. Cycle members are
|
|
118
|
+
* listed only under their cycle. Read-only.
|
|
119
|
+
*/
|
|
120
|
+
// implements REQ-core-validation-rules, REQ-cli-schema-migration, REQ-kibi-kb-lifecycle-integrity
|
|
121
|
+
export function planSupersededClosures(workspaceRoot) {
|
|
122
|
+
const { requirements, edges } = readRequirementsAndEdges(workspaceRoot);
|
|
123
|
+
const cycles = supersessionCycles(edges);
|
|
124
|
+
const inCycle = new Set(cycles.flat());
|
|
125
|
+
const successors = new Map();
|
|
126
|
+
for (const [from, to] of edges) {
|
|
127
|
+
successors.set(to, [...(successors.get(to) ?? []), from]);
|
|
128
|
+
}
|
|
129
|
+
const closures = [];
|
|
130
|
+
for (const [id, supersededBy] of [...successors.entries()].sort(([left], [right]) => left.localeCompare(right))) {
|
|
131
|
+
const requirement = requirements.get(id);
|
|
132
|
+
if (requirement === undefined ||
|
|
133
|
+
inCycle.has(id) ||
|
|
134
|
+
requirement.status === CLOSED_REQUIREMENT_STATUS) {
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
closures.push({
|
|
138
|
+
id,
|
|
139
|
+
path: requirement.path,
|
|
140
|
+
status: requirement.status,
|
|
141
|
+
supersededBy: [...new Set(supersededBy)].sort(),
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
return {
|
|
145
|
+
closures,
|
|
146
|
+
cycles: cycles.map((members) => {
|
|
147
|
+
const memberSet = new Set(members);
|
|
148
|
+
return {
|
|
149
|
+
members,
|
|
150
|
+
edges: edges.filter(([from, to]) => memberSet.has(from) && memberSet.has(to)),
|
|
151
|
+
files: members
|
|
152
|
+
.map((member) => requirements.get(member)?.path)
|
|
153
|
+
.filter((file) => file !== undefined),
|
|
154
|
+
};
|
|
155
|
+
}),
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Set `status: closed` on each superseded requirement that is not closed,
|
|
160
|
+
* editing only the status line (or appending it). Requirements in a
|
|
161
|
+
* supersession cycle are never touched. With `planned`, only those ids are
|
|
162
|
+
* closed. Idempotent: a closed requirement is not planned again.
|
|
163
|
+
*/
|
|
164
|
+
// implements REQ-cli-schema-migration, REQ-kibi-kb-lifecycle-integrity
|
|
165
|
+
export function applySupersededClosures(workspaceRoot, planned) {
|
|
166
|
+
const closed = [];
|
|
167
|
+
const skipped = [];
|
|
168
|
+
for (const closure of planSupersededClosures(workspaceRoot).closures) {
|
|
169
|
+
if (planned !== undefined && !planned.has(closure.id))
|
|
170
|
+
continue;
|
|
171
|
+
const absolute = path.join(workspaceRoot, closure.path);
|
|
172
|
+
const content = readText(absolute);
|
|
173
|
+
const next = content === null
|
|
174
|
+
? null
|
|
175
|
+
: withTopLevelField(content, "status", CLOSED_REQUIREMENT_STATUS);
|
|
176
|
+
if (next === null) {
|
|
177
|
+
skipped.push({
|
|
178
|
+
path: closure.path,
|
|
179
|
+
reason: "status could not be set without changing other fields",
|
|
180
|
+
});
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
writeFileAtomically(absolute, next);
|
|
184
|
+
closed.push(closure);
|
|
185
|
+
}
|
|
186
|
+
return { closed, skipped };
|
|
187
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logic-modeling.d.ts","sourceRoot":"","sources":["../../../src/operations/modeling/logic-modeling.ts"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,WAAW,EAIjB,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"logic-modeling.d.ts","sourceRoot":"","sources":["../../../src/operations/modeling/logic-modeling.ts"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,WAAW,EAIjB,MAAM,mBAAmB,CAAC;AAQ3B,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC;IAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,mBAAmB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACjD,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,UAAU,EAAE,WAAW,CAAC;IACjC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,SAAS,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CACpD;AAUD,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAE3D;AAED,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,mBAAmB,GACzB,oBAAoB,CAkHtB"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import { logicSemanticKey, utf8Span, validateLogicIr, } from "../../logic/ir.js";
|
|
3
|
-
import { normalizeSemanticClause, semanticClaimKey, } from "../semantic-advisor/clauses.js";
|
|
3
|
+
import { modeledClaimRole, normalizeSemanticClause, semanticClaimKey, } from "../semantic-advisor/clauses.js";
|
|
4
4
|
import { semanticSourceHash } from "../semantic-advisor/shared.js";
|
|
5
5
|
function shortId(value) {
|
|
6
6
|
return createHash("sha256")
|
|
@@ -63,7 +63,7 @@ export function buildLogicApplyPlan(input) {
|
|
|
63
63
|
type: "fact",
|
|
64
64
|
id: ruleId,
|
|
65
65
|
properties: {
|
|
66
|
-
title:
|
|
66
|
+
title: `Rule: ${claimText}`,
|
|
67
67
|
status: "active",
|
|
68
68
|
source: input.source,
|
|
69
69
|
fact_kind: "rule",
|
|
@@ -98,9 +98,7 @@ export function buildLogicApplyPlan(input) {
|
|
|
98
98
|
{
|
|
99
99
|
claim_key: claimKey,
|
|
100
100
|
claim_text: claimText,
|
|
101
|
-
role:
|
|
102
|
-
? "normative"
|
|
103
|
-
: "descriptive",
|
|
101
|
+
role: modeledClaimRole(claimText, validation.normalized.modality),
|
|
104
102
|
status: "modeled",
|
|
105
103
|
span,
|
|
106
104
|
semantic_key: semanticKey,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model-requirement.d.ts","sourceRoot":"","sources":["../../../src/operations/modeling/model-requirement.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0CAA0C,CAAC;
|
|
1
|
+
{"version":3,"file":"model-requirement.d.ts","sourceRoot":"","sources":["../../../src/operations/modeling/model-requirement.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0CAA0C,CAAC;AAgBjF,OAAO,EACL,yBAAyB,EACzB,uBAAuB,EACxB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACL,iCAAiC,EACjC,uBAAuB,EACxB,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EACV,oBAAoB,EACpB,sBAAsB,EACvB,MAAM,wBAAwB,CAAC;AAUhC,YAAY,EACV,oBAAoB,EACpB,sBAAsB,GACvB,MAAM,wBAAwB,CAAC;AAkNhC,OAAO,EACL,iCAAiC,EACjC,uBAAuB,EACvB,yBAAyB,EACzB,uBAAuB,GACxB,CAAC;AAIF,wBAAgB,4BAA4B,CAC1C,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,OAAO,EAAE;IACP,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB,GACA,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CA4CzB;AA+OD,wBAAsB,4BAA4B,CAChD,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAIxB;AAED,wBAAsB,wBAAwB,CAC5C,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,oBAAoB,EAC1B,aAAa,EAAE,MAAM,EACrB,OAAO,CAAC,EAAE,gBAAgB,GACzB,OAAO,CAAC,sBAAsB,CAAC,CAgHjC;AAED,wBAAsB,uBAAuB,CAC3C,IAAI,EAAE,oBAAoB,EAC1B,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC,sBAAsB,CAAC,CAajC"}
|