opencode-lcm 0.13.1 → 0.13.2
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/CHANGELOG.md +5 -0
- package/package.json +1 -1
- package/dist/store-doctor.d.ts +0 -73
- package/dist/store-doctor.js +0 -106
- package/dist/store-schema.d.ts +0 -8
- package/dist/store-schema.js +0 -23
- package/dist/store-session-read.d.ts +0 -97
- package/dist/store-session-read.js +0 -80
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.13.2] - 2026-04-08
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
- Republish of 0.13.1 malformed-message hardening through CI with provenance
|
|
14
|
+
|
|
10
15
|
## [0.13.1] - 2026-04-07
|
|
11
16
|
|
|
12
17
|
### Fixed
|
package/package.json
CHANGED
package/dist/store-doctor.d.ts
DELETED
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
import type { SqlDatabaseLike } from './store-types.js';
|
|
2
|
-
/**
|
|
3
|
-
* Doctor diagnostics operations.
|
|
4
|
-
* Analyzes store health: summary graph integrity, FTS index consistency, orphan detection.
|
|
5
|
-
*/
|
|
6
|
-
export type DoctorSessionIssue = {
|
|
7
|
-
sessionID: string;
|
|
8
|
-
issues: string[];
|
|
9
|
-
};
|
|
10
|
-
export type DoctorReport = {
|
|
11
|
-
scope: string;
|
|
12
|
-
checkedSessions: number;
|
|
13
|
-
summarySessionsNeedingRebuild: DoctorSessionIssue[];
|
|
14
|
-
lineageSessionsNeedingRefresh: string[];
|
|
15
|
-
orphanSummaryEdges: number;
|
|
16
|
-
messageFts: {
|
|
17
|
-
expected: number;
|
|
18
|
-
actual: number;
|
|
19
|
-
};
|
|
20
|
-
summaryFts: {
|
|
21
|
-
expected: number;
|
|
22
|
-
actual: number;
|
|
23
|
-
};
|
|
24
|
-
artifactFts: {
|
|
25
|
-
expected: number;
|
|
26
|
-
actual: number;
|
|
27
|
-
};
|
|
28
|
-
orphanArtifactBlobs: number;
|
|
29
|
-
status: 'clean' | 'issues-found';
|
|
30
|
-
};
|
|
31
|
-
type SessionSnapshot = {
|
|
32
|
-
sessionID: string;
|
|
33
|
-
messages: {
|
|
34
|
-
info: {
|
|
35
|
-
id: string;
|
|
36
|
-
time: {
|
|
37
|
-
created: number;
|
|
38
|
-
};
|
|
39
|
-
};
|
|
40
|
-
parts: unknown[];
|
|
41
|
-
}[];
|
|
42
|
-
rootSessionID?: string;
|
|
43
|
-
lineageDepth?: number;
|
|
44
|
-
};
|
|
45
|
-
type SummaryNodeRow = {
|
|
46
|
-
node_id: string;
|
|
47
|
-
session_id: string;
|
|
48
|
-
level: number;
|
|
49
|
-
slot: number;
|
|
50
|
-
archived_message_ids_json: string;
|
|
51
|
-
summary_text: string;
|
|
52
|
-
created_at: number;
|
|
53
|
-
};
|
|
54
|
-
type DoctorDeps = {
|
|
55
|
-
db: SqlDatabaseLike;
|
|
56
|
-
getArchivedMessages: (messages: SessionSnapshot['messages']) => SessionSnapshot['messages'];
|
|
57
|
-
buildArchivedSignature: (messages: SessionSnapshot['messages']) => string;
|
|
58
|
-
readSummaryNode: (nodeID: string) => SummaryNodeRow | undefined;
|
|
59
|
-
canReuseSummaryGraph: (sessionID: string, archived: SessionSnapshot['messages'], roots: SummaryNodeRow[]) => boolean;
|
|
60
|
-
readScopedSummaryRows: (sessionIDs?: string[]) => unknown[];
|
|
61
|
-
readScopedArtifactRows: (sessionIDs?: string[]) => unknown[];
|
|
62
|
-
readOrphanArtifactBlobRows: () => unknown[];
|
|
63
|
-
countScopedFtsRows: (table: 'message_fts' | 'summary_fts' | 'artifact_fts', sessionIDs?: string[]) => number;
|
|
64
|
-
countScopedOrphanSummaryEdges: (sessionIDs?: string[]) => number;
|
|
65
|
-
guessMessageText: (message: SessionSnapshot['messages'][number], ignorePrefixes: string[]) => string;
|
|
66
|
-
ignoreToolPrefixes: string[];
|
|
67
|
-
parseJson: <T>(value: string) => T;
|
|
68
|
-
};
|
|
69
|
-
export declare function collectDoctorReport(sessions: SessionSnapshot[], sessionID: string | undefined, deps: DoctorDeps, readLineageChain: (sessionID: string) => {
|
|
70
|
-
sessionID: string;
|
|
71
|
-
}[]): DoctorReport;
|
|
72
|
-
export declare function hasDoctorIssues(report: DoctorReport): boolean;
|
|
73
|
-
export {};
|
package/dist/store-doctor.js
DELETED
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
function countFtsExpected(sessions, deps) {
|
|
2
|
-
return sessions.reduce((count, session) => {
|
|
3
|
-
return (count +
|
|
4
|
-
session.messages.filter((message) => deps.guessMessageText(message, deps.ignoreToolPrefixes).length > 0).length);
|
|
5
|
-
}, 0);
|
|
6
|
-
}
|
|
7
|
-
function diagnoseSummarySession(session, deps) {
|
|
8
|
-
const issues = [];
|
|
9
|
-
const archived = deps.getArchivedMessages(session.messages);
|
|
10
|
-
const state = deps.db
|
|
11
|
-
.prepare('SELECT * FROM summary_state WHERE session_id = ?')
|
|
12
|
-
.get(session.sessionID);
|
|
13
|
-
const summaryNodeCount = deps.db
|
|
14
|
-
.prepare('SELECT COUNT(*) AS count FROM summary_nodes WHERE session_id = ?')
|
|
15
|
-
.get(session.sessionID);
|
|
16
|
-
const summaryEdgeCount = deps.db
|
|
17
|
-
.prepare('SELECT COUNT(*) AS count FROM summary_edges WHERE session_id = ?')
|
|
18
|
-
.get(session.sessionID);
|
|
19
|
-
if (archived.length === 0) {
|
|
20
|
-
if (state)
|
|
21
|
-
issues.push('unexpected-summary-state');
|
|
22
|
-
if (summaryNodeCount.count > 0)
|
|
23
|
-
issues.push('unexpected-summary-nodes');
|
|
24
|
-
if (summaryEdgeCount.count > 0)
|
|
25
|
-
issues.push('unexpected-summary-edges');
|
|
26
|
-
return issues.length > 0 ? { sessionID: session.sessionID, issues } : undefined;
|
|
27
|
-
}
|
|
28
|
-
const latestMessageCreated = archived.at(-1)?.info.time.created ?? 0;
|
|
29
|
-
const archivedSignature = deps.buildArchivedSignature(archived);
|
|
30
|
-
const rootIDs = state ? deps.parseJson(state.root_node_ids_json) : [];
|
|
31
|
-
const roots = rootIDs
|
|
32
|
-
.map((nodeID) => deps.readSummaryNode(nodeID))
|
|
33
|
-
.filter((node) => Boolean(node));
|
|
34
|
-
if (!state) {
|
|
35
|
-
issues.push('missing-summary-state');
|
|
36
|
-
}
|
|
37
|
-
else {
|
|
38
|
-
if (state.archived_count !== archived.length)
|
|
39
|
-
issues.push('archived-count-mismatch');
|
|
40
|
-
if (state.latest_message_created !== latestMessageCreated)
|
|
41
|
-
issues.push('latest-message-mismatch');
|
|
42
|
-
if (state.archived_signature !== archivedSignature)
|
|
43
|
-
issues.push('archived-signature-mismatch');
|
|
44
|
-
if (rootIDs.length === 0)
|
|
45
|
-
issues.push('missing-root-node-ids');
|
|
46
|
-
if (roots.length !== rootIDs.length) {
|
|
47
|
-
issues.push('missing-root-node-record');
|
|
48
|
-
}
|
|
49
|
-
else if (rootIDs.length > 0 &&
|
|
50
|
-
!deps.canReuseSummaryGraph(session.sessionID, archived, roots)) {
|
|
51
|
-
issues.push('invalid-summary-graph');
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
if (summaryNodeCount.count === 0)
|
|
55
|
-
issues.push('missing-summary-nodes');
|
|
56
|
-
return issues.length > 0 ? { sessionID: session.sessionID, issues } : undefined;
|
|
57
|
-
}
|
|
58
|
-
function needsLineageRefresh(session, readLineageChain) {
|
|
59
|
-
const chain = readLineageChain(session.sessionID);
|
|
60
|
-
const expectedRoot = chain[0]?.sessionID ?? session.sessionID;
|
|
61
|
-
const expectedDepth = Math.max(0, chain.length - 1);
|
|
62
|
-
return ((session.rootSessionID ?? session.sessionID) !== expectedRoot ||
|
|
63
|
-
(session.lineageDepth ?? 0) !== expectedDepth);
|
|
64
|
-
}
|
|
65
|
-
export function collectDoctorReport(sessions, sessionID, deps, readLineageChain) {
|
|
66
|
-
const sessionIDs = sessions.map((session) => session.sessionID);
|
|
67
|
-
const summarySessionsNeedingRebuild = sessions
|
|
68
|
-
.map((session) => diagnoseSummarySession(session, deps))
|
|
69
|
-
.filter((issue) => Boolean(issue));
|
|
70
|
-
const lineageSessionsNeedingRefresh = sessions
|
|
71
|
-
.filter((session) => needsLineageRefresh(session, readLineageChain))
|
|
72
|
-
.map((session) => session.sessionID);
|
|
73
|
-
const messageFtsExpected = countFtsExpected(sessions, deps);
|
|
74
|
-
const report = {
|
|
75
|
-
scope: sessionID ? `session:${sessionID}` : 'all',
|
|
76
|
-
checkedSessions: sessions.length,
|
|
77
|
-
summarySessionsNeedingRebuild,
|
|
78
|
-
lineageSessionsNeedingRefresh,
|
|
79
|
-
orphanSummaryEdges: deps.countScopedOrphanSummaryEdges(sessionIDs),
|
|
80
|
-
messageFts: {
|
|
81
|
-
expected: messageFtsExpected,
|
|
82
|
-
actual: deps.countScopedFtsRows('message_fts', sessionIDs),
|
|
83
|
-
},
|
|
84
|
-
summaryFts: {
|
|
85
|
-
expected: deps.readScopedSummaryRows(sessionIDs).length,
|
|
86
|
-
actual: deps.countScopedFtsRows('summary_fts', sessionIDs),
|
|
87
|
-
},
|
|
88
|
-
artifactFts: {
|
|
89
|
-
expected: deps.readScopedArtifactRows(sessionIDs).length,
|
|
90
|
-
actual: deps.countScopedFtsRows('artifact_fts', sessionIDs),
|
|
91
|
-
},
|
|
92
|
-
orphanArtifactBlobs: deps.readOrphanArtifactBlobRows().length,
|
|
93
|
-
status: 'clean',
|
|
94
|
-
};
|
|
95
|
-
report.status = hasDoctorIssues(report) ? 'issues-found' : 'clean';
|
|
96
|
-
return report;
|
|
97
|
-
}
|
|
98
|
-
export function hasDoctorIssues(report) {
|
|
99
|
-
return (report.summarySessionsNeedingRebuild.length > 0 ||
|
|
100
|
-
report.lineageSessionsNeedingRefresh.length > 0 ||
|
|
101
|
-
report.orphanSummaryEdges > 0 ||
|
|
102
|
-
report.messageFts.expected !== report.messageFts.actual ||
|
|
103
|
-
report.summaryFts.expected !== report.summaryFts.actual ||
|
|
104
|
-
report.artifactFts.expected !== report.artifactFts.actual ||
|
|
105
|
-
report.orphanArtifactBlobs > 0);
|
|
106
|
-
}
|
package/dist/store-schema.d.ts
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import type { SqlDatabaseLike } from './store-types.js';
|
|
2
|
-
/**
|
|
3
|
-
* Schema version management operations.
|
|
4
|
-
* Handles reading, writing, and validating the SQLite store schema version.
|
|
5
|
-
*/
|
|
6
|
-
export declare function readSchemaVersionSync(db: SqlDatabaseLike): number;
|
|
7
|
-
export declare function assertSupportedSchemaVersionSync(db: SqlDatabaseLike, maxVersion: number): void;
|
|
8
|
-
export declare function writeSchemaVersionSync(db: SqlDatabaseLike, version: number): void;
|
package/dist/store-schema.js
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Schema version management operations.
|
|
3
|
-
* Handles reading, writing, and validating the SQLite store schema version.
|
|
4
|
-
*/
|
|
5
|
-
export function readSchemaVersionSync(db) {
|
|
6
|
-
const result = db.prepare('PRAGMA user_version').get();
|
|
7
|
-
if (!result || typeof result !== 'object')
|
|
8
|
-
return 0;
|
|
9
|
-
for (const value of Object.values(result)) {
|
|
10
|
-
if (typeof value === 'number' && Number.isFinite(value))
|
|
11
|
-
return value;
|
|
12
|
-
}
|
|
13
|
-
return 0;
|
|
14
|
-
}
|
|
15
|
-
export function assertSupportedSchemaVersionSync(db, maxVersion) {
|
|
16
|
-
const schemaVersion = readSchemaVersionSync(db);
|
|
17
|
-
if (schemaVersion <= maxVersion)
|
|
18
|
-
return;
|
|
19
|
-
throw new Error(`Unsupported store schema version: ${schemaVersion}. This build supports up to ${maxVersion}.`);
|
|
20
|
-
}
|
|
21
|
-
export function writeSchemaVersionSync(db, version) {
|
|
22
|
-
db.exec(`PRAGMA user_version = ${Math.max(0, Math.trunc(version))}`);
|
|
23
|
-
}
|
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
import type { SqlDatabaseLike } from './store-types.js';
|
|
2
|
-
/**
|
|
3
|
-
* Session read operations.
|
|
4
|
-
* Handles reading sessions, messages, parts, artifacts from the store.
|
|
5
|
-
*/
|
|
6
|
-
export type SessionRow = {
|
|
7
|
-
session_id: string;
|
|
8
|
-
title: string | null;
|
|
9
|
-
parent_session_id: string | null;
|
|
10
|
-
root_session_id: string | null;
|
|
11
|
-
lineage_depth: number | null;
|
|
12
|
-
session_directory: string | null;
|
|
13
|
-
worktree_key: string | null;
|
|
14
|
-
pinned: number;
|
|
15
|
-
pin_reason: string | null;
|
|
16
|
-
deleted: number;
|
|
17
|
-
updated_at: number;
|
|
18
|
-
created_at: number;
|
|
19
|
-
event_count: number;
|
|
20
|
-
};
|
|
21
|
-
export type MessageRow = {
|
|
22
|
-
session_id: string;
|
|
23
|
-
message_id: string;
|
|
24
|
-
role: string;
|
|
25
|
-
created_at: number;
|
|
26
|
-
};
|
|
27
|
-
export type PartRow = {
|
|
28
|
-
session_id: string;
|
|
29
|
-
message_id: string;
|
|
30
|
-
part_id: string;
|
|
31
|
-
part_type: string;
|
|
32
|
-
sort_key: number;
|
|
33
|
-
state_json: string;
|
|
34
|
-
created_at: number;
|
|
35
|
-
};
|
|
36
|
-
export type ArtifactRow = {
|
|
37
|
-
artifact_id: string;
|
|
38
|
-
session_id: string;
|
|
39
|
-
message_id: string;
|
|
40
|
-
part_id: string;
|
|
41
|
-
artifact_kind: string;
|
|
42
|
-
field_name: string;
|
|
43
|
-
content_hash: string | null;
|
|
44
|
-
preview_text: string;
|
|
45
|
-
metadata_json: string;
|
|
46
|
-
char_count: number;
|
|
47
|
-
created_at: number;
|
|
48
|
-
};
|
|
49
|
-
export type ArtifactBlobRow = {
|
|
50
|
-
content_hash: string;
|
|
51
|
-
content_text: string;
|
|
52
|
-
char_count: number;
|
|
53
|
-
created_at: number;
|
|
54
|
-
};
|
|
55
|
-
export type SummaryNodeRow = {
|
|
56
|
-
node_id: string;
|
|
57
|
-
session_id: string;
|
|
58
|
-
level: number;
|
|
59
|
-
slot: number;
|
|
60
|
-
archived_message_ids_json: string;
|
|
61
|
-
summary_text: string;
|
|
62
|
-
created_at: number;
|
|
63
|
-
};
|
|
64
|
-
export type SummaryEdgeRow = {
|
|
65
|
-
session_id: string;
|
|
66
|
-
parent_id: string;
|
|
67
|
-
child_id: string;
|
|
68
|
-
child_position: number;
|
|
69
|
-
};
|
|
70
|
-
export type SummaryStateRow = {
|
|
71
|
-
session_id: string;
|
|
72
|
-
archived_count: number;
|
|
73
|
-
latest_message_created: number;
|
|
74
|
-
archived_signature: string;
|
|
75
|
-
root_node_ids_json: string;
|
|
76
|
-
updated_at: number;
|
|
77
|
-
};
|
|
78
|
-
export declare function readSessionHeader(db: SqlDatabaseLike, sessionID: string): SessionRow | undefined;
|
|
79
|
-
export declare function readAllSessions(db: SqlDatabaseLike): SessionRow[];
|
|
80
|
-
export declare function readChildSessions(db: SqlDatabaseLike, parentSessionID: string): SessionRow[];
|
|
81
|
-
export declare function readLineageChain(db: SqlDatabaseLike, sessionID: string): SessionRow[];
|
|
82
|
-
export declare function readMessagesForSession(db: SqlDatabaseLike, sessionID: string): MessageRow[];
|
|
83
|
-
export declare function readPartsForSession(db: SqlDatabaseLike, sessionID: string): PartRow[];
|
|
84
|
-
export declare function readArtifactsForSession(db: SqlDatabaseLike, sessionID: string): ArtifactRow[];
|
|
85
|
-
export declare function readArtifact(db: SqlDatabaseLike, artifactID: string): ArtifactRow | undefined;
|
|
86
|
-
export declare function readArtifactBlob(db: SqlDatabaseLike, contentHash: string): ArtifactBlobRow | undefined;
|
|
87
|
-
export declare function readOrphanArtifactBlobRows(db: SqlDatabaseLike): ArtifactBlobRow[];
|
|
88
|
-
export declare function readLatestSessionID(db: SqlDatabaseLike): string | undefined;
|
|
89
|
-
export declare function readSessionStats(db: SqlDatabaseLike): {
|
|
90
|
-
sessionCount: number;
|
|
91
|
-
messageCount: number;
|
|
92
|
-
artifactCount: number;
|
|
93
|
-
summaryNodeCount: number;
|
|
94
|
-
blobCount: number;
|
|
95
|
-
orphanBlobCount: number;
|
|
96
|
-
orphanBlobChars: number;
|
|
97
|
-
};
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
export function readSessionHeader(db, sessionID) {
|
|
2
|
-
return db.prepare('SELECT * FROM sessions WHERE session_id = ?').get(sessionID);
|
|
3
|
-
}
|
|
4
|
-
export function readAllSessions(db) {
|
|
5
|
-
return db.prepare('SELECT * FROM sessions ORDER BY updated_at DESC').all();
|
|
6
|
-
}
|
|
7
|
-
export function readChildSessions(db, parentSessionID) {
|
|
8
|
-
return db
|
|
9
|
-
.prepare('SELECT * FROM sessions WHERE parent_session_id = ? ORDER BY updated_at DESC')
|
|
10
|
-
.all(parentSessionID);
|
|
11
|
-
}
|
|
12
|
-
export function readLineageChain(db, sessionID) {
|
|
13
|
-
const chain = [];
|
|
14
|
-
let current = readSessionHeader(db, sessionID);
|
|
15
|
-
while (current) {
|
|
16
|
-
chain.unshift(current);
|
|
17
|
-
if (!current.parent_session_id)
|
|
18
|
-
break;
|
|
19
|
-
current = readSessionHeader(db, current.parent_session_id);
|
|
20
|
-
}
|
|
21
|
-
return chain;
|
|
22
|
-
}
|
|
23
|
-
export function readMessagesForSession(db, sessionID) {
|
|
24
|
-
return db
|
|
25
|
-
.prepare('SELECT * FROM messages WHERE session_id = ? ORDER BY created_at ASC')
|
|
26
|
-
.all(sessionID);
|
|
27
|
-
}
|
|
28
|
-
export function readPartsForSession(db, sessionID) {
|
|
29
|
-
return db
|
|
30
|
-
.prepare('SELECT * FROM parts WHERE session_id = ? ORDER BY message_id ASC, sort_key ASC')
|
|
31
|
-
.all(sessionID);
|
|
32
|
-
}
|
|
33
|
-
export function readArtifactsForSession(db, sessionID) {
|
|
34
|
-
return db
|
|
35
|
-
.prepare('SELECT * FROM artifacts WHERE session_id = ? ORDER BY created_at DESC')
|
|
36
|
-
.all(sessionID);
|
|
37
|
-
}
|
|
38
|
-
export function readArtifact(db, artifactID) {
|
|
39
|
-
return db.prepare('SELECT * FROM artifacts WHERE artifact_id = ?').get(artifactID);
|
|
40
|
-
}
|
|
41
|
-
export function readArtifactBlob(db, contentHash) {
|
|
42
|
-
return db.prepare('SELECT * FROM artifact_blobs WHERE content_hash = ?').get(contentHash);
|
|
43
|
-
}
|
|
44
|
-
export function readOrphanArtifactBlobRows(db) {
|
|
45
|
-
return db
|
|
46
|
-
.prepare(`SELECT b.* FROM artifact_blobs b
|
|
47
|
-
WHERE NOT EXISTS (
|
|
48
|
-
SELECT 1 FROM artifacts a WHERE a.content_hash = b.content_hash
|
|
49
|
-
)
|
|
50
|
-
ORDER BY b.created_at ASC`)
|
|
51
|
-
.all();
|
|
52
|
-
}
|
|
53
|
-
export function readLatestSessionID(db) {
|
|
54
|
-
const row = db
|
|
55
|
-
.prepare('SELECT session_id FROM sessions ORDER BY updated_at DESC LIMIT 1')
|
|
56
|
-
.get();
|
|
57
|
-
return row?.session_id;
|
|
58
|
-
}
|
|
59
|
-
export function readSessionStats(db) {
|
|
60
|
-
const sessions = db.prepare('SELECT COUNT(*) AS count FROM sessions').get();
|
|
61
|
-
const messages = db.prepare('SELECT COUNT(*) AS count FROM messages').get();
|
|
62
|
-
const artifacts = db.prepare('SELECT COUNT(*) AS count FROM artifacts').get();
|
|
63
|
-
const summaryNodes = db.prepare('SELECT COUNT(*) AS count FROM summary_nodes').get();
|
|
64
|
-
const blobs = db
|
|
65
|
-
.prepare(`SELECT COUNT(*) AS count, COALESCE(SUM(char_count), 0) AS chars
|
|
66
|
-
FROM artifact_blobs b
|
|
67
|
-
WHERE NOT EXISTS (
|
|
68
|
-
SELECT 1 FROM artifacts a WHERE a.content_hash = b.content_hash
|
|
69
|
-
)`)
|
|
70
|
-
.get();
|
|
71
|
-
return {
|
|
72
|
-
sessionCount: sessions.count,
|
|
73
|
-
messageCount: messages.count,
|
|
74
|
-
artifactCount: artifacts.count,
|
|
75
|
-
summaryNodeCount: summaryNodes.count,
|
|
76
|
-
blobCount: blobs.count,
|
|
77
|
-
orphanBlobCount: blobs.count,
|
|
78
|
-
orphanBlobChars: blobs.chars,
|
|
79
|
-
};
|
|
80
|
-
}
|