kibi-opencode 0.14.0 → 0.15.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -12
- package/dist/config.d.ts +0 -3
- package/dist/config.js +0 -9
- package/dist/e2e-coverage-signals.js +1 -3
- package/dist/enforcement-policy.d.ts +2 -0
- package/dist/enforcement-policy.js +18 -3
- package/dist/enforcement-scope.js +1 -3
- package/dist/file-entity-links.js +2 -6
- package/dist/file-operation-reminders.d.ts +4 -4
- package/dist/file-operation-state.js +4 -2
- package/dist/init-kibi-alias.js +0 -1
- package/dist/init-kibi-capability.js +1 -5
- package/dist/kb-freshness-state.d.ts +62 -0
- package/dist/kb-freshness-state.js +215 -0
- package/dist/kibi-checkpoint-runner.d.ts +1 -1
- package/dist/kibi-checkpoint-runner.js +6 -3
- package/dist/knowledge-classifier.js +2 -1
- package/dist/meaningful-change-classifier.d.ts +30 -0
- package/dist/meaningful-change-classifier.js +103 -0
- package/dist/plugin-startup.js +0 -1
- package/dist/plugin.js +101 -391
- package/dist/prompt.d.ts +6 -5
- package/dist/prompt.js +48 -84
- package/dist/reconcile-engine.d.ts +15 -1
- package/dist/reconcile-engine.js +1 -3
- package/dist/scheduler.js +16 -4
- package/dist/session-edit-state.js +2 -1
- package/dist/source-linked-guidance.js +3 -1
- package/dist/startup-notifier.d.ts +7 -1
- package/dist/startup-notifier.js +51 -17
- package/dist/tui.js +1 -403
- package/dist/tui.jsx +1 -113
- package/dist/version-metadata.d.ts +13 -0
- package/dist/version-metadata.js +78 -0
- package/dist/version-metadata.json +1 -0
- package/package.json +5 -7
- package/dist/brief-delivery-reasons.d.ts +0 -12
- package/dist/brief-delivery-reasons.js +0 -132
- package/dist/brief-intent.d.ts +0 -41
- package/dist/brief-intent.js +0 -142
- package/dist/briefing-runtime.d.ts +0 -24
- package/dist/briefing-runtime.js +0 -277
- package/dist/graph-narrator.d.ts +0 -25
- package/dist/graph-narrator.js +0 -408
- package/dist/idle-brief-audit.d.ts +0 -36
- package/dist/idle-brief-audit.js +0 -186
- package/dist/idle-brief-paths.d.ts +0 -6
- package/dist/idle-brief-paths.js +0 -120
- package/dist/idle-brief-reader.d.ts +0 -37
- package/dist/idle-brief-reader.js +0 -163
- package/dist/idle-brief-runtime.d.ts +0 -55
- package/dist/idle-brief-runtime.js +0 -496
- package/dist/idle-brief-store.d.ts +0 -113
- package/dist/idle-brief-store.js +0 -262
- package/dist/session-fingerprint.d.ts +0 -11
- package/dist/session-fingerprint.js +0 -21
- package/dist/tui-brief-delivery.d.ts +0 -67
- package/dist/tui-brief-delivery.js +0 -279
- package/dist/tui-brief-view-model.d.ts +0 -63
- package/dist/tui-brief-view-model.js +0 -209
- package/dist/utils/brief-marker.d.ts +0 -19
- package/dist/utils/brief-marker.js +0 -101
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import type { IdleBriefCitation, IdleBriefEnvelope, IdleBriefStatement } from "./idle-brief-store.js";
|
|
2
|
-
export interface TuiBriefViewModel {
|
|
3
|
-
briefId: string;
|
|
4
|
-
schemaVersion: "1.0" | "2.0";
|
|
5
|
-
branch: string;
|
|
6
|
-
createdAt: string;
|
|
7
|
-
type: "success" | "warning";
|
|
8
|
-
unread: boolean;
|
|
9
|
-
contentHash: string;
|
|
10
|
-
/** Short human-readable title derived from the envelope */
|
|
11
|
-
title: string;
|
|
12
|
-
/** "What changed" section content */
|
|
13
|
-
whatChanged: string[];
|
|
14
|
-
/** "Why it matters" section content */
|
|
15
|
-
whyItMatters: string | undefined;
|
|
16
|
-
/** Project knowledge impact section (citations, constraints, risks) */
|
|
17
|
-
knowledgeImpact: {
|
|
18
|
-
citations: IdleBriefCitation[];
|
|
19
|
-
constraints: IdleBriefStatement[];
|
|
20
|
-
regressionRisks: IdleBriefStatement[];
|
|
21
|
-
};
|
|
22
|
-
/** Interpretation note section (validation + missing evidence) */
|
|
23
|
-
interpretationNote: {
|
|
24
|
-
validationCount: number;
|
|
25
|
-
missingEvidence: IdleBriefStatement[];
|
|
26
|
-
};
|
|
27
|
-
/** Summary counts (schema-aware) */
|
|
28
|
-
counts: {
|
|
29
|
-
schemaVersion: "1.0";
|
|
30
|
-
requirementsAdded: number;
|
|
31
|
-
relationshipsAdded: number;
|
|
32
|
-
entitiesDeleted: number;
|
|
33
|
-
} | {
|
|
34
|
-
schemaVersion: "2.0";
|
|
35
|
-
entitiesAdded: number;
|
|
36
|
-
entitiesModified: number;
|
|
37
|
-
entitiesRemoved: number;
|
|
38
|
-
relationshipsChanged: number;
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
/**
|
|
42
|
-
* Build a structured view model from a persisted brief envelope.
|
|
43
|
-
*
|
|
44
|
-
* Derives all route-rendering data (title, sections, citations, counts) from
|
|
45
|
-
* the envelope without regenerating any content. Supports both schema 1.0 and
|
|
46
|
-
* 2.0 during the migration window.
|
|
47
|
-
*
|
|
48
|
-
* @param envelope - The persisted brief envelope
|
|
49
|
-
* @returns A deterministic view model suitable for route rendering
|
|
50
|
-
*/
|
|
51
|
-
export declare function buildTuiBriefViewModel(// implements REQ-opencode-kibi-briefing-v6
|
|
52
|
-
envelope: IdleBriefEnvelope): TuiBriefViewModel;
|
|
53
|
-
/**
|
|
54
|
-
* Build a short summary text from a persisted brief envelope.
|
|
55
|
-
*
|
|
56
|
-
* Reuses the same section-building logic as `buildTuiBriefMessage` from
|
|
57
|
-
* `tui-brief-delivery.ts`, producing a deterministic plain-text summary
|
|
58
|
-
* suitable for TUI route rendering or server-side summary generation.
|
|
59
|
-
*
|
|
60
|
-
* @param envelope - The persisted brief envelope
|
|
61
|
-
* @returns A multi-line summary string
|
|
62
|
-
*/
|
|
63
|
-
export declare function buildTuiBriefSummary(envelope: IdleBriefEnvelope): string;
|
|
@@ -1,209 +0,0 @@
|
|
|
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
|
-
import { renderFullBriefReasons, renderToastSummary } from "./brief-delivery-reasons.js";
|
|
11
|
-
// ─── Helpers ───────────────────────────────────────────────────────────────
|
|
12
|
-
function firstNonEmpty(...values) {
|
|
13
|
-
for (const value of values) {
|
|
14
|
-
const trimmed = value?.trim();
|
|
15
|
-
if (trimmed) {
|
|
16
|
-
return trimmed;
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
return undefined;
|
|
20
|
-
}
|
|
21
|
-
function isOperationalByEntityIds(item) {
|
|
22
|
-
if (item.entityIds.length === 0)
|
|
23
|
-
return false;
|
|
24
|
-
return item.entityIds.every((id) => {
|
|
25
|
-
const dashIdx = id.indexOf("-");
|
|
26
|
-
if (dashIdx < 0)
|
|
27
|
-
return false;
|
|
28
|
-
return /\.[a-zA-Z0-9]+$/.test(id.slice(dashIdx + 1));
|
|
29
|
-
});
|
|
30
|
-
}
|
|
31
|
-
function isOperationalDeliveryItem(item, allItems) {
|
|
32
|
-
if (item.kind === "relationship_changed") {
|
|
33
|
-
// relationship_changed items have no entityIds; treat as operational when
|
|
34
|
-
// all entity-level items in the set are operational (they're relationship side-effects)
|
|
35
|
-
const entityItems = allItems.filter((i) => i.kind === "entity_added" || i.kind === "entity_modified" || i.kind === "entity_removed");
|
|
36
|
-
return entityItems.length > 0 && entityItems.every(isOperationalByEntityIds);
|
|
37
|
-
}
|
|
38
|
-
return isOperationalByEntityIds(item);
|
|
39
|
-
}
|
|
40
|
-
function deriveWhatChanged(envelope) {
|
|
41
|
-
const briefing = envelope.briefing;
|
|
42
|
-
const deliveryReasons = briefing.deliveryReasons;
|
|
43
|
-
if (deliveryReasons?.items?.length) {
|
|
44
|
-
const domainItems = deliveryReasons.items.filter((item) => !isOperationalDeliveryItem(item, deliveryReasons.items));
|
|
45
|
-
if (domainItems.length > 0) {
|
|
46
|
-
return domainItems.map((item) => item.text);
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
if (envelope.schemaVersion === "2.0") {
|
|
50
|
-
const narrative = envelope.briefing.changeNarrative
|
|
51
|
-
.map((line) => line.trim())
|
|
52
|
-
.filter(Boolean)
|
|
53
|
-
.filter((line) => !line.includes(".sisyphus/"));
|
|
54
|
-
if (narrative.length > 0) {
|
|
55
|
-
return narrative.slice(0, 2);
|
|
56
|
-
}
|
|
57
|
-
const fallbackEntity = envelope.changes.entities.modified[0] ??
|
|
58
|
-
envelope.changes.entities.added[0];
|
|
59
|
-
if (fallbackEntity) {
|
|
60
|
-
const action = envelope.changes.entities.modified[0] ? "Modified" : "Added";
|
|
61
|
-
return [
|
|
62
|
-
`${action} ${fallbackEntity.id}: ${fallbackEntity.title ?? "Untitled"}`,
|
|
63
|
-
];
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
const fallback = firstNonEmpty(envelope.summary, envelope.briefing.tldr);
|
|
67
|
-
return fallback ? [fallback] : [];
|
|
68
|
-
}
|
|
69
|
-
// ─── Public API ────────────────────────────────────────────────────────────
|
|
70
|
-
/**
|
|
71
|
-
* Build a structured view model from a persisted brief envelope.
|
|
72
|
-
*
|
|
73
|
-
* Derives all route-rendering data (title, sections, citations, counts) from
|
|
74
|
-
* the envelope without regenerating any content. Supports both schema 1.0 and
|
|
75
|
-
* 2.0 during the migration window.
|
|
76
|
-
*
|
|
77
|
-
* @param envelope - The persisted brief envelope
|
|
78
|
-
* @returns A deterministic view model suitable for route rendering
|
|
79
|
-
*/
|
|
80
|
-
export function buildTuiBriefViewModel(// implements REQ-opencode-kibi-briefing-v6
|
|
81
|
-
envelope) {
|
|
82
|
-
const briefing = envelope.briefing;
|
|
83
|
-
const deliveryReasons = briefing.deliveryReasons;
|
|
84
|
-
let title = firstNonEmpty(envelope.summary, envelope.briefing.tldr);
|
|
85
|
-
if (deliveryReasons?.items?.length) {
|
|
86
|
-
const filteredToast = renderToastSummary(deliveryReasons);
|
|
87
|
-
if (filteredToast) {
|
|
88
|
-
title = filteredToast.summary;
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
else if (envelope.schemaVersion === "2.0" && envelope.briefing.changeNarrative.length > 0) {
|
|
92
|
-
title = envelope.briefing.changeNarrative[0]?.trim() ?? title;
|
|
93
|
-
}
|
|
94
|
-
const base = {
|
|
95
|
-
briefId: envelope.briefId,
|
|
96
|
-
schemaVersion: envelope.schemaVersion,
|
|
97
|
-
branch: envelope.branch,
|
|
98
|
-
createdAt: envelope.createdAt,
|
|
99
|
-
type: envelope.type,
|
|
100
|
-
unread: envelope.unread,
|
|
101
|
-
contentHash: envelope.contentHash,
|
|
102
|
-
title: title ?? "Kibi Brief",
|
|
103
|
-
whatChanged: deriveWhatChanged(envelope),
|
|
104
|
-
whyItMatters: deliveryReasons?.items?.length
|
|
105
|
-
? renderToastSummary(deliveryReasons)?.whyItMatters || undefined
|
|
106
|
-
: undefined,
|
|
107
|
-
knowledgeImpact: {
|
|
108
|
-
citations: envelope.briefing.citations,
|
|
109
|
-
constraints: envelope.briefing.constraints ?? [],
|
|
110
|
-
regressionRisks: envelope.briefing.regressionRisks ?? [],
|
|
111
|
-
},
|
|
112
|
-
interpretationNote: {
|
|
113
|
-
validationCount: envelope.validation.count,
|
|
114
|
-
missingEvidence: envelope.briefing.missingEvidence ?? [],
|
|
115
|
-
},
|
|
116
|
-
};
|
|
117
|
-
if (envelope.schemaVersion === "2.0") {
|
|
118
|
-
return {
|
|
119
|
-
...base,
|
|
120
|
-
counts: {
|
|
121
|
-
schemaVersion: "2.0",
|
|
122
|
-
entitiesAdded: envelope.counts.entitiesAdded,
|
|
123
|
-
entitiesModified: envelope.counts.entitiesModified,
|
|
124
|
-
entitiesRemoved: envelope.counts.entitiesRemoved,
|
|
125
|
-
relationshipsChanged: envelope.counts.relationshipsChanged,
|
|
126
|
-
},
|
|
127
|
-
};
|
|
128
|
-
}
|
|
129
|
-
return {
|
|
130
|
-
...base,
|
|
131
|
-
counts: {
|
|
132
|
-
schemaVersion: "1.0",
|
|
133
|
-
requirementsAdded: envelope.counts.requirementsAdded,
|
|
134
|
-
relationshipsAdded: envelope.counts.relationshipsAdded,
|
|
135
|
-
entitiesDeleted: envelope.counts.entitiesDeleted,
|
|
136
|
-
},
|
|
137
|
-
};
|
|
138
|
-
}
|
|
139
|
-
/**
|
|
140
|
-
* Build a short summary text from a persisted brief envelope.
|
|
141
|
-
*
|
|
142
|
-
* Reuses the same section-building logic as `buildTuiBriefMessage` from
|
|
143
|
-
* `tui-brief-delivery.ts`, producing a deterministic plain-text summary
|
|
144
|
-
* suitable for TUI route rendering or server-side summary generation.
|
|
145
|
-
*
|
|
146
|
-
* @param envelope - The persisted brief envelope
|
|
147
|
-
* @returns A multi-line summary string
|
|
148
|
-
*/
|
|
149
|
-
export function buildTuiBriefSummary(envelope) {
|
|
150
|
-
const briefing = envelope.briefing;
|
|
151
|
-
const deliveryReasons = briefing.deliveryReasons;
|
|
152
|
-
if (deliveryReasons?.items?.length) {
|
|
153
|
-
return renderFullBriefReasons(deliveryReasons);
|
|
154
|
-
}
|
|
155
|
-
const lines = [];
|
|
156
|
-
// What changed
|
|
157
|
-
lines.push("## What changed");
|
|
158
|
-
lines.push(...deriveWhatChanged(envelope));
|
|
159
|
-
lines.push("");
|
|
160
|
-
// Why it matters
|
|
161
|
-
if (deliveryReasons?.items?.length) {
|
|
162
|
-
lines.push("## Why it matters");
|
|
163
|
-
lines.push(deliveryReasons.toast.whyItMatters || "");
|
|
164
|
-
lines.push("");
|
|
165
|
-
}
|
|
166
|
-
// Project knowledge impact
|
|
167
|
-
const hasKnowledgeImpact = envelope.briefing.citations.length > 0 ||
|
|
168
|
-
(envelope.briefing.constraints?.length ?? 0) > 0 ||
|
|
169
|
-
(envelope.briefing.regressionRisks?.length ?? 0) > 0;
|
|
170
|
-
if (hasKnowledgeImpact) {
|
|
171
|
-
lines.push("## Project knowledge impact");
|
|
172
|
-
if (envelope.briefing.citations.length > 0) {
|
|
173
|
-
for (const citation of envelope.briefing.citations) {
|
|
174
|
-
lines.push(`- **${citation.id}**${citation.title ? `: ${citation.title}` : ""}${citation.source ? ` (${citation.source})` : ""}`);
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
if ((envelope.briefing.constraints?.length ?? 0) > 0) {
|
|
178
|
-
for (const constraint of envelope.briefing.constraints ?? []) {
|
|
179
|
-
lines.push(`- ${constraint.statement}`);
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
if ((envelope.briefing.regressionRisks?.length ?? 0) > 0) {
|
|
183
|
-
for (const risk of envelope.briefing.regressionRisks ?? []) {
|
|
184
|
-
lines.push(`- ${risk.statement}`);
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
lines.push("");
|
|
188
|
-
}
|
|
189
|
-
// Interpretation note
|
|
190
|
-
const hasMissingEvidence = (envelope.briefing.missingEvidence?.length ?? 0) > 0;
|
|
191
|
-
if (envelope.validation.count > 0 || hasMissingEvidence) {
|
|
192
|
-
lines.push("## Interpretation note");
|
|
193
|
-
if (envelope.validation.count > 0) {
|
|
194
|
-
lines.push(`Validation checks reported unresolved items: ${envelope.validation.count} issue(s).`);
|
|
195
|
-
}
|
|
196
|
-
if (hasMissingEvidence) {
|
|
197
|
-
lines.push("This brief includes unresolved evidence notes:");
|
|
198
|
-
for (const item of envelope.briefing.missingEvidence ?? []) {
|
|
199
|
-
lines.push(`- ${item.statement}`);
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
lines.push("");
|
|
203
|
-
}
|
|
204
|
-
// Trim trailing blank lines
|
|
205
|
-
while (lines.length > 0 && lines[lines.length - 1] === "") {
|
|
206
|
-
lines.pop();
|
|
207
|
-
}
|
|
208
|
-
return lines.join("\n");
|
|
209
|
-
}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
export interface PendingBriefMarkerIssue {
|
|
2
|
-
filePath: string;
|
|
3
|
-
reason: "parse" | "schema" | "delete";
|
|
4
|
-
}
|
|
5
|
-
export interface PendingBriefMarkersResult {
|
|
6
|
-
entityIds: string[];
|
|
7
|
-
relationships: Array<{
|
|
8
|
-
from: string;
|
|
9
|
-
to: string;
|
|
10
|
-
type: string;
|
|
11
|
-
}>;
|
|
12
|
-
markerPaths: string[];
|
|
13
|
-
issues: PendingBriefMarkerIssue[];
|
|
14
|
-
}
|
|
15
|
-
export declare function loadPendingBriefMarkers(workspaceRoot: string, branch: string): PendingBriefMarkersResult;
|
|
16
|
-
export declare function deletePendingBriefMarkers(markerPaths: string[]): Promise<{
|
|
17
|
-
deletedCount: number;
|
|
18
|
-
issues: PendingBriefMarkerIssue[];
|
|
19
|
-
}>;
|
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
import * as fs from "node:fs";
|
|
2
|
-
import * as path from "node:path";
|
|
3
|
-
// implements REQ-opencode-kibi-briefing-v2
|
|
4
|
-
export function loadPendingBriefMarkers(workspaceRoot, branch) {
|
|
5
|
-
const pendingDir = path.join(workspaceRoot, ".kb", "briefs", "pending");
|
|
6
|
-
if (!fs.existsSync(pendingDir)) {
|
|
7
|
-
return { entityIds: [], relationships: [], markerPaths: [], issues: [] };
|
|
8
|
-
}
|
|
9
|
-
let entries;
|
|
10
|
-
try {
|
|
11
|
-
entries = fs.readdirSync(pendingDir, { withFileTypes: true });
|
|
12
|
-
}
|
|
13
|
-
catch {
|
|
14
|
-
return { entityIds: [], relationships: [], markerPaths: [], issues: [] };
|
|
15
|
-
}
|
|
16
|
-
const issues = [];
|
|
17
|
-
const markerPaths = [];
|
|
18
|
-
const entityIds = [];
|
|
19
|
-
const seenEntityIds = new Set();
|
|
20
|
-
const relationshipMap = new Map();
|
|
21
|
-
for (const entry of entries
|
|
22
|
-
.filter((dirent) => dirent.isFile() && dirent.name.endsWith(".json"))
|
|
23
|
-
.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
24
|
-
const filePath = path.join(pendingDir, entry.name);
|
|
25
|
-
let payload;
|
|
26
|
-
try {
|
|
27
|
-
payload = parsePendingBriefMarker(JSON.parse(fs.readFileSync(filePath, "utf8")));
|
|
28
|
-
}
|
|
29
|
-
catch (error) {
|
|
30
|
-
issues.push({
|
|
31
|
-
filePath,
|
|
32
|
-
reason: error instanceof SyntaxError ? "parse" : "schema",
|
|
33
|
-
});
|
|
34
|
-
continue;
|
|
35
|
-
}
|
|
36
|
-
if (payload.branch !== branch) {
|
|
37
|
-
continue;
|
|
38
|
-
}
|
|
39
|
-
markerPaths.push(filePath);
|
|
40
|
-
for (const entityId of payload.entityIds) {
|
|
41
|
-
if (seenEntityIds.has(entityId)) {
|
|
42
|
-
continue;
|
|
43
|
-
}
|
|
44
|
-
seenEntityIds.add(entityId);
|
|
45
|
-
entityIds.push(entityId);
|
|
46
|
-
}
|
|
47
|
-
for (const relationship of payload.relationships) {
|
|
48
|
-
relationshipMap.set(`${relationship.type}\u0000${relationship.from}\u0000${relationship.to}`, relationship);
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
return {
|
|
52
|
-
entityIds,
|
|
53
|
-
relationships: [...relationshipMap.values()],
|
|
54
|
-
markerPaths,
|
|
55
|
-
issues,
|
|
56
|
-
};
|
|
57
|
-
}
|
|
58
|
-
// implements REQ-opencode-kibi-briefing-v2
|
|
59
|
-
export async function deletePendingBriefMarkers(markerPaths) {
|
|
60
|
-
let deletedCount = 0;
|
|
61
|
-
const issues = [];
|
|
62
|
-
for (const markerPath of markerPaths) {
|
|
63
|
-
try {
|
|
64
|
-
const existedBeforeDelete = fs.existsSync(markerPath);
|
|
65
|
-
await fs.promises.rm(markerPath, { force: true });
|
|
66
|
-
if (existedBeforeDelete && !fs.existsSync(markerPath)) {
|
|
67
|
-
deletedCount += 1;
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
catch {
|
|
71
|
-
issues.push({ filePath: markerPath, reason: "delete" });
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
return { deletedCount, issues };
|
|
75
|
-
}
|
|
76
|
-
function parsePendingBriefMarker(value) {
|
|
77
|
-
if (!value || typeof value !== "object") {
|
|
78
|
-
throw new Error("Invalid marker payload");
|
|
79
|
-
}
|
|
80
|
-
const record = value;
|
|
81
|
-
const branch = typeof record.branch === "string" ? record.branch.trim() : "";
|
|
82
|
-
const entityIds = Array.isArray(record.entityIds)
|
|
83
|
-
? record.entityIds.filter((item) => typeof item === "string" && item.length > 0)
|
|
84
|
-
: null;
|
|
85
|
-
const relationships = Array.isArray(record.relationships)
|
|
86
|
-
? record.relationships
|
|
87
|
-
.filter((item) => !!item &&
|
|
88
|
-
typeof item === "object" &&
|
|
89
|
-
typeof item.from === "string" &&
|
|
90
|
-
typeof item.to === "string" &&
|
|
91
|
-
typeof item.type === "string" &&
|
|
92
|
-
item.from.length > 0 &&
|
|
93
|
-
item.to.length > 0 &&
|
|
94
|
-
item.type.length > 0)
|
|
95
|
-
.map((item) => ({ from: item.from, to: item.to, type: item.type }))
|
|
96
|
-
: [];
|
|
97
|
-
if (!branch || !entityIds) {
|
|
98
|
-
throw new Error("Invalid marker schema");
|
|
99
|
-
}
|
|
100
|
-
return { branch, entityIds, relationships };
|
|
101
|
-
}
|