kibi-cli 2.25.0 → 2.26.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli-errors.d.ts +14 -0
- package/dist/cli-errors.d.ts.map +1 -1
- package/dist/cli-errors.js +31 -0
- package/dist/commands/check.d.ts.map +1 -1
- package/dist/commands/check.js +28 -0
- package/dist/commands/migrate.d.ts +2 -0
- package/dist/commands/migrate.d.ts.map +1 -1
- package/dist/commands/migrate.js +115 -4
- package/dist/commands/sync/cache.d.ts +30 -0
- package/dist/commands/sync/cache.d.ts.map +1 -1
- package/dist/commands/sync/cache.js +61 -0
- package/dist/commands/sync/extraction.d.ts +6 -0
- package/dist/commands/sync/extraction.d.ts.map +1 -1
- package/dist/commands/sync/extraction.js +4 -1
- package/dist/commands/sync.d.ts.map +1 -1
- package/dist/commands/sync.js +27 -1
- package/dist/operations/bootstrap/claim-restatement.d.ts +37 -0
- package/dist/operations/bootstrap/claim-restatement.d.ts.map +1 -0
- package/dist/operations/bootstrap/claim-restatement.js +83 -0
- package/dist/operations/bootstrap/generate.d.ts.map +1 -1
- package/dist/operations/bootstrap/generate.js +23 -12
- package/dist/operations/bootstrap/intent-claims.d.ts +5 -2
- package/dist/operations/bootstrap/intent-claims.d.ts.map +1 -1
- package/dist/operations/bootstrap/intent-claims.js +44 -4
- package/dist/operations/migration/requirement-status.d.ts +41 -2
- package/dist/operations/migration/requirement-status.d.ts.map +1 -1
- package/dist/operations/migration/requirement-status.js +75 -7
- package/dist/operations/migration/schema6.d.ts +9 -5
- package/dist/operations/migration/schema6.d.ts.map +1 -1
- package/dist/operations/migration/schema6.js +82 -13
- package/dist/operations/migration/symbol-coordinates-refresh.d.ts +36 -0
- package/dist/operations/migration/symbol-coordinates-refresh.d.ts.map +1 -0
- package/dist/operations/migration/symbol-coordinates-refresh.js +99 -0
- package/dist/operations/mutation/source-authoring.d.ts +9 -0
- package/dist/operations/mutation/source-authoring.d.ts.map +1 -1
- package/dist/operations/mutation/source-authoring.js +20 -0
- package/dist/operations/mutation/stored-entity.d.ts +5 -0
- package/dist/operations/mutation/stored-entity.d.ts.map +1 -1
- package/dist/operations/mutation/uncompiled-source.d.ts +43 -0
- package/dist/operations/mutation/uncompiled-source.d.ts.map +1 -0
- package/dist/operations/mutation/uncompiled-source.js +115 -0
- package/dist/operations/mutation/upsert.d.ts +6 -0
- package/dist/operations/mutation/upsert.d.ts.map +1 -1
- package/dist/operations/mutation/upsert.js +32 -5
- package/dist/public/impact/analyzer.d.ts.map +1 -1
- package/dist/public/impact/analyzer.js +13 -3
- package/dist/public/impact/diagnostics.js +1 -1
- package/dist/public/impact/unowned-files.d.ts +31 -0
- package/dist/public/impact/unowned-files.d.ts.map +1 -0
- package/dist/public/impact/unowned-files.js +171 -0
- package/dist/public/operations/catalog.d.ts +1 -1
- package/dist/public/operations/discovery-entities.d.ts +11 -0
- package/dist/public/operations/discovery-entities.d.ts.map +1 -1
- package/dist/public/operations/discovery-entities.js +28 -0
- package/dist/public/operations/discovery-executors.d.ts.map +1 -1
- package/dist/public/operations/discovery-executors.js +13 -1
- package/dist/public/operations/result-envelope.d.ts +2 -0
- package/dist/public/operations/result-envelope.d.ts.map +1 -1
- package/dist/public/operations/result-envelope.js +1 -0
- package/dist/public/operations/source-relationship-parity.d.ts.map +1 -1
- package/dist/public/operations/source-relationship-parity.js +22 -7
- package/dist/public/operations/specs/check.d.ts +1 -1
- package/dist/public/operations/specs/check.js +1 -1
- package/dist/public/skills/kibi-bootstrap/SKILL.md +2 -2
- package/dist/public/skills/kibi-usage/SKILL.md +11 -5
- package/dist/traceability/git-change-snapshot.d.ts.map +1 -1
- package/dist/traceability/git-change-snapshot.js +44 -3
- package/dist/traceability/staged-diagnostics.d.ts +1 -1
- package/dist/traceability/staged-diagnostics.d.ts.map +1 -1
- package/dist/traceability/staged-migration.d.ts +13 -0
- package/dist/traceability/staged-migration.d.ts.map +1 -0
- package/dist/traceability/staged-migration.js +59 -0
- package/dist/traceability/staged-symbols-manifest.d.ts +11 -0
- package/dist/traceability/staged-symbols-manifest.d.ts.map +1 -1
- package/dist/traceability/staged-symbols-manifest.js +50 -16
- package/package.json +2 -2
- package/src/public/impact/analyzer.ts +21 -7
- package/src/public/impact/diagnostics.ts +1 -1
- package/src/public/impact/unowned-files.ts +229 -0
- package/src/public/operations/discovery-entities.ts +36 -0
- package/src/public/operations/discovery-executors.ts +17 -1
- package/src/public/operations/result-envelope.ts +3 -0
- package/src/public/operations/source-relationship-parity.ts +22 -7
- package/src/public/operations/specs/check.ts +1 -1
- package/src/public/skills/kibi-bootstrap/SKILL.md +2 -2
- package/src/public/skills/kibi-usage/SKILL.md +11 -5
|
@@ -21,16 +21,18 @@ import { FIRMNESS_FROM_ORIGIN_SCHEMA_VERSION } from "../../public/operations/dec
|
|
|
21
21
|
import { migrationAction, } from "../../public/operations/migration-plan.js";
|
|
22
22
|
import { CLOSE_SUPERSEDED_REQUIREMENTS_ACTION_ID, CLOSE_SUPERSEDED_REQUIREMENTS_CODE, MIGRATION_SYNC_ACTION_ID, MIGRATION_SYNC_CODE, SOURCE_PATH_REWRITE_ACTION_ID, SOURCE_PATH_REWRITE_CODE, closeSupersededRequirementsActionInput, exceptionUnapprovedActionInput, migrationSyncActionInput, sourcePathReviewActionInput, sourcePathRewriteActionInput, supersessionCycleReviewActionInput, } from "../../public/operations/schema6-check-actions.js";
|
|
23
23
|
import { readAllShards } from "../../relationships/shards.js";
|
|
24
|
+
import { KB_PATHS } from "../../utils/kb-paths.js";
|
|
24
25
|
import { CONTEXT_MISSING_TAG_CODE, SEMANTIC_TEXT_PIN_CODE, applyContextMissingTags, applySemanticTextPins, countByType, planContextMissingTags, planSemanticTextPins, } from "./entity-body-context.js";
|
|
25
26
|
import { FIRM_SUPERSEDE_ACKNOWLEDGE_CODE, applyFirmSupersedeAcknowledgement, planFirmSupersedeAcknowledgement, } from "./firm-supersede.js";
|
|
26
27
|
import { applyInventoryRederivation, applyInventoryRederivationDroppingGrounding, planInventoryRederivation, } from "./inventory-rederive.js";
|
|
27
28
|
import { listLaneMarkdownFiles } from "./kb-sources.js";
|
|
28
29
|
import { applyOriginBackfill, planOriginBackfill } from "./origin-backfill.js";
|
|
29
30
|
import { POLARITY_VALUE_BACKFILL_CODE, applyPolarityValueBackfill, planPolarityValueBackfill, } from "./polarity-values.js";
|
|
30
|
-
import { applyRequirementStatusMapping, planRequirementStatusMappings, } from "./requirement-status.js";
|
|
31
|
+
import { DELIVERED_REQUIREMENT_TAG, applyDeliveredStatusMappings, applyRequirementStatusMapping, planRequirementStatusMappings, } from "./requirement-status.js";
|
|
31
32
|
import { applySourcePathRepairs, findSourceRepairs, plannedSourcePathRepairs, } from "./source-paths.js";
|
|
32
33
|
import { applySupersededClosures, planSupersededClosures, } from "./superseded-closure.js";
|
|
33
34
|
import { SUPERSEDES_REASON_ACKNOWLEDGE_CODE, applySupersedesReasonAcknowledgement, planSupersedesReasonAcknowledgement, } from "./supersedes-reason.js";
|
|
35
|
+
import { coordinateRefreshFailureMessage, readGeneratedManifestBytes, refreshCoordinatesAfterMigration, } from "./symbol-coordinates-refresh.js";
|
|
34
36
|
import { SYMBOL_LEGACY_LINK_MARK_ACTION_ID, SYMBOL_LEGACY_LINK_MARK_CODE, applySymbolLegacyLinks, planSymbolLegacyLinks, } from "./symbol-legacy-links.js";
|
|
35
37
|
/** The KB schema generation that introduced entity `origin`. */
|
|
36
38
|
// implements REQ-kibi-schema6-migration, REQ-cli-schema-migration
|
|
@@ -56,6 +58,11 @@ export const SEMANTIC_INVENTORY_REDERIVE_DROP_GROUNDING_CODE = "semantic_invento
|
|
|
56
58
|
/** Review, applied only when approved by id: map a legacy requirement status. */
|
|
57
59
|
// implements REQ-cli-schema-migration
|
|
58
60
|
export const REQ_STATUS_VOCABULARY_MAP_CODE = "req_status_vocabulary_map";
|
|
61
|
+
/** Automatic: map delivery statuses to `closed` plus the tag `implemented`. */
|
|
62
|
+
// implements REQ-cli-schema-migration
|
|
63
|
+
export const REQ_STATUS_DELIVERED_MAP_CODE = "req_status_delivered_map";
|
|
64
|
+
// implements REQ-cli-schema-migration
|
|
65
|
+
export const REQ_STATUS_DELIVERED_MAP_ACTION_ID = "req-status-delivered-map";
|
|
59
66
|
/** Automatic: stamp `origin: {kind: migration}` on authored entities. */
|
|
60
67
|
// implements REQ-kibi-schema6-migration, REQ-cli-schema-migration
|
|
61
68
|
export const ENTITY_ORIGIN_BACKFILL_CODE = "entity_origin_backfill";
|
|
@@ -210,16 +217,52 @@ function plannedDrops(action) {
|
|
|
210
217
|
: []);
|
|
211
218
|
}
|
|
212
219
|
/**
|
|
213
|
-
*
|
|
214
|
-
*
|
|
215
|
-
*
|
|
216
|
-
|
|
217
|
-
|
|
220
|
+
* The automatic action for requirements whose status is delivery vocabulary
|
|
221
|
+
* (`implemented`, `done`, `completed`): sync cannot compile them, and their
|
|
222
|
+
* one lossless reading is `closed` plus the tag `implemented`.
|
|
223
|
+
*/
|
|
224
|
+
function deliveredStatusAction(findings) {
|
|
225
|
+
return migrationAction({
|
|
226
|
+
id: REQ_STATUS_DELIVERED_MAP_ACTION_ID,
|
|
227
|
+
code: REQ_STATUS_DELIVERED_MAP_CODE,
|
|
228
|
+
category: "schema",
|
|
229
|
+
safety: "automatic",
|
|
230
|
+
autoApplicable: true,
|
|
231
|
+
invocation: { kind: "cli", command_argv: ["kibi", "migrate", "--yes"] },
|
|
232
|
+
affectedEntityIds: findings.map((finding) => finding.requirementId),
|
|
233
|
+
affectedFiles: findings.map((finding) => finding.path),
|
|
234
|
+
postconditions: [{ rule: "req-status-vocabulary", findings: 0 }],
|
|
235
|
+
evidence: {
|
|
236
|
+
reason: "Delivery statuses are outside the entity schema, so kibi sync cannot compile these requirements and every store-backed tool misses them. Each becomes status closed with the tag implemented, which Kibi reads as a delivered requirement that still owes coverage; only the status line and the tags change.",
|
|
237
|
+
count: findings.length,
|
|
238
|
+
mappings: findings.map((finding) => ({
|
|
239
|
+
requirementId: finding.requirementId,
|
|
240
|
+
path: finding.path,
|
|
241
|
+
from: finding.status,
|
|
242
|
+
to: finding.automatic?.status ?? "closed",
|
|
243
|
+
tag: finding.automatic?.tag ?? DELIVERED_REQUIREMENT_TAG,
|
|
244
|
+
})),
|
|
245
|
+
},
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* Requirements whose status is outside the vocabulary. Delivery vocabulary
|
|
250
|
+
* gets one automatic action (see deliveredStatusAction). Every other status
|
|
251
|
+
* gets one review action (the target status is a semantic choice) carrying
|
|
252
|
+
* the suggested mapping and the inventory drift the requirement shows once
|
|
253
|
+
* mapped. With a suggestion it is executable when approved by id; the
|
|
254
|
+
* re-derivation of the latent drift depends on it.
|
|
218
255
|
*/
|
|
219
256
|
// implements REQ-cli-schema-migration, REQ-kibi-proposition-complete-ingestion
|
|
220
257
|
export function requirementStatusActions(workspaceRoot) {
|
|
221
258
|
const actions = [];
|
|
222
|
-
|
|
259
|
+
const findings = planRequirementStatusMappings(workspaceRoot);
|
|
260
|
+
const delivered = findings.filter((finding) => finding.automatic !== null);
|
|
261
|
+
if (delivered.length > 0)
|
|
262
|
+
actions.push(deliveredStatusAction(delivered));
|
|
263
|
+
for (const finding of findings) {
|
|
264
|
+
if (finding.automatic !== null)
|
|
265
|
+
continue;
|
|
223
266
|
const id = `req-status-vocabulary-map-${finding.requirementId}`;
|
|
224
267
|
const drift = finding.latentDrift;
|
|
225
268
|
const target = finding.suggestedStatus;
|
|
@@ -232,7 +275,9 @@ export function requirementStatusActions(workspaceRoot) {
|
|
|
232
275
|
invocation: target === null
|
|
233
276
|
? {
|
|
234
277
|
kind: "review",
|
|
235
|
-
instruction:
|
|
278
|
+
instruction: finding.extractionError === null
|
|
279
|
+
? `${finding.requirementId} (${finding.path}) has status ${finding.status}, which is not a requirement status, so it is skipped by the proof ladder and its semantic inventory is never validated. Set status to open, in_progress or closed (legacy: active, approved) in the file, or use proof_exempt to park it, then rerun kibi migrate.`
|
|
280
|
+
: `${finding.requirementId} (${finding.path}) has status ${finding.status}, which is not a status Kibi knows, so kibi sync cannot compile it (${finding.extractionError}) and kb_query, kb_coverage and kb_upsert do not see it. Set status to open, in_progress or closed in the file (closed with the tag implemented for delivered work), then run kibi sync and rerun kibi migrate.`,
|
|
236
281
|
}
|
|
237
282
|
: { kind: "cli", command_argv: approvalArgv([id]) },
|
|
238
283
|
affectedEntityIds: [finding.requirementId],
|
|
@@ -241,9 +286,14 @@ export function requirementStatusActions(workspaceRoot) {
|
|
|
241
286
|
dispositionRequired: true,
|
|
242
287
|
allowedDispositions: ["fixed", "deferred"],
|
|
243
288
|
evidence: {
|
|
244
|
-
reason:
|
|
289
|
+
reason: finding.extractionError === null
|
|
290
|
+
? `Status ${finding.status} is ADR or lifecycle vocabulary, not a requirement status: the requirement is skipped by the proof ladder and kibi sync never validates its semantic inventory.`
|
|
291
|
+
: `Status ${finding.status} is outside the entity schema, so kibi sync cannot compile the requirement at all.`,
|
|
245
292
|
status: finding.status,
|
|
246
293
|
suggestedStatus: target,
|
|
294
|
+
...(finding.extractionError === null
|
|
295
|
+
? {}
|
|
296
|
+
: { extractionError: finding.extractionError }),
|
|
247
297
|
...(target === null
|
|
248
298
|
? {}
|
|
249
299
|
: {
|
|
@@ -515,9 +565,13 @@ export function buildSchema6MigrationFragment(input) {
|
|
|
515
565
|
if (!plan.safe && plan.rederivableByDroppingGrounding)
|
|
516
566
|
actions.push(dropGroundingAction(plan));
|
|
517
567
|
}
|
|
518
|
-
// Requirements with a status outside the vocabulary:
|
|
519
|
-
//
|
|
520
|
-
|
|
568
|
+
// Requirements with a status outside the vocabulary: delivery statuses are
|
|
569
|
+
// mapped automatically; any other mapping is a review, and its latent drift
|
|
570
|
+
// is re-derived only after an approved mapping.
|
|
571
|
+
const statusActions = requirementStatusActions(input.workspaceRoot);
|
|
572
|
+
actions.push(...statusActions);
|
|
573
|
+
if (statusActions.some((action) => action.id === REQ_STATUS_DELIVERED_MAP_ACTION_ID))
|
|
574
|
+
sourceRewriteActionIds.push(REQ_STATUS_DELIVERED_MAP_ACTION_ID);
|
|
521
575
|
if (drift.some((plan) => !plan.safe)) {
|
|
522
576
|
diagnostics.push(`${drift.filter((plan) => !plan.safe).length} requirement inventory(ies) need a manual fix before kibi sync succeeds; see the semantic_inventory_review actions.`);
|
|
523
577
|
}
|
|
@@ -637,7 +691,9 @@ export function symbolLegacyLinkAction(workspaceRoot) {
|
|
|
637
691
|
autoApplicable: true,
|
|
638
692
|
invocation: { kind: "cli", command_argv: ["kibi", "migrate", "--yes"] },
|
|
639
693
|
affectedEntityIds: plan.targets.map((target) => target.id),
|
|
640
|
-
|
|
694
|
+
// A mark changes the record's coordinate identity, so the action also
|
|
695
|
+
// regenerates the coordinate artifact.
|
|
696
|
+
affectedFiles: [plan.manifestPath, KB_PATHS.symbolCoordinates],
|
|
641
697
|
postconditions: [{ rule: "symbol_granularity_violation", findings: 0 }],
|
|
642
698
|
evidence: {
|
|
643
699
|
reason: "These symbols link a source file coarsely while it declares narrower behavioral symbols, so the staged check (kibi check --staged) blocks the next commit that touches them. Each gets granularity_reason: legacy-link (accepted legacy granularity); no link moves and no other field changes.",
|
|
@@ -725,6 +781,12 @@ export async function applySchema6MigrationAction(action, context) {
|
|
|
725
781
|
applyRequirementStatusMapping(context.workspaceRoot, mapping.path, mapping.from, mapping.to);
|
|
726
782
|
return;
|
|
727
783
|
}
|
|
784
|
+
case REQ_STATUS_DELIVERED_MAP_CODE: {
|
|
785
|
+
const result = applyDeliveredStatusMappings(context.workspaceRoot, new Set(action.affectedEntityIds));
|
|
786
|
+
if (result.skipped.length > 0)
|
|
787
|
+
throw new Error(`Could not map the status of ${result.skipped.map((skip) => `${skip.path} (${skip.reason})`).join(", ")}; set status: closed and add the tag implemented by hand.`);
|
|
788
|
+
return;
|
|
789
|
+
}
|
|
728
790
|
case SEMANTIC_INVENTORY_REDERIVE_DROP_GROUNDING_CODE: {
|
|
729
791
|
const requirementId = action.affectedEntityIds[0];
|
|
730
792
|
const contractHash = action.evidence.contractHash;
|
|
@@ -737,6 +799,7 @@ export async function applySchema6MigrationAction(action, context) {
|
|
|
737
799
|
applyOriginBackfill(context.workspaceRoot, context.clock().toISOString());
|
|
738
800
|
return;
|
|
739
801
|
case SYMBOL_LEGACY_LINK_MARK_CODE: {
|
|
802
|
+
const before = readGeneratedManifestBytes(context.workspaceRoot);
|
|
740
803
|
const result = applySymbolLegacyLinks(context.workspaceRoot, {
|
|
741
804
|
...(typeof action.evidence.manifestHash === "string"
|
|
742
805
|
? { expectedHash: action.evidence.manifestHash }
|
|
@@ -745,6 +808,11 @@ export async function applySchema6MigrationAction(action, context) {
|
|
|
745
808
|
});
|
|
746
809
|
if (result.unmarked.length > 0)
|
|
747
810
|
throw new Error(`Could not mark ${result.unmarked.join(", ")} as legacy-link in place; add granularity_reason: legacy-link to them by hand.`);
|
|
811
|
+
// A legacy-link mark changes the record's coordinate identity; keep
|
|
812
|
+
// the generated artifact current so the next commit carries no drift.
|
|
813
|
+
const refresh = await refreshCoordinatesAfterMigration(context.workspaceRoot, before);
|
|
814
|
+
if (refresh.outcome === "failed")
|
|
815
|
+
console.warn(`Warning: ${coordinateRefreshFailureMessage(refresh.reason)}`);
|
|
748
816
|
return;
|
|
749
817
|
}
|
|
750
818
|
case CLOSE_SUPERSEDED_REQUIREMENTS_CODE: {
|
|
@@ -791,6 +859,7 @@ export const SCHEMA6_AUTOMATIC_CODES = new Set([
|
|
|
791
859
|
SUPERSEDES_REASON_ACKNOWLEDGE_CODE,
|
|
792
860
|
FIRM_SUPERSEDE_ACKNOWLEDGE_CODE,
|
|
793
861
|
SEMANTIC_INVENTORY_REDERIVE_CODE,
|
|
862
|
+
REQ_STATUS_DELIVERED_MAP_CODE,
|
|
794
863
|
ENTITY_ORIGIN_BACKFILL_CODE,
|
|
795
864
|
CLOSE_SUPERSEDED_REQUIREMENTS_CODE,
|
|
796
865
|
SOURCE_PATH_REWRITE_CODE,
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bytes of the symbols manifest and its generated coordinate artifact at
|
|
3
|
+
* their canonical paths; null for a file that does not exist.
|
|
4
|
+
*/
|
|
5
|
+
export type GeneratedManifestBytes = Readonly<{
|
|
6
|
+
symbols: string | null;
|
|
7
|
+
coordinates: string | null;
|
|
8
|
+
}>;
|
|
9
|
+
/** Snapshot taken before a migration writes, to tell what it rewrote. */
|
|
10
|
+
export declare function readGeneratedManifestBytes(workspaceRoot: string): GeneratedManifestBytes;
|
|
11
|
+
/** What the post-migration coordinate refresh did. */
|
|
12
|
+
export type MigrationCoordinateRefresh = {
|
|
13
|
+
outcome: "skipped";
|
|
14
|
+
} | {
|
|
15
|
+
outcome: "refreshed";
|
|
16
|
+
} | {
|
|
17
|
+
outcome: "failed";
|
|
18
|
+
reason: string;
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Refresh generated symbol coordinates the way
|
|
22
|
+
* `kibi sync --refresh-symbol-coordinates` does, after a migration rewrote or
|
|
23
|
+
* moved the symbols manifest. The coordinate artifact binds each record by an
|
|
24
|
+
* identity hash that includes `granularity_reason`, so a legacy-link mark
|
|
25
|
+
* leaves the committed coordinates stale; without this refresh the pre-commit
|
|
26
|
+
* generated-manifest gate rejects the first commit after a migration.
|
|
27
|
+
*
|
|
28
|
+
* Skipped when `before` shows the run left both files untouched, or when the
|
|
29
|
+
* manifest has no symbols. A refresh failure is returned, not thrown: the
|
|
30
|
+
* migration itself is complete, and the caller tells the user to refresh by
|
|
31
|
+
* hand before committing.
|
|
32
|
+
*/
|
|
33
|
+
export declare function refreshCoordinatesAfterMigration(workspaceRoot: string, before?: GeneratedManifestBytes): Promise<MigrationCoordinateRefresh>;
|
|
34
|
+
/** The line a migration prints when its coordinate refresh failed. */
|
|
35
|
+
export declare function coordinateRefreshFailureMessage(reason: string): string;
|
|
36
|
+
//# sourceMappingURL=symbol-coordinates-refresh.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"symbol-coordinates-refresh.d.ts","sourceRoot":"","sources":["../../../src/operations/migration/symbol-coordinates-refresh.ts"],"names":[],"mappings":"AA0BA;;;GAGG;AAEH,MAAM,MAAM,sBAAsB,GAAG,QAAQ,CAAC;IAC5C,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B,CAAC,CAAC;AAMH,yEAAyE;AAEzE,wBAAgB,0BAA0B,CACxC,aAAa,EAAE,MAAM,GACpB,sBAAsB,CAMxB;AAYD,sDAAsD;AAEtD,MAAM,MAAM,0BAA0B,GAClC;IAAE,OAAO,EAAE,SAAS,CAAA;CAAE,GACtB;IAAE,OAAO,EAAE,WAAW,CAAA;CAAE,GACxB;IAAE,OAAO,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAE1C;;;;;;;;;;;;GAYG;AAEH,wBAAsB,gCAAgC,CACpD,aAAa,EAAE,MAAM,EACrB,MAAM,CAAC,EAAE,sBAAsB,GAC9B,OAAO,CAAC,0BAA0B,CAAC,CA0CrC;AAED,sEAAsE;AAEtE,wBAAgB,+BAA+B,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEtE"}
|
|
@@ -0,0 +1,99 @@
|
|
|
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 { createHash } from "node:crypto";
|
|
19
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
20
|
+
import path from "node:path";
|
|
21
|
+
import { load as parseYAML } from "js-yaml";
|
|
22
|
+
import { resolveSymbolsManifestPaths } from "../../utils/manifest-paths.js";
|
|
23
|
+
import { republishPendingSourceReceipt } from "../mutation/source-authoring.js";
|
|
24
|
+
import { withSymbolCompilerLock } from "../mutation/symbol-compiler-lock.js";
|
|
25
|
+
function readOrNull(filePath) {
|
|
26
|
+
return existsSync(filePath) ? readFileSync(filePath, "utf8") : null;
|
|
27
|
+
}
|
|
28
|
+
/** Snapshot taken before a migration writes, to tell what it rewrote. */
|
|
29
|
+
// implements REQ-cli-migration-first-commit
|
|
30
|
+
export function readGeneratedManifestBytes(workspaceRoot) {
|
|
31
|
+
const paths = resolveSymbolsManifestPaths(workspaceRoot);
|
|
32
|
+
return {
|
|
33
|
+
symbols: readOrNull(paths.symbolsPath),
|
|
34
|
+
coordinates: readOrNull(paths.coordinatesPath),
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
function hasSymbols(content) {
|
|
38
|
+
try {
|
|
39
|
+
const parsed = parseYAML(content);
|
|
40
|
+
return Array.isArray(parsed?.symbols) && parsed.symbols.length > 0;
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
// An unreadable manifest is reported by the refresh itself.
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Refresh generated symbol coordinates the way
|
|
49
|
+
* `kibi sync --refresh-symbol-coordinates` does, after a migration rewrote or
|
|
50
|
+
* moved the symbols manifest. The coordinate artifact binds each record by an
|
|
51
|
+
* identity hash that includes `granularity_reason`, so a legacy-link mark
|
|
52
|
+
* leaves the committed coordinates stale; without this refresh the pre-commit
|
|
53
|
+
* generated-manifest gate rejects the first commit after a migration.
|
|
54
|
+
*
|
|
55
|
+
* Skipped when `before` shows the run left both files untouched, or when the
|
|
56
|
+
* manifest has no symbols. A refresh failure is returned, not thrown: the
|
|
57
|
+
* migration itself is complete, and the caller tells the user to refresh by
|
|
58
|
+
* hand before committing.
|
|
59
|
+
*/
|
|
60
|
+
// implements REQ-cli-migration-first-commit
|
|
61
|
+
export async function refreshCoordinatesAfterMigration(workspaceRoot, before) {
|
|
62
|
+
const after = readGeneratedManifestBytes(workspaceRoot);
|
|
63
|
+
if (after.symbols === null || !hasSymbols(after.symbols))
|
|
64
|
+
return { outcome: "skipped" };
|
|
65
|
+
if (before !== undefined &&
|
|
66
|
+
before.symbols === after.symbols &&
|
|
67
|
+
before.coordinates === after.coordinates)
|
|
68
|
+
return { outcome: "skipped" };
|
|
69
|
+
const { symbolsPath, coordinatesPath } = resolveSymbolsManifestPaths(workspaceRoot);
|
|
70
|
+
try {
|
|
71
|
+
const { refreshManifestCoordinates } = await import("../../commands/sync/manifest.js");
|
|
72
|
+
await withSymbolCompilerLock(workspaceRoot, () => refreshManifestCoordinates(symbolsPath, workspaceRoot, {
|
|
73
|
+
refreshSymbolCoordinates: true,
|
|
74
|
+
}));
|
|
75
|
+
// Files the migration moved are still untracked and pinned by a
|
|
76
|
+
// pending-source receipt; rebind each to its refreshed bytes so the next
|
|
77
|
+
// sync does not refuse it as hash drift. A file without a receipt is
|
|
78
|
+
// left alone.
|
|
79
|
+
for (const filePath of [symbolsPath, coordinatesPath]) {
|
|
80
|
+
if (!existsSync(filePath))
|
|
81
|
+
continue;
|
|
82
|
+
republishPendingSourceReceipt(workspaceRoot, path.relative(workspaceRoot, filePath).split(path.sep).join("/"), createHash("sha256")
|
|
83
|
+
.update(readFileSync(filePath, "utf8"), "utf8")
|
|
84
|
+
.digest("hex"));
|
|
85
|
+
}
|
|
86
|
+
return { outcome: "refreshed" };
|
|
87
|
+
}
|
|
88
|
+
catch (error) {
|
|
89
|
+
return {
|
|
90
|
+
outcome: "failed",
|
|
91
|
+
reason: error instanceof Error ? error.message : String(error),
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
/** The line a migration prints when its coordinate refresh failed. */
|
|
96
|
+
// implements REQ-cli-migration-first-commit
|
|
97
|
+
export function coordinateRefreshFailureMessage(reason) {
|
|
98
|
+
return `Could not refresh symbol coordinates after the migration (${reason}). Run 'kibi sync --refresh-symbol-coordinates' and stage .kb/symbols.yaml and .kb/symbol-coordinates.yaml before the first commit, or the pre-commit hook reports generated manifest drift.`;
|
|
99
|
+
}
|
|
@@ -43,6 +43,15 @@ export declare function normalizeAuthoredSourcePath(workspaceRoot: string, sourc
|
|
|
43
43
|
*/
|
|
44
44
|
export declare function configuredSourceTarget(workspaceRoot: string, type: string): string | undefined;
|
|
45
45
|
export declare function hasConfiguredSourceTarget(workspaceRoot: string, type: string): boolean;
|
|
46
|
+
/**
|
|
47
|
+
* The absolute authored document an upsert of an entity the store does not
|
|
48
|
+
* hold would write: the same resolution writeSourceForUpsert uses, so a check
|
|
49
|
+
* on that file judges the file the writer merges into. Undefined when the
|
|
50
|
+
* writer has no target (it reports DOCUMENT_PATH_REQUIRED itself).
|
|
51
|
+
*/
|
|
52
|
+
export declare function newEntitySourceTarget(context: OperationContext, input: UpsertInput): string | undefined;
|
|
53
|
+
/** The front matter of an authored document; throws on YAML it cannot parse. */
|
|
54
|
+
export declare function authoredFrontmatter(content: string): Record<string, unknown>;
|
|
46
55
|
/** Generated coordinate fields belong exclusively to `.kb/symbol-coordinates.yaml`. */
|
|
47
56
|
export declare const GENERATED_SYMBOL_FIELDS: readonly ["sourceLine", "sourceColumn", "sourceEndLine", "sourceEndColumn", "coordinatesGeneratedAt"];
|
|
48
57
|
export declare function manifestRelationships(item: unknown): Array<{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"source-authoring.d.ts","sourceRoot":"","sources":["../../../src/operations/mutation/source-authoring.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0CAA0C,CAAC;AAOjF,OAAO,KAAK,EAAqB,WAAW,EAAE,MAAM,YAAY,CAAC;AAEjE,MAAM,MAAM,kBAAkB,GAAG,QAAQ,CAAC;IACxC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,OAAO,GAAG,QAAQ,CAAC;IACzB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,OAAO,EAAE,OAAO,CAAC;CAClB,CAAC,CAAC;AAmBH,wBAAgB,yBAAyB,CACvC,aAAa,EAAE,MAAM,EACrB,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,MAAM,GAChB,IAAI,CAiBN;AAED,KAAK,SAAS,GAAG,QAAQ,CAAC;IAAE,KAAK,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,IAAI,CAAA;CAAE,CAAC,CAAC;AAExD,8EAA8E;AAE9E,wBAAgB,aAAa,CAAC,YAAY,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAOpE;AAED;;;;GAIG;AAEH,wBAAgB,gBAAgB,CAC9B,YAAY,EAAE,MAAM,EACpB,KAAK,EAAE,SAAS,GAAG,IAAI,GACtB,IAAI,CAON;AAeD;;;;GAIG;AAEH,wBAAgB,0BAA0B,CACxC,aAAa,EAAE,MAAM,EACrB,YAAY,EAAE,MAAM,GACnB,IAAI,CAMN;AAED;;;;;;GAMG;AAEH,wBAAgB,6BAA6B,CAC3C,aAAa,EAAE,MAAM,EACrB,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,MAAM,GAChB,OAAO,CA8BT;AAgBD,wBAAgB,0BAA0B,CACxC,aAAa,EAAE,MAAM,EACrB,QAAQ,EAAE,MAAM,GACf,MAAM,CAqCR;AAED,wBAAgB,2BAA2B,CACzC,aAAa,EAAE,MAAM,EACrB,MAAM,EAAE,MAAM,GACb,MAAM,CAoBR;AAkCD;;;;GAIG;AACH,wBAAgB,sBAAsB,CACpC,aAAa,EAAE,MAAM,EACrB,IAAI,EAAE,MAAM,GACX,MAAM,GAAG,SAAS,CAYpB;AAED,wBAAgB,yBAAyB,CACvC,aAAa,EAAE,MAAM,EACrB,IAAI,EAAE,MAAM,GACX,OAAO,CAET;
|
|
1
|
+
{"version":3,"file":"source-authoring.d.ts","sourceRoot":"","sources":["../../../src/operations/mutation/source-authoring.ts"],"names":[],"mappings":"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"}
|
|
@@ -248,6 +248,26 @@ function sourcePath(context, input, entity, existing) {
|
|
|
248
248
|
}
|
|
249
249
|
return resolveContainedSourcePath(context.workspaceRoot, relative);
|
|
250
250
|
}
|
|
251
|
+
/**
|
|
252
|
+
* The absolute authored document an upsert of an entity the store does not
|
|
253
|
+
* hold would write: the same resolution writeSourceForUpsert uses, so a check
|
|
254
|
+
* on that file judges the file the writer merges into. Undefined when the
|
|
255
|
+
* writer has no target (it reports DOCUMENT_PATH_REQUIRED itself).
|
|
256
|
+
*/
|
|
257
|
+
// implements REQ-kibi-uncompiled-source-visibility
|
|
258
|
+
export function newEntitySourceTarget(context, input) {
|
|
259
|
+
try {
|
|
260
|
+
return sourcePath(context, input, { id: input.id }, undefined);
|
|
261
|
+
}
|
|
262
|
+
catch {
|
|
263
|
+
return undefined;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
/** The front matter of an authored document; throws on YAML it cannot parse. */
|
|
267
|
+
// implements REQ-kibi-uncompiled-source-visibility
|
|
268
|
+
export function authoredFrontmatter(content) {
|
|
269
|
+
return bodyAndFrontmatter(content).frontmatter;
|
|
270
|
+
}
|
|
251
271
|
/**
|
|
252
272
|
* Front matter keys an upsert never writes: runtime provenance/timestamps
|
|
253
273
|
* belong to the compiled entity, not to the authored source artifact, and
|
|
@@ -9,6 +9,11 @@ export type StoredEntityLookup = {
|
|
|
9
9
|
readonly exists: () => Promise<boolean>;
|
|
10
10
|
/** The stored entity, loaded only when one exists. */
|
|
11
11
|
readonly entity: () => Promise<StoredEntity>;
|
|
12
|
+
/**
|
|
13
|
+
* The entity's own relationships when they come from its authored file
|
|
14
|
+
* rather than the store (an entity the store does not hold yet).
|
|
15
|
+
*/
|
|
16
|
+
readonly relationships?: readonly Readonly<Record<string, unknown>>[];
|
|
12
17
|
};
|
|
13
18
|
/**
|
|
14
19
|
* One read of the entity an upsert replaces, shared by every step of the
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stored-entity.d.ts","sourceRoot":"","sources":["../../../src/operations/mutation/stored-entity.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0CAA0C,CAAC;AAE3E;;;GAGG;AACH,MAAM,MAAM,YAAY,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,IAAI,GAAG,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"stored-entity.d.ts","sourceRoot":"","sources":["../../../src/operations/mutation/stored-entity.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0CAA0C,CAAC;AAE3E;;;GAGG;AACH,MAAM,MAAM,YAAY,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,IAAI,GAAG,SAAS,CAAC;AAGhF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,+CAA+C;IAC/C,QAAQ,CAAC,MAAM,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;IACxC,sDAAsD;IACtD,QAAQ,CAAC,MAAM,EAAE,MAAM,OAAO,CAAC,YAAY,CAAC,CAAC;IAC7C;;;OAGG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EAAE,CAAC;CACvE,CAAC;AAGF;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,IAAI,CAAC,UAAU,EAAE,OAAO,CAAC,EACjC,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,MAAM,GACX,kBAAkB,CAsBpB"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { OperationContext } from "../../public/operations/runtime-types.js";
|
|
2
|
+
import type { StoredEntityLookup } from "./stored-entity.js";
|
|
3
|
+
import type { RelationshipInput, UpsertInput } from "./types.js";
|
|
4
|
+
/**
|
|
5
|
+
* An authored document for an entity the compiled store does not hold: the
|
|
6
|
+
* file the source-first writer would merge an upsert into.
|
|
7
|
+
*/
|
|
8
|
+
export type UncompiledAuthoredSource = Readonly<{
|
|
9
|
+
/** Workspace-relative path. */
|
|
10
|
+
path: string;
|
|
11
|
+
absolute: string;
|
|
12
|
+
content: string;
|
|
13
|
+
/**
|
|
14
|
+
* The entity as its file states it: the extracted entity when the file
|
|
15
|
+
* compiles, its front matter when it does not.
|
|
16
|
+
*/
|
|
17
|
+
stored: Readonly<Record<string, unknown>>;
|
|
18
|
+
/** Why kibi sync cannot compile the file as authored; null when it can. */
|
|
19
|
+
extractionError: string | null;
|
|
20
|
+
}>;
|
|
21
|
+
/**
|
|
22
|
+
* The authored document an upsert of `input` would merge into although the
|
|
23
|
+
* store does not hold the entity: a file left out of the last sync (one sync
|
|
24
|
+
* could not extract, or one written since). Null when the writer would
|
|
25
|
+
* create a new file, writes a symbol manifest, or the file declares another
|
|
26
|
+
* entity. A file whose front matter does not parse is refused here: the
|
|
27
|
+
* writer could not merge into it either.
|
|
28
|
+
*/
|
|
29
|
+
export declare function readUncompiledAuthoredSource(context: OperationContext, input: UpsertInput): Promise<UncompiledAuthoredSource | null>;
|
|
30
|
+
/**
|
|
31
|
+
* The store lookup for an upsert whose entity exists only in its authored
|
|
32
|
+
* file: the file's own state is what the write changes, so the stored
|
|
33
|
+
* ledger, origin and firmness checks read it.
|
|
34
|
+
*/
|
|
35
|
+
export declare function authoredEntityLookup(source: UncompiledAuthoredSource): StoredEntityLookup;
|
|
36
|
+
/**
|
|
37
|
+
* Render the document the writer will leave and extract it as kibi sync
|
|
38
|
+
* will. A write that leaves the file uncompilable is refused, naming the
|
|
39
|
+
* file and the error, because the entity would stay invisible to every
|
|
40
|
+
* store-backed tool. Returns the relationships the written file declares.
|
|
41
|
+
*/
|
|
42
|
+
export declare function assertAuthoredWriteCompiles(source: UncompiledAuthoredSource, input: UpsertInput, entity: Readonly<Record<string, unknown>>): readonly RelationshipInput[];
|
|
43
|
+
//# sourceMappingURL=uncompiled-source.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"uncompiled-source.d.ts","sourceRoot":"","sources":["../../../src/operations/mutation/uncompiled-source.ts"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0CAA0C,CAAC;AAMjF,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAC7D,OAAO,KAAK,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEjE;;;GAGG;AAEH,MAAM,MAAM,wBAAwB,GAAG,QAAQ,CAAC;IAC9C,+BAA+B;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAC1C,2EAA2E;IAC3E,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;CAChC,CAAC,CAAC;AAMH;;;;;;;GAOG;AAEH,wBAAsB,4BAA4B,CAChD,OAAO,EAAE,gBAAgB,EACzB,KAAK,EAAE,WAAW,GACjB,OAAO,CAAC,wBAAwB,GAAG,IAAI,CAAC,CA8C1C;AAED;;;;GAIG;AAEH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,wBAAwB,GAC/B,kBAAkB,CAKpB;AAED;;;;;GAKG;AAEH,wBAAgB,2BAA2B,CACzC,MAAM,EAAE,wBAAwB,EAChC,KAAK,EAAE,WAAW,EAClB,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GACxC,SAAS,iBAAiB,EAAE,CAa9B"}
|
|
@@ -0,0 +1,115 @@
|
|
|
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 { sourceExtractionRemediation } from "../../commands/sync/cache.js";
|
|
20
|
+
import { extractFromMarkdownString } from "../../extractors/markdown.js";
|
|
21
|
+
import { authoredFrontmatter, newEntitySourceTarget, renderSourceDocument, } from "./source-authoring.js";
|
|
22
|
+
function errorText(error) {
|
|
23
|
+
return error instanceof Error ? error.message : String(error);
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* The authored document an upsert of `input` would merge into although the
|
|
27
|
+
* store does not hold the entity: a file left out of the last sync (one sync
|
|
28
|
+
* could not extract, or one written since). Null when the writer would
|
|
29
|
+
* create a new file, writes a symbol manifest, or the file declares another
|
|
30
|
+
* entity. A file whose front matter does not parse is refused here: the
|
|
31
|
+
* writer could not merge into it either.
|
|
32
|
+
*/
|
|
33
|
+
// implements REQ-kibi-uncompiled-source-visibility
|
|
34
|
+
export async function readUncompiledAuthoredSource(context, input) {
|
|
35
|
+
if (context.fs === undefined || context.sourceFirst === false)
|
|
36
|
+
return null;
|
|
37
|
+
if (input.type === "symbol")
|
|
38
|
+
return null;
|
|
39
|
+
const absolute = newEntitySourceTarget(context, input);
|
|
40
|
+
if (absolute === undefined || !/\.mdx?$/i.test(absolute))
|
|
41
|
+
return null;
|
|
42
|
+
let content;
|
|
43
|
+
try {
|
|
44
|
+
content = await context.fs.readFile(absolute);
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
const relative = path
|
|
50
|
+
.relative(context.workspaceRoot, absolute)
|
|
51
|
+
.replaceAll(path.sep, "/");
|
|
52
|
+
try {
|
|
53
|
+
const { entity } = extractFromMarkdownString(content, absolute);
|
|
54
|
+
if (entity.id !== input.id)
|
|
55
|
+
return null;
|
|
56
|
+
return {
|
|
57
|
+
path: relative,
|
|
58
|
+
absolute,
|
|
59
|
+
content,
|
|
60
|
+
stored: entity,
|
|
61
|
+
extractionError: null,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
const extractionError = errorText(error);
|
|
66
|
+
let frontmatter;
|
|
67
|
+
try {
|
|
68
|
+
frontmatter = authoredFrontmatter(content);
|
|
69
|
+
}
|
|
70
|
+
catch (parseError) {
|
|
71
|
+
throw new Error(`Upsert of ${input.id} refused: ${relative} exists but kibi sync cannot compile it (${extractionError}), and its front matter does not parse (${errorText(parseError)}), so the write cannot merge into it. Fix the front matter of ${relative}, run kibi sync, then retry.`);
|
|
72
|
+
}
|
|
73
|
+
if (frontmatter.id !== undefined && frontmatter.id !== input.id)
|
|
74
|
+
return null;
|
|
75
|
+
if (frontmatter.type !== undefined && frontmatter.type !== input.type)
|
|
76
|
+
return null;
|
|
77
|
+
return {
|
|
78
|
+
path: relative,
|
|
79
|
+
absolute,
|
|
80
|
+
content,
|
|
81
|
+
stored: { ...frontmatter, id: input.id, type: input.type },
|
|
82
|
+
extractionError,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* The store lookup for an upsert whose entity exists only in its authored
|
|
88
|
+
* file: the file's own state is what the write changes, so the stored
|
|
89
|
+
* ledger, origin and firmness checks read it.
|
|
90
|
+
*/
|
|
91
|
+
// implements REQ-kibi-uncompiled-source-visibility
|
|
92
|
+
export function authoredEntityLookup(source) {
|
|
93
|
+
return {
|
|
94
|
+
exists: async () => true,
|
|
95
|
+
entity: async () => source.stored,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Render the document the writer will leave and extract it as kibi sync
|
|
100
|
+
* will. A write that leaves the file uncompilable is refused, naming the
|
|
101
|
+
* file and the error, because the entity would stay invisible to every
|
|
102
|
+
* store-backed tool. Returns the relationships the written file declares.
|
|
103
|
+
*/
|
|
104
|
+
// implements REQ-kibi-uncompiled-source-visibility
|
|
105
|
+
export function assertAuthoredWriteCompiles(source, input, entity) {
|
|
106
|
+
let after;
|
|
107
|
+
try {
|
|
108
|
+
after = renderSourceDocument(input, entity, source.content, source.path);
|
|
109
|
+
return extractFromMarkdownString(after, source.absolute).relationships.map((relationship) => ({ ...relationship }));
|
|
110
|
+
}
|
|
111
|
+
catch (error) {
|
|
112
|
+
const message = errorText(error);
|
|
113
|
+
throw new Error(`Upsert of ${input.id} refused: ${input.id} exists in ${source.path} but is not compiled${source.extractionError === null ? "" : ` (${source.extractionError})`}, and this write would leave the file uncompilable: ${message}. ${sourceExtractionRemediation(source.path, message)}`);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
@@ -3,6 +3,7 @@ import type { OperationResult } from "../../public/operations/types.js";
|
|
|
3
3
|
import type { SemanticAdvisorReceipt } from "../semantic-advisor/types.js";
|
|
4
4
|
import { type StoredEntityLookup } from "./stored-entity.js";
|
|
5
5
|
import type { RelationshipInput, StagedUpsertState, UpsertInput, UpsertPayload, ValidatedUpsert } from "./types.js";
|
|
6
|
+
import { type UncompiledAuthoredSource } from "./uncompiled-source.js";
|
|
6
7
|
export declare function assertRelationshipShardContained(workspaceRoot: string, shardPath: string): void;
|
|
7
8
|
export declare function validateAppendOnlyProofReceipts(entity: Readonly<Record<string, unknown>>, context: OperationContext, staged?: StagedUpsertState): Promise<void>;
|
|
8
9
|
export declare function effectiveRelationships(input: UpsertInput, entity: Readonly<Record<string, unknown>>, relationships: readonly RelationshipInput[], context: OperationContext, staged?: StagedUpsertState, lookup?: StoredEntityLookup): Promise<readonly RelationshipInput[]>;
|
|
@@ -32,6 +33,11 @@ export declare function analyzeUpsertSemantics(payload: UpsertInput & {
|
|
|
32
33
|
}): UpsertSemanticAnalysis;
|
|
33
34
|
export type UpsertValidation = Readonly<{
|
|
34
35
|
readonly validated: ValidatedUpsert;
|
|
36
|
+
/**
|
|
37
|
+
* The authored file the write merges into although the store does not
|
|
38
|
+
* hold the entity; absent for an ordinary create or update.
|
|
39
|
+
*/
|
|
40
|
+
readonly uncompiledSource?: UncompiledAuthoredSource;
|
|
35
41
|
/** The upsert's relationships merged with the entity's existing ones. */
|
|
36
42
|
readonly relationships: readonly RelationshipInput[];
|
|
37
43
|
readonly semantic: UpsertSemanticAnalysis;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"upsert.d.ts","sourceRoot":"","sources":["../../../src/operations/mutation/upsert.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0CAA0C,CAAC;AACjF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AAexE,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,8BAA8B,CAAC;AA6B3E,OAAO,EACL,KAAK,kBAAkB,EAExB,MAAM,oBAAoB,CAAC;AAQ5B,OAAO,KAAK,EACV,iBAAiB,EACjB,iBAAiB,EACjB,WAAW,EACX,aAAa,EACb,eAAe,EAChB,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"upsert.d.ts","sourceRoot":"","sources":["../../../src/operations/mutation/upsert.ts"],"names":[],"mappings":"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"}
|