kibi-cli 2.18.0 → 2.20.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 +2 -2
- package/dist/cli-operation-metadata.js +2 -2
- package/dist/cli-register-maintenance.js +1 -1
- package/dist/commands/doctor.js +11 -5
- package/dist/commands/engine.d.ts +2 -1
- package/dist/commands/engine.d.ts.map +1 -1
- package/dist/commands/engine.js +6 -1
- package/dist/commands/sync/manifest.d.ts +10 -0
- package/dist/commands/sync/manifest.d.ts.map +1 -1
- package/dist/commands/sync/manifest.js +27 -0
- package/dist/commands/sync/untracked-targets.d.ts +17 -0
- package/dist/commands/sync/untracked-targets.d.ts.map +1 -1
- package/dist/commands/sync/untracked-targets.js +43 -1
- package/dist/commands/sync.d.ts.map +1 -1
- package/dist/commands/sync.js +51 -2
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +33 -22
- package/dist/intent-search.d.ts +7 -0
- package/dist/intent-search.d.ts.map +1 -1
- package/dist/intent-search.js +66 -4
- package/dist/operations/modeling/predicate-applicability.d.ts.map +1 -1
- package/dist/operations/modeling/predicate-applicability.js +10 -4
- package/dist/operations/modeling/predicate-applyplan.d.ts.map +1 -1
- package/dist/operations/modeling/predicate-applyplan.js +16 -5
- package/dist/operations/modeling/predicate-catalog-4.d.ts.map +1 -1
- package/dist/operations/modeling/predicate-catalog-4.js +3 -0
- package/dist/operations/modeling/predicate-inference-1.d.ts.map +1 -1
- package/dist/operations/modeling/predicate-inference-1.js +34 -7
- package/dist/operations/modeling/predicate-score-3.js +1 -1
- package/dist/operations/modeling/predicate-types.d.ts +6 -0
- 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 +111 -0
- package/dist/operations/mutation/source-authoring.d.ts.map +1 -1
- package/dist/operations/mutation/source-authoring.js +5 -12
- package/dist/operations/mutation/types.d.ts +26 -0
- package/dist/operations/mutation/types.d.ts.map +1 -1
- package/dist/operations/mutation/upsert.d.ts.map +1 -1
- package/dist/operations/mutation/upsert.js +8 -2
- package/dist/operations/mutation/validate-upsert.d.ts.map +1 -1
- package/dist/operations/mutation/validate-upsert.js +116 -4
- package/dist/operations/mutation/warnings.d.ts +10 -0
- package/dist/operations/mutation/warnings.d.ts.map +1 -1
- package/dist/operations/mutation/warnings.js +26 -0
- package/dist/operations/mutation/what-if.d.ts +25 -0
- package/dist/operations/mutation/what-if.d.ts.map +1 -0
- package/dist/operations/mutation/what-if.js +59 -0
- package/dist/operations/planning/compile-intent.d.ts +15 -20
- package/dist/operations/planning/compile-intent.d.ts.map +1 -1
- package/dist/operations/planning/compile-intent.js +64 -53
- package/dist/operations/semantic-advisor/clauses.d.ts.map +1 -1
- package/dist/operations/semantic-advisor/clauses.js +8 -7
- package/dist/prolog/janitor.d.ts +26 -2
- package/dist/prolog/janitor.d.ts.map +1 -1
- package/dist/prolog/janitor.js +55 -3
- package/dist/prolog/store-lock.d.ts +47 -3
- package/dist/prolog/store-lock.d.ts.map +1 -1
- package/dist/prolog/store-lock.js +148 -11
- package/dist/proof/inspect.d.ts +1 -1
- package/dist/proof/inspect.d.ts.map +1 -1
- package/dist/proof/inspect.js +9 -2
- package/dist/public/operations/catalog.d.ts +97 -4
- package/dist/public/operations/catalog.d.ts.map +1 -1
- package/dist/public/operations/check-executor.d.ts +2 -2
- package/dist/public/operations/check-executor.d.ts.map +1 -1
- package/dist/public/operations/check-executor.js +35 -0
- package/dist/public/operations/check-format-shared.d.ts +16 -0
- package/dist/public/operations/check-format-shared.d.ts.map +1 -1
- package/dist/public/operations/check-format-shared.js +19 -0
- package/dist/public/operations/contracts.d.ts.map +1 -1
- package/dist/public/operations/contracts.js +11 -4
- package/dist/public/operations/discovery-executors.d.ts +39 -0
- package/dist/public/operations/discovery-executors.d.ts.map +1 -1
- package/dist/public/operations/discovery-executors.js +368 -3
- package/dist/public/operations/specs/composite.d.ts +1 -1
- package/dist/public/operations/specs/composite.js +1 -1
- package/dist/public/operations/specs/discovery.d.ts +52 -3
- package/dist/public/operations/specs/discovery.d.ts.map +1 -1
- package/dist/public/operations/specs/discovery.js +58 -3
- package/dist/public/operations/specs/upsert.d.ts +44 -0
- package/dist/public/operations/specs/upsert.d.ts.map +1 -1
- package/dist/public/operations/specs/upsert.js +14 -0
- package/dist/public/skills/kibi-usage/SKILL.md +44 -1
- package/dist/public/skills/kibi-usage/resources/fact-lanes.md +4 -2
- package/dist/runtime/cli-runtime.d.ts.map +1 -1
- package/dist/runtime/cli-runtime.js +7 -2
- package/dist/search-answer.d.ts +25 -3
- package/dist/search-answer.d.ts.map +1 -1
- package/dist/search-answer.js +96 -8
- package/dist/utils/branch-store.d.ts.map +1 -1
- package/dist/utils/branch-store.js +4 -2
- package/dist/utils/content-freshness.d.ts.map +1 -1
- package/dist/utils/content-freshness.js +12 -2
- package/dist/utils/symbol-manifest-layout.d.ts +9 -0
- package/dist/utils/symbol-manifest-layout.d.ts.map +1 -0
- package/dist/utils/symbol-manifest-layout.js +18 -0
- package/package.json +3 -3
- package/src/public/operations/check-executor.ts +44 -1
- package/src/public/operations/check-format-shared.ts +35 -1
- package/src/public/operations/contracts.ts +15 -4
- package/src/public/operations/discovery-executors.ts +484 -2
- package/src/public/operations/specs/composite.ts +1 -1
- package/src/public/operations/specs/discovery.ts +70 -3
- package/src/public/operations/specs/upsert.ts +15 -0
- package/src/public/skills/kibi-usage/SKILL.md +44 -1
- package/src/public/skills/kibi-usage/resources/fact-lanes.md +4 -2
|
@@ -707,6 +707,50 @@ export declare const upsertSpec: {
|
|
|
707
707
|
readonly default: false;
|
|
708
708
|
readonly description: "Validate the payload and return schema/modeling errors, a normalized preview and the semantic advisor receipt without writing the KB or workspace. Use it as the preflight before the real write.";
|
|
709
709
|
};
|
|
710
|
+
readonly plannedFacts: {
|
|
711
|
+
readonly type: "array";
|
|
712
|
+
readonly description: "dryRun only. Fact upsert payloads (type, id, properties, optional relationships) that will be written before this payload, typically the applyPlan entries kb_model returned. They are validated in order and staged with the payload, so a requires_predicate or requires_property target that does not exist yet resolves, its claim_key is read from the plan, and the contradiction preview runs against the KB as it would be after the whole batch (result: stagedFacts, whatIf). A conflict the batch would introduce, such as an allow and a deny permission_rule on the same key, is refused as the commit would refuse it. Rejected without dryRun: write the facts first.";
|
|
713
|
+
readonly items: {
|
|
714
|
+
readonly type: "object";
|
|
715
|
+
readonly required: readonly ["type", "id", "properties"];
|
|
716
|
+
readonly properties: {
|
|
717
|
+
readonly type: {
|
|
718
|
+
readonly type: "string";
|
|
719
|
+
readonly const: "fact";
|
|
720
|
+
};
|
|
721
|
+
readonly id: {
|
|
722
|
+
readonly type: "string";
|
|
723
|
+
readonly minLength: 1;
|
|
724
|
+
};
|
|
725
|
+
readonly properties: {
|
|
726
|
+
readonly type: "object";
|
|
727
|
+
};
|
|
728
|
+
readonly relationships: {
|
|
729
|
+
readonly type: "array";
|
|
730
|
+
readonly description: "Optional relationship rows to create in the same call. For requirement encoding, prefer `constrains` + `requires_property` for strict property facts or `requires_predicate` for ontology predicate facts. Side effect: asserts edges in KB.";
|
|
731
|
+
readonly items: {
|
|
732
|
+
readonly type: "object";
|
|
733
|
+
readonly required: readonly ["type", "from", "to"];
|
|
734
|
+
readonly properties: {
|
|
735
|
+
readonly type: {
|
|
736
|
+
readonly type: "string";
|
|
737
|
+
readonly enum: readonly ["depends_on", "specified_by", "verified_by", "validates", "implements", "covered_by", "executable_for", "constrained_by", "constrains", "requires_property", "requires_predicate", "requires_rule", "guards", "publishes", "consumes", "supersedes", "restates", "assumes", "exempts", "relates_to"];
|
|
738
|
+
readonly description: "Relationship type enum. Use only supported values. Direction semantics follow KB model (e.g., implements symbol->req, verified_by req/scenario->test, executable_for symbol->test).";
|
|
739
|
+
};
|
|
740
|
+
readonly from: {
|
|
741
|
+
readonly type: "string";
|
|
742
|
+
readonly description: "Source entity ID (must exist). Example: 'SYM-login-handler'.";
|
|
743
|
+
};
|
|
744
|
+
readonly to: {
|
|
745
|
+
readonly type: "string";
|
|
746
|
+
readonly description: "Target entity ID (must exist). Example: 'REQ-cli-gc'.";
|
|
747
|
+
};
|
|
748
|
+
};
|
|
749
|
+
};
|
|
750
|
+
};
|
|
751
|
+
};
|
|
752
|
+
};
|
|
753
|
+
};
|
|
710
754
|
readonly document: {
|
|
711
755
|
readonly type: "object";
|
|
712
756
|
readonly additionalProperties: false;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"upsert.d.ts","sourceRoot":"","sources":["../../../../src/public/operations/specs/upsert.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,aAAa,EAAE,MAAM,wCAAwC,CAAC;AAQvE,eAAO,MAAM,UAAU
|
|
1
|
+
{"version":3,"file":"upsert.d.ts","sourceRoot":"","sources":["../../../../src/public/operations/specs/upsert.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,aAAa,EAAE,MAAM,wCAAwC,CAAC;AAQvE,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA0DuC,CAAC"}
|
|
@@ -24,6 +24,20 @@ export const upsertSpec = {
|
|
|
24
24
|
default: false,
|
|
25
25
|
description: "Validate the payload and return schema/modeling errors, a normalized preview and the semantic advisor receipt without writing the KB or workspace. Use it as the preflight before the real write.",
|
|
26
26
|
},
|
|
27
|
+
plannedFacts: {
|
|
28
|
+
type: "array",
|
|
29
|
+
description: "dryRun only. Fact upsert payloads (type, id, properties, optional relationships) that will be written before this payload, typically the applyPlan entries kb_model returned. They are validated in order and staged with the payload, so a requires_predicate or requires_property target that does not exist yet resolves, its claim_key is read from the plan, and the contradiction preview runs against the KB as it would be after the whole batch (result: stagedFacts, whatIf). A conflict the batch would introduce, such as an allow and a deny permission_rule on the same key, is refused as the commit would refuse it. Rejected without dryRun: write the facts first.",
|
|
30
|
+
items: {
|
|
31
|
+
type: "object",
|
|
32
|
+
required: ["type", "id", "properties"],
|
|
33
|
+
properties: {
|
|
34
|
+
type: { type: "string", const: "fact" },
|
|
35
|
+
id: { type: "string", minLength: 1 },
|
|
36
|
+
properties: { type: "object" },
|
|
37
|
+
relationships: RELATIONSHIPS_SCHEMA,
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
},
|
|
27
41
|
document: {
|
|
28
42
|
type: "object",
|
|
29
43
|
additionalProperties: false,
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
id: kibi-usage
|
|
3
3
|
name: Kibi Usage
|
|
4
4
|
description: Use Kibi's source-first, exact-Git, migration-aware, proof-aware operations safely across MCP or the trusted local CLI, including partial completion repair.
|
|
5
|
-
version: 2.
|
|
5
|
+
version: 2.15.2
|
|
6
6
|
kibiCompatibility: ">=1.0.0"
|
|
7
7
|
tags:
|
|
8
8
|
- kibi
|
|
@@ -82,6 +82,41 @@ different workspace than the one you asked for; its `detail.reason` says why.
|
|
|
82
82
|
Use the CLI from your working directory instead: `npx --no-install kibi ...`
|
|
83
83
|
runs where you are and needs no `workspaceRoot`.
|
|
84
84
|
|
|
85
|
+
## Reading a hook snippet
|
|
86
|
+
|
|
87
|
+
On hosts where Kibi hooks are installed, a short block
|
|
88
|
+
arrives before you read or edit a file whose symbols are linked to
|
|
89
|
+
requirements. It is projected from `.kb/symbols.yaml`, not from the store, so
|
|
90
|
+
it is a pointer to the knowledge, never proof. Each line answers one question:
|
|
91
|
+
|
|
92
|
+
- `Kibi knowledge for <path> (symbol manifest):` and the `- REQ-… — <symbol
|
|
93
|
+
titles>` rows: the requirements the file's symbols implement, lead
|
|
94
|
+
requirement first. Read the lead requirement with `kb_query({id})` before
|
|
95
|
+
changing behavior.
|
|
96
|
+
- `REQ-… must keep true: FACT-…` (edit only): the ground facts the lead
|
|
97
|
+
requirement requires. An edit that breaks one of them is a requirement
|
|
98
|
+
change: supersede and remodel the requirement, do not code around the fact.
|
|
99
|
+
- `Decision: ADR-…` (edit only): the decision behind the lead requirement.
|
|
100
|
+
- `Covered by: TEST-…` and `Test code for: …`: the tests that prove the
|
|
101
|
+
file's symbols; run or update them with the edit.
|
|
102
|
+
- `The edit is inside <symbol>, which implements REQ-…`: the symbol the edit
|
|
103
|
+
lands in.
|
|
104
|
+
- `Next layer: …`: the exact `kb_query` and `kb_search(... sourceLocations)`
|
|
105
|
+
calls that return the full detail.
|
|
106
|
+
- The `kb_check({sourceFiles:[…], includeImpactDiagnostics:true,
|
|
107
|
+
includeWorkingTreeDiff:true})` line (edit only): run it after the edit. The
|
|
108
|
+
Stop hook reminds you once per session of files edited without it.
|
|
109
|
+
|
|
110
|
+
A file already shown this session gets only the one-line `Kibi: this edit to
|
|
111
|
+
<path> is inside <symbol>` update; the facts and tests from its first snippet
|
|
112
|
+
still apply. `Kibi: no symbol in <path> is linked to a requirement yet` means
|
|
113
|
+
the file is unowned: find the governing requirement with `kb_search` and
|
|
114
|
+
`sourceLocations`, then link a symbol to it with `implements` through
|
|
115
|
+
`kb_upsert`. Without a readable manifest (`Kibi: the hook could not read
|
|
116
|
+
.kb/symbols.yaml`) snippets are off for this session; `kb_query({sourceFile})`
|
|
117
|
+
still answers and `kibi sync` regenerates the manifest. The search tip and the
|
|
118
|
+
`.kb/` note appear once per session and need no action.
|
|
119
|
+
|
|
85
120
|
## Safe workflow
|
|
86
121
|
|
|
87
122
|
1. Always discover before you mutate: start with `kb_search`, then exact-filter with `kb_query`. Use
|
|
@@ -409,6 +444,14 @@ Prolog `symbol-coverage` also requires the test to `validates` the requirement
|
|
|
409
444
|
enough. Do not rely on legacy `// implements REQ-<area>-<behavior>` comments as the
|
|
410
445
|
traceability record.
|
|
411
446
|
|
|
447
|
+
Set the symbol's `title` to the behavioral member the extractor can locate in
|
|
448
|
+
`sourceFile`: `ClassName.methodName`, an exported function, or a class, not a
|
|
449
|
+
file or module name. A traceability link (`implements`, `covered_by`, …) from
|
|
450
|
+
a symbol whose `title` names no such member is refused by the granularity gate
|
|
451
|
+
when the file already has granular behavioral symbols, unless the symbol sets
|
|
452
|
+
`granularity_reason` to `config-artifact`, `module-level-behavior`,
|
|
453
|
+
`extractor-miss`, `legacy-link` or `test-suite`.
|
|
454
|
+
|
|
412
455
|
## Complete Logical Coverage
|
|
413
456
|
|
|
414
457
|
Decompose all atomic normative clauses into `claim_key`/`claim_text` entries in
|
|
@@ -68,14 +68,16 @@ id: FACT-SUSPENDED-PUBLISH-DENIED
|
|
|
68
68
|
status: active
|
|
69
69
|
fact_kind: predicate
|
|
70
70
|
predicate_name: permission_rule
|
|
71
|
-
predicate_args: [suspended_user, publish,
|
|
71
|
+
predicate_args: [suspended_user, publish, article, deny]
|
|
72
72
|
polarity: deny
|
|
73
|
-
canonical_key: permission_rule(suspended_user,publish,
|
|
73
|
+
canonical_key: permission_rule(suspended_user,publish,article,deny)
|
|
74
74
|
claim_key: <advisor-issued key for this exact clause>
|
|
75
75
|
claim_text: Suspended users must not publish articles.
|
|
76
76
|
relationship: { type: requires_predicate, from: REQ-SUSPENDED-PUBLISH-DENIED, to: FACT-SUSPENDED-PUBLISH-DENIED }
|
|
77
77
|
```
|
|
78
78
|
|
|
79
|
+
Inferred bindings drop the article and singularise the resource (`articles` becomes `article`, `any analysis request` and `analysis requests` both become `analysis_request`), so an allow and a deny on the same actor, action and resource share one key. Grants read the same as `allowed`: `may`, `can`, `is allowed to`, `are permitted to`, `must be able to`, `are able to`, `have permission to` and `are entitled to` all select `permission_rule` with `polarity: assert`.
|
|
80
|
+
|
|
79
81
|
If another current requirement links an `assert` fact with the same predicate namespace, name, and ordered arguments, `domain-contradictions` reports the pair. More complex semantic conflicts require a shared canonical schema and arguments; do not assume Kibi can prove arbitrary equivalence between differently shaped predicates.
|
|
80
82
|
|
|
81
83
|
The full logical representation of a requirement is the conjunction of all of its linked ground property and predicate terms. Conditions, exceptions, permissions, and ordering constraints remain explicit arguments of their declared schemas. Contradiction detection therefore depends on equivalent prose reusing the same predicate name, argument roles, ordered canonical values, and opposing polarity rather than inventing synonymous terms.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli-runtime.d.ts","sourceRoot":"","sources":["../../src/runtime/cli-runtime.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"cli-runtime.d.ts","sourceRoot":"","sources":["../../src/runtime/cli-runtime.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAKV,gBAAgB,EAEhB,cAAc,EACf,MAAM,uCAAuC,CAAC;AAC/C,OAAO,EAEL,KAAK,qBAAqB,EAE3B,MAAM,6BAA6B,CAAC;AAOrC,wBAAgB,wBAAwB,CACtC,UAAU,EAAE,qBAAqB,GAChC,MAAM,CAOR;AA2GD,wBAAgB,gBAAgB,CAC9B,OAAO,GAAE,cAAmB,GAC3B,gBAAgB,CAgJlB"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
-
import { retryAttachAfterBreakingStaleLock } from "../prolog/store-lock.js";
|
|
2
|
+
import { noteDeadHolderBeforeAttach, retryAttachAfterBreakingStaleLock, } from "../prolog/store-lock.js";
|
|
3
3
|
import { EngineClient } from "../engine.js";
|
|
4
4
|
import { CapabilityRegistryCache, ensureCapabilityRegistry, } from "../plugins/registry.js";
|
|
5
5
|
import { nodeFilesystem, nodeGit, nodeNetwork, } from "../public/operations/node-ports.js";
|
|
@@ -186,8 +186,13 @@ export function createCliRuntime(options = {}) {
|
|
|
186
186
|
await prolog.start?.();
|
|
187
187
|
const kbPath = attachment.storePath;
|
|
188
188
|
if (!usesEngine) {
|
|
189
|
+
// implements REQ-core-journaled-engine-persistence
|
|
190
|
+
// A killed holder never makes kb_attach fail, so note it first.
|
|
191
|
+
const recordTakeover = noteDeadHolderBeforeAttach(kbPath);
|
|
189
192
|
let attached = await prolog.query(`kb_attach('${quoteProlog(kbPath)}')`);
|
|
190
|
-
if (
|
|
193
|
+
if (attached.success)
|
|
194
|
+
recordTakeover();
|
|
195
|
+
else {
|
|
191
196
|
attached = await retryAttachAfterBreakingStaleLock(prolog, kbPath, attached);
|
|
192
197
|
}
|
|
193
198
|
if (!attached.success) {
|
package/dist/search-answer.d.ts
CHANGED
|
@@ -66,12 +66,21 @@ export type SearchAnswerVerdict = Readonly<{
|
|
|
66
66
|
export type SearchAnswerException = SearchAnswerEntity & Readonly<{
|
|
67
67
|
approvedBy?: string;
|
|
68
68
|
}>;
|
|
69
|
+
/**
|
|
70
|
+
* A linked fact says what it states in its typed form, so an agent can read
|
|
71
|
+
* `has_role(alice, admin)` or `user.role_assignment max_roles lte 2` without
|
|
72
|
+
* opening the entity, and `ask` is the exact kb_query that answers precise
|
|
73
|
+
* questions about the same predicate or subject.
|
|
74
|
+
*/
|
|
75
|
+
export type SearchAnswerFact = SearchAnswerEntity & Readonly<{
|
|
76
|
+
factKind?: string;
|
|
77
|
+
claim?: string;
|
|
78
|
+
ask?: string;
|
|
79
|
+
}>;
|
|
69
80
|
export type SearchAnswerRequirement = SearchAnswerEntity & Readonly<{
|
|
70
81
|
score: number;
|
|
71
82
|
via: string;
|
|
72
|
-
facts: readonly
|
|
73
|
-
factKind?: string;
|
|
74
|
-
})[];
|
|
83
|
+
facts: readonly SearchAnswerFact[];
|
|
75
84
|
scenarios: readonly SearchAnswerEntity[];
|
|
76
85
|
tests: readonly SearchAnswerTest[];
|
|
77
86
|
adrs: readonly SearchAnswerEntity[];
|
|
@@ -85,6 +94,17 @@ export type SearchAnswerScope = Readonly<{
|
|
|
85
94
|
snapshotId: string;
|
|
86
95
|
syncedAt: string | null;
|
|
87
96
|
}>;
|
|
97
|
+
/**
|
|
98
|
+
* A matched fact, scenario, test or symbol that no requirement owns, with
|
|
99
|
+
* its 1-based `rank` in the search results. When the top-ranked match is
|
|
100
|
+
* here, the governing list was reached through lower-ranked matches, and
|
|
101
|
+
* the answer says so instead of presenting those requirements as the top
|
|
102
|
+
* match's.
|
|
103
|
+
*/
|
|
104
|
+
export type SearchAnswerUngoverned = SearchAnswerFact & Readonly<{
|
|
105
|
+
type: string;
|
|
106
|
+
rank: number;
|
|
107
|
+
}>;
|
|
88
108
|
export type SearchAnswer = Readonly<{
|
|
89
109
|
version: "kibi.search-answer.v1";
|
|
90
110
|
governing: readonly SearchAnswerRequirement[];
|
|
@@ -93,6 +113,7 @@ export type SearchAnswer = Readonly<{
|
|
|
93
113
|
supersededBy?: string;
|
|
94
114
|
})[];
|
|
95
115
|
observations: readonly SearchAnswerEntity[];
|
|
116
|
+
ungoverned: readonly SearchAnswerUngoverned[];
|
|
96
117
|
scope: SearchAnswerScope;
|
|
97
118
|
truncated: boolean;
|
|
98
119
|
note: string;
|
|
@@ -110,6 +131,7 @@ export declare const SEARCH_ANSWER_LIMITS: {
|
|
|
110
131
|
readonly rationale: 3;
|
|
111
132
|
readonly notGoverning: 5;
|
|
112
133
|
readonly observations: 3;
|
|
134
|
+
readonly ungoverned: 5;
|
|
113
135
|
/** Entity rows loaded per answer, the matched seeds included. */
|
|
114
136
|
readonly entityLoads: 70;
|
|
115
137
|
readonly maxBytes: 16384;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search-answer.d.ts","sourceRoot":"","sources":["../src/search-answer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAW5D,OAAO,KAAK,EACV,UAAU,EAEX,MAAM,sCAAsC,CAAC;AAI9C;;;;;;;;;;;;;;GAcG;AACH,MAAM,MAAM,kBAAkB,GAAG,QAAQ,CAAC;IACxC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC,CAAC;AAEH;;;GAGG;AAEH,MAAM,MAAM,gBAAgB,GAAG,kBAAkB,GAAG,QAAQ,CAAC;IAAE,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAE9E,sEAAsE;AAEtE,MAAM,MAAM,qBAAqB,GAAG,kBAAkB,GACpD,QAAQ,CAAC;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAElD,0EAA0E;AAE1E,MAAM,MAAM,mBAAmB,GAAG,QAAQ,CAAC;IACzC,KAAK,EAAE,uBAAuB,GAAG,sBAAsB,CAAC;IACxD,MAAM,EAAE,eAAe,GAAG,YAAY,CAAC;IACvC,uEAAuE;IACvE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC,CAAC;AAEH;;;;;GAKG;AAEH,MAAM,MAAM,mBAAmB,GAAG,QAAQ,CAAC;IACzC,IAAI,EACA,0BAA0B,GAC1B,qBAAqB,GACrB,wBAAwB,GACxB,qBAAqB,GACrB,qBAAqB,CAAC;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;CAC7B,CAAC,CAAC;AAGH,MAAM,MAAM,mBAAmB,GAAG,QAAQ,CAAC;IACzC;;;;OAIG;IACH,MAAM,EAAE,eAAe,GAAG,YAAY,GAAG,SAAS,GAAG,MAAM,CAAC;IAC5D,SAAS,EAAE,SAAS,mBAAmB,EAAE,CAAC;CAC3C,CAAC,CAAC;AAEH,sDAAsD;AAEtD,MAAM,MAAM,qBAAqB,GAAG,kBAAkB,GACpD,QAAQ,CAAC;IAAE,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"search-answer.d.ts","sourceRoot":"","sources":["../src/search-answer.ts"],"names":[],"mappings":"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"}
|
package/dist/search-answer.js
CHANGED
|
@@ -43,6 +43,19 @@ const ROW_KEYS = [
|
|
|
43
43
|
"approved_by",
|
|
44
44
|
"source",
|
|
45
45
|
"sourceFile",
|
|
46
|
+
"predicate_namespace",
|
|
47
|
+
"predicate_name",
|
|
48
|
+
"predicate_args",
|
|
49
|
+
"polarity",
|
|
50
|
+
"subject_key",
|
|
51
|
+
"property_key",
|
|
52
|
+
"operator",
|
|
53
|
+
"value_type",
|
|
54
|
+
"value_string",
|
|
55
|
+
"value_int",
|
|
56
|
+
"value_number",
|
|
57
|
+
"value_bool",
|
|
58
|
+
"unit",
|
|
46
59
|
];
|
|
47
60
|
// implements REQ-kibi-search-answer-layer-v2
|
|
48
61
|
export const SEARCH_ANSWER_LIMITS = {
|
|
@@ -52,6 +65,7 @@ export const SEARCH_ANSWER_LIMITS = {
|
|
|
52
65
|
rationale: 3,
|
|
53
66
|
notGoverning: 5,
|
|
54
67
|
observations: 3,
|
|
68
|
+
ungoverned: 5,
|
|
55
69
|
/** Entity rows loaded per answer, the matched seeds included. */
|
|
56
70
|
entityLoads: 70,
|
|
57
71
|
maxBytes: 16_384,
|
|
@@ -76,6 +90,40 @@ function brief(entity) {
|
|
|
76
90
|
...(status ? { status } : {}),
|
|
77
91
|
};
|
|
78
92
|
}
|
|
93
|
+
function queryCall(args) {
|
|
94
|
+
return `kb_query(${JSON.stringify(args)})`;
|
|
95
|
+
}
|
|
96
|
+
/** Typed statement and follow-up query of a linked fact, by fact kind. */
|
|
97
|
+
// implements REQ-kibi-query-fact-filters
|
|
98
|
+
function factDetail(fact) {
|
|
99
|
+
const factKind = text(fact.fact_kind);
|
|
100
|
+
const base = factKind ? { factKind } : {};
|
|
101
|
+
const predicate = text(fact.predicate_name);
|
|
102
|
+
if (factKind === "predicate" && predicate) {
|
|
103
|
+
const args = Array.isArray(fact.predicate_args)
|
|
104
|
+
? fact.predicate_args.map(text).join(", ")
|
|
105
|
+
: text(fact.predicate_args);
|
|
106
|
+
const polarity = text(fact.polarity) === "deny" ? " [deny]" : "";
|
|
107
|
+
return {
|
|
108
|
+
...base,
|
|
109
|
+
claim: `${predicate}(${args})${polarity}`,
|
|
110
|
+
ask: queryCall({ predicate }),
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
const subjectKey = text(fact.subject_key);
|
|
114
|
+
const propertyKey = text(fact.property_key);
|
|
115
|
+
if (factKind === "property_value" && subjectKey && propertyKey) {
|
|
116
|
+
const unit = text(fact.unit);
|
|
117
|
+
const valueType = text(fact.value_type) || "string";
|
|
118
|
+
const value = text(fact[`value_${valueType}`]);
|
|
119
|
+
const claim = `${subjectKey} ${propertyKey} ${text(fact.operator) || "eq"} ${value}${unit ? ` ${unit}` : ""}`;
|
|
120
|
+
return { ...base, claim, ask: queryCall({ subjectKey, propertyKey }) };
|
|
121
|
+
}
|
|
122
|
+
if (factKind === "subject" && subjectKey) {
|
|
123
|
+
return { ...base, claim: subjectKey, ask: queryCall({ subjectKey }) };
|
|
124
|
+
}
|
|
125
|
+
return base;
|
|
126
|
+
}
|
|
79
127
|
function edgesGoal(ids) {
|
|
80
128
|
const idList = ids.map((id) => `'${escapeAtom(id)}'`).join(",");
|
|
81
129
|
return `findall([Rel,From,To], (member(Rel, [${ANSWER_RELATIONSHIPS.join(",")}]), kb_relationship(Rel, From, To), (member(From, [${idList}]); member(To, [${idList}]))), Edges)`;
|
|
@@ -466,11 +514,12 @@ export async function buildSearchAnswer(prolog, matches, options = {}) {
|
|
|
466
514
|
candidates.set(owner, { score, via });
|
|
467
515
|
};
|
|
468
516
|
const observations = [];
|
|
517
|
+
const ungoverned = [];
|
|
469
518
|
const rationaleRows = new Map();
|
|
470
519
|
// A matched test may verify a scenario rather than a requirement; its
|
|
471
520
|
// targets are resolved to their governing requirements after the loop.
|
|
472
521
|
const testTargets = [];
|
|
473
|
-
for (const match of seeds) {
|
|
522
|
+
for (const [index, match] of seeds.entries()) {
|
|
474
523
|
const id = text(match.entity.id);
|
|
475
524
|
const entity = graph.row(id) ?? match.entity;
|
|
476
525
|
const type = text(entity.type || match.entity.type);
|
|
@@ -501,6 +550,18 @@ export async function buildSearchAnswer(prolog, matches, options = {}) {
|
|
|
501
550
|
testTargets.push({ id, score: match.score, targets: owners });
|
|
502
551
|
continue;
|
|
503
552
|
}
|
|
553
|
+
if (owners.length === 0 && ["fact", "scenario", "symbol"].includes(type)) {
|
|
554
|
+
if (ungoverned.length < limits.ungoverned)
|
|
555
|
+
ungoverned.push({
|
|
556
|
+
...brief(entity),
|
|
557
|
+
...(type === "fact" ? factDetail(entity) : {}),
|
|
558
|
+
type,
|
|
559
|
+
rank: index + 1,
|
|
560
|
+
});
|
|
561
|
+
else
|
|
562
|
+
truncated = true;
|
|
563
|
+
continue;
|
|
564
|
+
}
|
|
504
565
|
for (const owner of owners)
|
|
505
566
|
propose(owner, match.score * 0.9, `${type} ${id}`);
|
|
506
567
|
}
|
|
@@ -515,6 +576,15 @@ export async function buildSearchAnswer(prolog, matches, options = {}) {
|
|
|
515
576
|
});
|
|
516
577
|
const targetEdges = graph.edgesOf(targetIds);
|
|
517
578
|
for (const test of testTargets) {
|
|
579
|
+
if (test.targets.length === 0) {
|
|
580
|
+
const row = graph.row(test.id);
|
|
581
|
+
const rank = seedIds.indexOf(test.id) + 1;
|
|
582
|
+
if (row !== null && ungoverned.length < limits.ungoverned)
|
|
583
|
+
ungoverned.push({ ...brief(row), type: "test", rank });
|
|
584
|
+
else if (row !== null)
|
|
585
|
+
truncated = true;
|
|
586
|
+
continue;
|
|
587
|
+
}
|
|
518
588
|
for (const target of test.targets) {
|
|
519
589
|
// A target that some requirement specifies is a scenario: lift the
|
|
520
590
|
// test to that requirement. Anything else is a directly verified
|
|
@@ -666,10 +736,10 @@ export async function buildSearchAnswer(prolog, matches, options = {}) {
|
|
|
666
736
|
...brief(req.entity),
|
|
667
737
|
score: req.score,
|
|
668
738
|
via: req.via,
|
|
669
|
-
facts: rowsOf(plan.facts).map((fact) => {
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
}),
|
|
739
|
+
facts: rowsOf(plan.facts).map((fact) => ({
|
|
740
|
+
...brief(fact),
|
|
741
|
+
...factDetail(fact),
|
|
742
|
+
})),
|
|
673
743
|
scenarios: rowsOf(plan.scenarios).map(brief),
|
|
674
744
|
tests: rowsOf(testIds[index] ?? []).map((row) => ({
|
|
675
745
|
...brief(row),
|
|
@@ -699,20 +769,36 @@ export async function buildSearchAnswer(prolog, matches, options = {}) {
|
|
|
699
769
|
? verdicts.scope.syncedAt
|
|
700
770
|
: null,
|
|
701
771
|
};
|
|
772
|
+
ungoverned.sort((left, right) => left.rank - right.rank);
|
|
702
773
|
const answer = {
|
|
703
774
|
version: "kibi.search-answer.v1",
|
|
704
775
|
governing,
|
|
705
776
|
rationale,
|
|
706
777
|
notGoverning,
|
|
707
778
|
observations: observations.slice(0, limits.observations),
|
|
779
|
+
ungoverned,
|
|
708
780
|
scope,
|
|
709
781
|
truncated: truncated || graph.truncated,
|
|
710
|
-
note: governing.length
|
|
711
|
-
? "No current requirement matched or owns a matched entity. Absence here is not evidence that nothing governs the change; refine the query or pass sourceLocations."
|
|
712
|
-
: "Governing requirements are current requirements matched by the query or linked to a matched entity. Links are discovery, not proof. A verdict lists the contradiction and scenario-feasibility witnesses that name the requirement; none means no check named it, not that it is proven. Use kb_check and kb_coverage for consistency and proof status.",
|
|
782
|
+
note: answerNote(governing.length, ungoverned),
|
|
713
783
|
};
|
|
714
784
|
return fitSearchAnswer(answer, limits.maxBytes);
|
|
715
785
|
}
|
|
786
|
+
// implements REQ-search-answer-hygiene
|
|
787
|
+
/**
|
|
788
|
+
* How to read the layer. When the top-ranked match is owned by no
|
|
789
|
+
* requirement, the note says so first: the governing list, if any, came from
|
|
790
|
+
* lower-ranked matches and is not the top match's requirement.
|
|
791
|
+
*/
|
|
792
|
+
function answerNote(governingCount, ungoverned) {
|
|
793
|
+
const top = ungoverned.find((entry) => entry.rank === 1);
|
|
794
|
+
const lead = top === undefined
|
|
795
|
+
? ""
|
|
796
|
+
: `The top-ranked match ${top.id} (${top.type}) is linked to no requirement${governingCount === 0 ? "" : "; the governing requirements below were reached through lower-ranked matches"}. `;
|
|
797
|
+
return (lead +
|
|
798
|
+
(governingCount === 0
|
|
799
|
+
? "No current requirement matched or owns a matched entity. Absence here is not evidence that nothing governs the change; refine the query or pass sourceLocations."
|
|
800
|
+
: "Governing requirements are current requirements matched by the query or linked to a matched entity. Links are discovery, not proof. A verdict lists the contradiction and scenario-feasibility witnesses that name the requirement; none means no check named it, not that it is proven. Use kb_check and kb_coverage for consistency and proof status."));
|
|
801
|
+
}
|
|
716
802
|
function byteSize(value) {
|
|
717
803
|
return Buffer.byteLength(JSON.stringify(value), "utf8");
|
|
718
804
|
}
|
|
@@ -737,6 +823,7 @@ function withoutExcerpt(entity) {
|
|
|
737
823
|
const ANSWER_TRIM_ORDER = [
|
|
738
824
|
"observations",
|
|
739
825
|
"notGoverning",
|
|
826
|
+
"ungoverned",
|
|
740
827
|
"rationale",
|
|
741
828
|
];
|
|
742
829
|
const REQUIREMENT_TRIM_ORDER = [
|
|
@@ -791,6 +878,7 @@ export function fitSearchAnswer(answer, maxBytes = SEARCH_ANSWER_LIMITS.maxBytes
|
|
|
791
878
|
rationale: current.rationale.map((adr) => clipRationale(adr, titleChars)),
|
|
792
879
|
notGoverning: clipAll(current.notGoverning),
|
|
793
880
|
observations: clipAll(current.observations),
|
|
881
|
+
ungoverned: clipAll(current.ungoverned),
|
|
794
882
|
};
|
|
795
883
|
// Excerpts are the most expendable text: drop them before any entry.
|
|
796
884
|
for (let index = current.rationale.length - 1; index >= 0 && over(); index -= 1) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"branch-store.d.ts","sourceRoot":"","sources":["../../src/utils/branch-store.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"branch-store.d.ts","sourceRoot":"","sources":["../../src/utils/branch-store.ts"],"names":[],"mappings":"AA2BA,mEAAmE;AACnE,eAAO,MAAM,yBAAyB,8BAA8B,CAAC;AACrE,yCAAyC;AACzC,eAAO,MAAM,8BAA8B,8BAA8B,CAAC;AAE1E,MAAM,MAAM,gBAAgB,GACxB,SAAS,GACT,SAAS,GACT,YAAY,GACZ,YAAY,CAAC;AAEjB,MAAM,MAAM,qBAAqB,GAAG,QAAQ,CAAC;IAC3C,KAAK,EAAE,gBAAgB,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gBAAgB,EAAE,OAAO,CAAC;CAC3B,CAAC,CAAC;AAEH;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,aAAa,EAAE,MAAM,EACrB,MAAM,EAAE,MAAM,GACb,qBAAqB,CA0GvB;AAED;;;;GAIG;AAEH,wBAAgB,sBAAsB,CACpC,SAAS,EAAE,MAAM,GAChB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAiBhC;AAED;;;;;;GAMG;AAEH,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,MAAM,EACjB,GAAG,GAAE,IAAiB,GACrB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAmBhC;AAED,wBAAgB,iBAAiB,CAC/B,UAAU,EAAE,qBAAqB,GAChC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAWhC;AA6BD;;;;GAIG;AAEH,wBAAgB,sBAAsB,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,CAOpE;AAED,MAAM,MAAM,sBAAsB,GAAG,QAAQ,CAAC;IAC5C,oEAAoE;IACpE,QAAQ,EAAE,OAAO,CAAC;IAClB,0EAA0E;IAC1E,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B,CAAC,CAAC;AAEH;;;;;;GAMG;AAEH,wBAAgB,sBAAsB,CACpC,UAAU,EAAE,qBAAqB,GAChC,sBAAsB,CAwBxB;AAkBD;;;;;;GAMG;AAEH,wBAAgB,2BAA2B,CACzC,aAAa,EAAE,MAAM,EACrB,UAAU,EAAE,qBAAqB,EACjC,MAAM,EAAE,MAAM,GACb,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAwBhC"}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { existsSync, readFileSync, readdirSync, statSync, } from "node:fs";
|
|
6
6
|
import * as path from "node:path";
|
|
7
|
-
import { STORE_LOCK_TAKEOVER_VISIBLE_MS, classifyStoreLockHolder, readStoreLockOwner, readStoreLockTakeover, } from "../prolog/store-lock.js";
|
|
7
|
+
import { FOREIGN_STORE_LOCK_REASON_PREFIX, STORE_LOCK_TAKEOVER_VISIBLE_MS, classifyStoreLockHolder, readStoreLockOwner, readStoreLockTakeover, } from "../prolog/store-lock.js";
|
|
8
8
|
import { branchStoreManifestMatches, branchStorePath, legacyBranchStorePath, } from "./branch-store-locator.js";
|
|
9
9
|
import { ENTITY_LANES, KB_ROOT } from "./kb-paths.js";
|
|
10
10
|
/** Stale-reason code of a branch store that was never compiled. */
|
|
@@ -170,7 +170,9 @@ export function storeLockTakeoverReason(storePath, now = new Date()) {
|
|
|
170
170
|
brokenPid: record.brokenPid,
|
|
171
171
|
reason: record.reason,
|
|
172
172
|
at: record.at,
|
|
173
|
-
detail: `Kibi broke a stale branch-store lock at ${record.at} (${record.reason || "holder no longer running"}) and reattached. Nothing needs repair;
|
|
173
|
+
detail: `Kibi broke a stale branch-store lock at ${record.at} (${record.reason || "holder no longer running"}) and reattached. Nothing needs repair; ${record.reason.startsWith(FOREIGN_STORE_LOCK_REASON_PREFIX)
|
|
174
|
+
? "the lock files were copied with the .kb directory (for example by cp -a) while another workspace's engine held its own store."
|
|
175
|
+
: "a holder that died while it held the store usually means an engine or kibi prove run crashed or was killed."}`,
|
|
174
176
|
};
|
|
175
177
|
}
|
|
176
178
|
export function branchStoreReason(inspection) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"content-freshness.d.ts","sourceRoot":"","sources":["../../src/utils/content-freshness.ts"],"names":[],"mappings":"AAYA,uDAAuD;AACvD,eAAO,MAAM,yBAAyB,EAAE,WAAW,CAAC,MAAM,CAIxD,CAAC;AAEH,KAAK,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"content-freshness.d.ts","sourceRoot":"","sources":["../../src/utils/content-freshness.ts"],"names":[],"mappings":"AAYA,uDAAuD;AACvD,eAAO,MAAM,yBAAyB,EAAE,WAAW,CAAC,MAAM,CAIxD,CAAC;AAEH,KAAK,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;AAyJhD;;;GAGG;AAEH,wBAAgB,yBAAyB,CACvC,aAAa,EAAE,MAAM,EACrB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,SAAS,MAAM,EAAE,GACzB;IAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,CAkBvC"}
|
|
@@ -7,7 +7,7 @@ import { existsSync, readFileSync } from "node:fs";
|
|
|
7
7
|
import * as path from "node:path";
|
|
8
8
|
import { load as parseYAML } from "js-yaml";
|
|
9
9
|
import { hashManifestWithCoordinates } from "../commands/sync/cache.js";
|
|
10
|
-
import { isSymbolsManifestPath } from "./kb-paths.js";
|
|
10
|
+
import { KB_PATHS, isSymbolsManifestPath } from "./kb-paths.js";
|
|
11
11
|
/** Stale-reason codes that compare file times only. */
|
|
12
12
|
export const MTIME_SOURCE_REASON_CODES = new Set([
|
|
13
13
|
"indexed_source_newer",
|
|
@@ -35,6 +35,7 @@ function record(value) {
|
|
|
35
35
|
* source hashes, and the per-symbol `sourceHash` of the generated coordinate
|
|
36
36
|
* artifact. A file whose bytes match that evidence has not changed since it
|
|
37
37
|
* was compiled, however new its mtime (a fresh clone, a checkout, a touch).
|
|
38
|
+
* Without either kind of evidence a reason is kept.
|
|
38
39
|
*/
|
|
39
40
|
class CompiledContentEvidence {
|
|
40
41
|
workspaceRoot;
|
|
@@ -85,10 +86,19 @@ class CompiledContentEvidence {
|
|
|
85
86
|
if (this.coordinateHashes)
|
|
86
87
|
return this.coordinateHashes;
|
|
87
88
|
const byFile = new Map();
|
|
89
|
+
// The coordinate artifact is content evidence in its own right: kb_upsert
|
|
90
|
+
// and sync record each symbol's source hash there. Consult the canonical
|
|
91
|
+
// artifact even when its manifest was never hashed (an untracked,
|
|
92
|
+
// upsert-only `.kb/symbols.yaml` that sync could not see).
|
|
93
|
+
const artifacts = new Set([
|
|
94
|
+
path.resolve(this.workspaceRoot, KB_PATHS.symbolCoordinates),
|
|
95
|
+
]);
|
|
88
96
|
for (const key of Object.keys(this.hashes)) {
|
|
89
97
|
if (!isSymbolsManifestPath(key) || !key.endsWith("symbols.yaml"))
|
|
90
98
|
continue;
|
|
91
|
-
|
|
99
|
+
artifacts.add(path.resolve(this.workspaceRoot, path.dirname(key), "symbol-coordinates.yaml"));
|
|
100
|
+
}
|
|
101
|
+
for (const artifact of artifacts) {
|
|
92
102
|
if (!existsSync(artifact))
|
|
93
103
|
continue;
|
|
94
104
|
try {
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type Document } from "yaml";
|
|
2
|
+
/**
|
|
3
|
+
* Render the `symbols` sequence of a parsed manifest, and every collection
|
|
4
|
+
* inside it, as block YAML. `kibi init` writes `symbols: []`, a flow
|
|
5
|
+
* sequence, and kibi-cli before 2.18.0 appended to it, so older manifests
|
|
6
|
+
* keep every symbol on that one line. Returns true when the layout changed.
|
|
7
|
+
*/
|
|
8
|
+
export declare function blockifySymbolManifest(doc: Document): boolean;
|
|
9
|
+
//# sourceMappingURL=symbol-manifest-layout.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"symbol-manifest-layout.d.ts","sourceRoot":"","sources":["../../src/utils/symbol-manifest-layout.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,QAAQ,EAA8B,MAAM,MAAM,CAAC;AAEjE;;;;;GAKG;AAEH,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,QAAQ,GAAG,OAAO,CAO7D"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { isCollection, isSeq, visit } from "yaml";
|
|
2
|
+
/**
|
|
3
|
+
* Render the `symbols` sequence of a parsed manifest, and every collection
|
|
4
|
+
* inside it, as block YAML. `kibi init` writes `symbols: []`, a flow
|
|
5
|
+
* sequence, and kibi-cli before 2.18.0 appended to it, so older manifests
|
|
6
|
+
* keep every symbol on that one line. Returns true when the layout changed.
|
|
7
|
+
*/
|
|
8
|
+
// implements REQ-kibi-hooks-flow-manifest, REQ-core-persistence
|
|
9
|
+
export function blockifySymbolManifest(doc) {
|
|
10
|
+
const symbols = doc.get("symbols", true);
|
|
11
|
+
if (!isSeq(symbols) || symbols.flow !== true)
|
|
12
|
+
return false;
|
|
13
|
+
visit(symbols, (_key, node) => {
|
|
14
|
+
if (isCollection(node))
|
|
15
|
+
node.flow = false;
|
|
16
|
+
});
|
|
17
|
+
return true;
|
|
18
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kibi-cli",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.20.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Kibi CLI for knowledge base management",
|
|
6
6
|
"engines": {
|
|
@@ -235,8 +235,8 @@
|
|
|
235
235
|
"fast-glob": "^3.2.12",
|
|
236
236
|
"gray-matter": "^4.0.3",
|
|
237
237
|
"js-yaml": "^4.1.0",
|
|
238
|
-
"kibi-core": "^0.
|
|
239
|
-
"kibi-plugin-builtin": "^0.5.
|
|
238
|
+
"kibi-core": "^0.21.0",
|
|
239
|
+
"kibi-plugin-builtin": "^0.5.1",
|
|
240
240
|
"kibi-plugin-sdk": "^0.5.0",
|
|
241
241
|
"kibi-swipl": "^1.0.1",
|
|
242
242
|
"saxes": "^6.0.0",
|