@gmickel/gno 1.31.0 → 1.33.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/README.md +15 -5
- package/assets/skill/SKILL.md +34 -0
- package/assets/skill/cli-reference.md +10 -2
- package/browser-extension/artifacts/{gno-browser-clipper-v1.31.0.zip → gno-browser-clipper-v1.33.0.zip} +0 -0
- package/browser-extension/artifacts/gno-browser-clipper-v1.33.0.zip.sha256 +1 -0
- package/browser-extension/dist/manifest.json +1 -1
- package/package.json +5 -1
- package/spec/cli.md +35 -1
- package/spec/db/schema.sql +55 -0
- package/spec/mcp.md +114 -11
- package/spec/output-schemas/file-refactor-apply-result.schema.json +305 -0
- package/spec/output-schemas/file-refactor-preview.schema.json +393 -0
- package/spec/output-schemas/publish-artifact.schema.json +76 -1
- package/src/cli/commands/publish.ts +43 -7
- package/src/core/document-capabilities.ts +13 -0
- package/src/core/file-ops.ts +129 -1
- package/src/core/file-refactor-adapter.ts +329 -0
- package/src/core/file-refactor-apply-edits.ts +61 -0
- package/src/core/file-refactor-apply-fs.ts +512 -0
- package/src/core/file-refactor-apply-safety.ts +340 -0
- package/src/core/file-refactor-apply-validate.ts +401 -0
- package/src/core/file-refactor-contract.ts +486 -0
- package/src/core/file-refactor-destination.ts +123 -0
- package/src/core/file-refactor-from-snapshot.ts +148 -0
- package/src/core/file-refactor-journal-port.ts +150 -0
- package/src/core/file-refactor-journal.ts +347 -0
- package/src/core/file-refactor-paths.ts +60 -0
- package/src/core/file-refactor-plan-classify.ts +208 -0
- package/src/core/file-refactor-plan-validate.ts +169 -0
- package/src/core/file-refactor-planner-types.ts +62 -0
- package/src/core/file-refactor-planner.ts +423 -0
- package/src/core/file-refactor-resolve.ts +280 -0
- package/src/core/file-refactor-service.ts +468 -0
- package/src/core/file-refactors.ts +84 -56
- package/src/core/link-destination-parse.ts +275 -0
- package/src/core/link-inventory-markdown.ts +454 -0
- package/src/core/link-inventory-opaque.ts +244 -0
- package/src/core/link-inventory-types.ts +47 -0
- package/src/core/link-inventory.ts +182 -0
- package/src/core/link-relevance.ts +150 -0
- package/src/ingestion/strip.ts +152 -26
- package/src/mcp/tools/index.ts +18 -17
- package/src/mcp/tools/workspace-write.ts +215 -97
- package/src/publish/artifact-asset-codec.ts +75 -0
- package/src/publish/artifact-asset-contract.ts +152 -0
- package/src/publish/artifact-asset-parse.ts +401 -0
- package/src/publish/artifact-asset-sniff.ts +108 -0
- package/src/publish/artifact-asset-validate.ts +209 -0
- package/src/publish/artifact-assets.ts +58 -0
- package/src/publish/artifact-validation.ts +32 -6
- package/src/publish/artifact.ts +50 -3
- package/src/publish/attachment-bundle.ts +145 -0
- package/src/publish/attachment-discover.ts +203 -0
- package/src/publish/attachment-load.ts +133 -0
- package/src/publish/attachment-obsidian.ts +45 -0
- package/src/publish/attachment-path.ts +334 -0
- package/src/publish/attachment-raster.ts +852 -0
- package/src/publish/attachment-resolver.ts +280 -0
- package/src/publish/attachment-types.ts +54 -0
- package/src/publish/encrypted-export.ts +121 -44
- package/src/publish/export-attachments.ts +224 -0
- package/src/publish/export-service.ts +142 -80
- package/src/publish/obsidian-sanitize.ts +121 -13
- package/src/sdk/client.ts +167 -115
- package/src/sdk/index.ts +7 -0
- package/src/sdk/types.ts +32 -2
- package/src/serve/file-refactor-http.ts +239 -0
- package/src/serve/public/components/RefactorImpactPreview.tsx +227 -0
- package/src/serve/public/globals.built.css +1 -1
- package/src/serve/public/pages/DocView.tsx +176 -41
- package/src/serve/routes/api.ts +193 -105
- package/src/store/migrations/026-file-refactor-recovery-journal.ts +72 -0
- package/src/store/migrations/index.ts +2 -0
- package/src/store/sqlite/adapter.ts +452 -0
- package/src/store/sqlite/file-refactor-journal-store.ts +275 -0
- package/src/store/types.ts +84 -0
- package/browser-extension/artifacts/gno-browser-clipper-v1.31.0.zip.sha256 +0 -1
|
@@ -16,6 +16,11 @@ import { AsyncLocalStorage } from "node:async_hooks";
|
|
|
16
16
|
import { basename } from "node:path";
|
|
17
17
|
|
|
18
18
|
import type { EgressLineage } from "../../core/egress-provenance";
|
|
19
|
+
import type {
|
|
20
|
+
FileRefactorJournalAdvance,
|
|
21
|
+
FileRefactorRecoveryReceipt,
|
|
22
|
+
FileRefactorRecoveryReceiptDraft,
|
|
23
|
+
} from "../../core/file-refactor-journal";
|
|
19
24
|
import type {
|
|
20
25
|
ActivationIndexDocument,
|
|
21
26
|
ActivationIndexIdentity,
|
|
@@ -55,6 +60,8 @@ import type {
|
|
|
55
60
|
EgressAuditStatusResult,
|
|
56
61
|
FtsResult,
|
|
57
62
|
FtsSearchOptions,
|
|
63
|
+
FileRefactorResolutionReferrerDocument,
|
|
64
|
+
FileRefactorResolutionSnapshot,
|
|
58
65
|
GetGraphNeighborsOptions,
|
|
59
66
|
GetGraphOptions,
|
|
60
67
|
GraphEdgeConfidence,
|
|
@@ -112,6 +119,10 @@ import {
|
|
|
112
119
|
type FtsTokenizer,
|
|
113
120
|
resolveConfiguredEgressPolicy,
|
|
114
121
|
} from "../../config/types";
|
|
122
|
+
import {
|
|
123
|
+
getDocumentCapabilities,
|
|
124
|
+
isTextLikeReferenceDocument,
|
|
125
|
+
} from "../../core/document-capabilities";
|
|
115
126
|
import { analyzeGraphCommunities } from "../../core/graph-analysis";
|
|
116
127
|
import {
|
|
117
128
|
classifyResolvedGraphEdge,
|
|
@@ -122,6 +133,7 @@ import {
|
|
|
122
133
|
buildWikiBestRankMatchCountSubquery,
|
|
123
134
|
buildWikiBestRankSubquery,
|
|
124
135
|
} from "../../core/graph-resolver";
|
|
136
|
+
import { buildContentPrefilterNeedles } from "../../core/link-relevance";
|
|
125
137
|
import { normalizeWikiName, stripWikiMdExt } from "../../core/links";
|
|
126
138
|
import {
|
|
127
139
|
parseActivationReceipt,
|
|
@@ -160,6 +172,12 @@ import {
|
|
|
160
172
|
listEgressAuditReceipts as listStoredEgressAuditReceipts,
|
|
161
173
|
purgeEgressAuditReceipts as purgeStoredEgressAuditReceipts,
|
|
162
174
|
} from "./egress-audit-store";
|
|
175
|
+
import {
|
|
176
|
+
advanceFileRefactorReceipt as advanceStoredFileRefactorReceipt,
|
|
177
|
+
createFileRefactorPreparedReceipt as createStoredFileRefactorPreparedReceipt,
|
|
178
|
+
getFileRefactorReceiptById as getStoredFileRefactorReceiptById,
|
|
179
|
+
getLatestFileRefactorReceiptByPlanDigest as getStoredLatestFileRefactorReceiptByPlanDigest,
|
|
180
|
+
} from "./file-refactor-journal-store";
|
|
163
181
|
import { loadFts5Snowball } from "./fts5-snowball";
|
|
164
182
|
import { queryGraphNeighborsForSeeds } from "./graph-neighbors";
|
|
165
183
|
import {
|
|
@@ -1960,6 +1978,38 @@ export class SqliteAdapter implements StorePort, SqliteDbProvider {
|
|
|
1960
1978
|
return purgeStoredDocumentChanges(this.ensureOpen());
|
|
1961
1979
|
}
|
|
1962
1980
|
|
|
1981
|
+
async createFileRefactorPreparedReceipt(
|
|
1982
|
+
draft: FileRefactorRecoveryReceiptDraft
|
|
1983
|
+
): Promise<StoreResult<FileRefactorRecoveryReceipt>> {
|
|
1984
|
+
return createStoredFileRefactorPreparedReceipt(this.ensureOpen(), draft);
|
|
1985
|
+
}
|
|
1986
|
+
|
|
1987
|
+
async advanceFileRefactorReceipt(
|
|
1988
|
+
journalId: string,
|
|
1989
|
+
update: FileRefactorJournalAdvance
|
|
1990
|
+
): Promise<StoreResult<FileRefactorRecoveryReceipt>> {
|
|
1991
|
+
return advanceStoredFileRefactorReceipt(
|
|
1992
|
+
this.ensureOpen(),
|
|
1993
|
+
journalId,
|
|
1994
|
+
update
|
|
1995
|
+
);
|
|
1996
|
+
}
|
|
1997
|
+
|
|
1998
|
+
async getFileRefactorReceiptById(
|
|
1999
|
+
journalId: string
|
|
2000
|
+
): Promise<StoreResult<FileRefactorRecoveryReceipt | null>> {
|
|
2001
|
+
return getStoredFileRefactorReceiptById(this.ensureOpen(), journalId);
|
|
2002
|
+
}
|
|
2003
|
+
|
|
2004
|
+
async getLatestFileRefactorReceiptByPlanDigest(
|
|
2005
|
+
planDigest: string
|
|
2006
|
+
): Promise<StoreResult<FileRefactorRecoveryReceipt | null>> {
|
|
2007
|
+
return getStoredLatestFileRefactorReceiptByPlanDigest(
|
|
2008
|
+
this.ensureOpen(),
|
|
2009
|
+
planDigest
|
|
2010
|
+
);
|
|
2011
|
+
}
|
|
2012
|
+
|
|
1963
2013
|
async upsertSavedCapsuleRegistration(
|
|
1964
2014
|
input: SavedCapsuleRegistrationInput
|
|
1965
2015
|
): Promise<StoreResult<SavedCapsuleRegistrationRecord>> {
|
|
@@ -3371,6 +3421,408 @@ export class SqliteAdapter implements StorePort, SqliteDbProvider {
|
|
|
3371
3421
|
}
|
|
3372
3422
|
}
|
|
3373
3423
|
|
|
3424
|
+
/**
|
|
3425
|
+
* Bounded read seam for reference-safe rename/move planning.
|
|
3426
|
+
* Loads catalog metadata plus content for indexed backlinks unioned with a
|
|
3427
|
+
* conservative SQL content prefilter (opaque embeds/HTML/code/malformed may
|
|
3428
|
+
* not appear in doc_links). Missing mirror content fails closed.
|
|
3429
|
+
*/
|
|
3430
|
+
async getFileRefactorResolutionSnapshot(input: {
|
|
3431
|
+
sourceUri: string;
|
|
3432
|
+
maxCatalogDocuments?: number;
|
|
3433
|
+
maxReferrerDocuments?: number;
|
|
3434
|
+
maxContentCharsPerDocument?: number;
|
|
3435
|
+
maxTotalContentChars?: number;
|
|
3436
|
+
}): Promise<StoreResult<FileRefactorResolutionSnapshot>> {
|
|
3437
|
+
try {
|
|
3438
|
+
const db = this.ensureOpen();
|
|
3439
|
+
const maxCatalog = Math.max(
|
|
3440
|
+
1,
|
|
3441
|
+
Math.floor(input.maxCatalogDocuments ?? 5_000)
|
|
3442
|
+
);
|
|
3443
|
+
const maxReferrers = Math.max(
|
|
3444
|
+
1,
|
|
3445
|
+
Math.floor(input.maxReferrerDocuments ?? 5_000)
|
|
3446
|
+
);
|
|
3447
|
+
const maxChars = Math.max(
|
|
3448
|
+
1,
|
|
3449
|
+
Math.floor(input.maxContentCharsPerDocument ?? 1_000_000)
|
|
3450
|
+
);
|
|
3451
|
+
const maxTotalChars = Math.max(
|
|
3452
|
+
maxChars,
|
|
3453
|
+
Math.floor(input.maxTotalContentChars ?? 20_000_000)
|
|
3454
|
+
);
|
|
3455
|
+
const truncationReasons: string[] = [];
|
|
3456
|
+
|
|
3457
|
+
const sourceRow = db
|
|
3458
|
+
.query<
|
|
3459
|
+
{
|
|
3460
|
+
id: number;
|
|
3461
|
+
uri: string;
|
|
3462
|
+
rel_path: string;
|
|
3463
|
+
collection: string;
|
|
3464
|
+
title: string | null;
|
|
3465
|
+
mirror_hash: string | null;
|
|
3466
|
+
source_ext: string;
|
|
3467
|
+
source_mime: string;
|
|
3468
|
+
record_key: string | null;
|
|
3469
|
+
},
|
|
3470
|
+
[string]
|
|
3471
|
+
>(
|
|
3472
|
+
`SELECT id, uri, rel_path, collection, title, mirror_hash,
|
|
3473
|
+
source_ext, source_mime, record_key
|
|
3474
|
+
FROM documents
|
|
3475
|
+
WHERE uri = ? AND active = 1`
|
|
3476
|
+
)
|
|
3477
|
+
.get(input.sourceUri);
|
|
3478
|
+
|
|
3479
|
+
if (!sourceRow) {
|
|
3480
|
+
return err("NOT_FOUND", `Document not found: ${input.sourceUri}`);
|
|
3481
|
+
}
|
|
3482
|
+
|
|
3483
|
+
const sourceCaps = getDocumentCapabilities({
|
|
3484
|
+
sourceExt: sourceRow.source_ext,
|
|
3485
|
+
sourceMime: sourceRow.source_mime,
|
|
3486
|
+
contentAvailable: Boolean(sourceRow.mirror_hash),
|
|
3487
|
+
recordKey: sourceRow.record_key,
|
|
3488
|
+
});
|
|
3489
|
+
|
|
3490
|
+
let sourceContent: string | null = null;
|
|
3491
|
+
let sourceContentTruncated = false;
|
|
3492
|
+
if (sourceRow.mirror_hash) {
|
|
3493
|
+
const contentRow = db
|
|
3494
|
+
.query<{ markdown: string }, [number, string]>(
|
|
3495
|
+
`SELECT substr(markdown, 1, ?) AS markdown
|
|
3496
|
+
FROM content WHERE mirror_hash = ?`
|
|
3497
|
+
)
|
|
3498
|
+
.get(maxChars + 1, sourceRow.mirror_hash);
|
|
3499
|
+
if (contentRow) {
|
|
3500
|
+
sourceContentTruncated = contentRow.markdown.length > maxChars;
|
|
3501
|
+
sourceContent = sourceContentTruncated
|
|
3502
|
+
? contentRow.markdown.slice(0, maxChars)
|
|
3503
|
+
: contentRow.markdown;
|
|
3504
|
+
if (sourceContentTruncated) {
|
|
3505
|
+
truncationReasons.push("source_content_truncated");
|
|
3506
|
+
}
|
|
3507
|
+
} else {
|
|
3508
|
+
truncationReasons.push("source_content_missing");
|
|
3509
|
+
}
|
|
3510
|
+
} else {
|
|
3511
|
+
// Null mirror_hash means source bytes are unavailable — fail closed.
|
|
3512
|
+
truncationReasons.push("source_content_missing");
|
|
3513
|
+
}
|
|
3514
|
+
|
|
3515
|
+
const catalogRows = db
|
|
3516
|
+
.query<
|
|
3517
|
+
{
|
|
3518
|
+
id: number;
|
|
3519
|
+
uri: string;
|
|
3520
|
+
rel_path: string;
|
|
3521
|
+
collection: string;
|
|
3522
|
+
title: string | null;
|
|
3523
|
+
},
|
|
3524
|
+
[string, number]
|
|
3525
|
+
>(
|
|
3526
|
+
`SELECT id, uri, rel_path, collection, title
|
|
3527
|
+
FROM documents
|
|
3528
|
+
WHERE active = 1 AND collection = ?
|
|
3529
|
+
ORDER BY id
|
|
3530
|
+
LIMIT ?`
|
|
3531
|
+
)
|
|
3532
|
+
.all(sourceRow.collection, maxCatalog + 1);
|
|
3533
|
+
|
|
3534
|
+
if (catalogRows.length > maxCatalog) {
|
|
3535
|
+
truncationReasons.push("catalog_truncated");
|
|
3536
|
+
}
|
|
3537
|
+
const catalog = catalogRows.slice(0, maxCatalog).map((row) => ({
|
|
3538
|
+
id: row.id,
|
|
3539
|
+
uri: row.uri,
|
|
3540
|
+
relPath: row.rel_path,
|
|
3541
|
+
collection: row.collection,
|
|
3542
|
+
title: row.title,
|
|
3543
|
+
}));
|
|
3544
|
+
|
|
3545
|
+
const occupiedRelPaths = catalog.map((doc) => doc.relPath);
|
|
3546
|
+
|
|
3547
|
+
const backlinksResult = await this.getBacklinksForDoc(sourceRow.id, {
|
|
3548
|
+
collection: sourceRow.collection,
|
|
3549
|
+
});
|
|
3550
|
+
if (!backlinksResult.ok) {
|
|
3551
|
+
return backlinksResult;
|
|
3552
|
+
}
|
|
3553
|
+
|
|
3554
|
+
const candidateIds = new Set<number>();
|
|
3555
|
+
for (const row of backlinksResult.value) {
|
|
3556
|
+
if (row.sourceDocId !== sourceRow.id) {
|
|
3557
|
+
candidateIds.add(row.sourceDocId);
|
|
3558
|
+
}
|
|
3559
|
+
}
|
|
3560
|
+
|
|
3561
|
+
const needles = buildContentPrefilterNeedles({
|
|
3562
|
+
relPath: sourceRow.rel_path,
|
|
3563
|
+
title: sourceRow.title,
|
|
3564
|
+
});
|
|
3565
|
+
const escapeLike = (value: string): string =>
|
|
3566
|
+
value
|
|
3567
|
+
.replaceAll("\\", "\\\\")
|
|
3568
|
+
.replaceAll("%", "\\%")
|
|
3569
|
+
.replaceAll("_", "\\_");
|
|
3570
|
+
|
|
3571
|
+
if (needles.length > 0) {
|
|
3572
|
+
const likeClauses = needles
|
|
3573
|
+
.map(() => `c.markdown LIKE '%' || ? || '%' ESCAPE '\\'`)
|
|
3574
|
+
.join(" OR ");
|
|
3575
|
+
const prefilterRows = db
|
|
3576
|
+
.query<{ id: number }, (string | number)[]>(
|
|
3577
|
+
`SELECT DISTINCT d.id AS id
|
|
3578
|
+
FROM documents d
|
|
3579
|
+
INNER JOIN content c ON c.mirror_hash = d.mirror_hash
|
|
3580
|
+
WHERE d.active = 1
|
|
3581
|
+
AND d.collection = ?
|
|
3582
|
+
AND d.id != ?
|
|
3583
|
+
AND (${likeClauses})
|
|
3584
|
+
ORDER BY d.id
|
|
3585
|
+
LIMIT ?`
|
|
3586
|
+
)
|
|
3587
|
+
.all(
|
|
3588
|
+
sourceRow.collection,
|
|
3589
|
+
sourceRow.id,
|
|
3590
|
+
...needles.map(escapeLike),
|
|
3591
|
+
maxReferrers + 1
|
|
3592
|
+
);
|
|
3593
|
+
if (prefilterRows.length > maxReferrers) {
|
|
3594
|
+
truncationReasons.push("content_prefilter_truncated");
|
|
3595
|
+
}
|
|
3596
|
+
for (const row of prefilterRows.slice(0, maxReferrers + 1)) {
|
|
3597
|
+
candidateIds.add(row.id);
|
|
3598
|
+
}
|
|
3599
|
+
}
|
|
3600
|
+
|
|
3601
|
+
// Completeness: union same-collection docs whose mirror content cannot be
|
|
3602
|
+
// loaded. Text-like docs (including read-only logical .md records) fail
|
|
3603
|
+
// closed; non-text binaries are omitted (they cannot hold markdown/wiki/
|
|
3604
|
+
// HTML refs). Preserve referrer caps via LIMIT + sorted slice below.
|
|
3605
|
+
const missingMirrorRows = db
|
|
3606
|
+
.query<
|
|
3607
|
+
{
|
|
3608
|
+
id: number;
|
|
3609
|
+
source_ext: string;
|
|
3610
|
+
source_mime: string;
|
|
3611
|
+
},
|
|
3612
|
+
[string, number, number]
|
|
3613
|
+
>(
|
|
3614
|
+
`SELECT d.id AS id,
|
|
3615
|
+
d.source_ext AS source_ext,
|
|
3616
|
+
d.source_mime AS source_mime
|
|
3617
|
+
FROM documents d
|
|
3618
|
+
WHERE d.active = 1
|
|
3619
|
+
AND d.collection = ?
|
|
3620
|
+
AND d.id != ?
|
|
3621
|
+
AND (
|
|
3622
|
+
d.mirror_hash IS NULL
|
|
3623
|
+
OR NOT EXISTS (
|
|
3624
|
+
SELECT 1 FROM content c WHERE c.mirror_hash = d.mirror_hash
|
|
3625
|
+
)
|
|
3626
|
+
)
|
|
3627
|
+
ORDER BY d.id
|
|
3628
|
+
LIMIT ?`
|
|
3629
|
+
)
|
|
3630
|
+
.all(sourceRow.collection, sourceRow.id, maxReferrers + 1);
|
|
3631
|
+
if (missingMirrorRows.length > maxReferrers) {
|
|
3632
|
+
truncationReasons.push("missing_mirror_scan_truncated");
|
|
3633
|
+
}
|
|
3634
|
+
for (const row of missingMirrorRows) {
|
|
3635
|
+
if (!isTextLikeReferenceDocument(row.source_ext, row.source_mime)) {
|
|
3636
|
+
continue;
|
|
3637
|
+
}
|
|
3638
|
+
candidateIds.add(row.id);
|
|
3639
|
+
}
|
|
3640
|
+
|
|
3641
|
+
const sortedCandidateIds = [...candidateIds].sort((a, b) => a - b);
|
|
3642
|
+
if (sortedCandidateIds.length > maxReferrers) {
|
|
3643
|
+
truncationReasons.push("referrers_truncated");
|
|
3644
|
+
}
|
|
3645
|
+
|
|
3646
|
+
const referrers: FileRefactorResolutionReferrerDocument[] = [];
|
|
3647
|
+
let totalContentChars = sourceContent?.length ?? 0;
|
|
3648
|
+
|
|
3649
|
+
for (const referrerId of sortedCandidateIds.slice(0, maxReferrers)) {
|
|
3650
|
+
const referrerRow = db
|
|
3651
|
+
.query<
|
|
3652
|
+
{
|
|
3653
|
+
id: number;
|
|
3654
|
+
uri: string;
|
|
3655
|
+
rel_path: string;
|
|
3656
|
+
collection: string;
|
|
3657
|
+
title: string | null;
|
|
3658
|
+
mirror_hash: string | null;
|
|
3659
|
+
source_ext: string;
|
|
3660
|
+
source_mime: string;
|
|
3661
|
+
record_key: string | null;
|
|
3662
|
+
},
|
|
3663
|
+
[number]
|
|
3664
|
+
>(
|
|
3665
|
+
`SELECT id, uri, rel_path, collection, title, mirror_hash,
|
|
3666
|
+
source_ext, source_mime, record_key
|
|
3667
|
+
FROM documents
|
|
3668
|
+
WHERE id = ? AND active = 1`
|
|
3669
|
+
)
|
|
3670
|
+
.get(referrerId);
|
|
3671
|
+
if (!referrerRow) continue;
|
|
3672
|
+
|
|
3673
|
+
const caps = getDocumentCapabilities({
|
|
3674
|
+
sourceExt: referrerRow.source_ext,
|
|
3675
|
+
sourceMime: referrerRow.source_mime,
|
|
3676
|
+
contentAvailable: Boolean(referrerRow.mirror_hash),
|
|
3677
|
+
recordKey: referrerRow.record_key,
|
|
3678
|
+
});
|
|
3679
|
+
|
|
3680
|
+
if (!referrerRow.mirror_hash) {
|
|
3681
|
+
truncationReasons.push("referrer_content_missing");
|
|
3682
|
+
referrers.push({
|
|
3683
|
+
id: referrerRow.id,
|
|
3684
|
+
uri: referrerRow.uri,
|
|
3685
|
+
relPath: referrerRow.rel_path,
|
|
3686
|
+
collection: referrerRow.collection,
|
|
3687
|
+
title: referrerRow.title,
|
|
3688
|
+
content: null,
|
|
3689
|
+
contentTruncated: false,
|
|
3690
|
+
contentMissing: true,
|
|
3691
|
+
editable: caps.editable,
|
|
3692
|
+
editableReason: caps.editable
|
|
3693
|
+
? undefined
|
|
3694
|
+
: caps.reason
|
|
3695
|
+
? "read_only_document"
|
|
3696
|
+
: "capability_denied",
|
|
3697
|
+
sourceExt: referrerRow.source_ext,
|
|
3698
|
+
sourceMime: referrerRow.source_mime,
|
|
3699
|
+
recordKey: referrerRow.record_key,
|
|
3700
|
+
});
|
|
3701
|
+
continue;
|
|
3702
|
+
}
|
|
3703
|
+
|
|
3704
|
+
const contentRow = db
|
|
3705
|
+
.query<{ markdown: string }, [number, string]>(
|
|
3706
|
+
`SELECT substr(markdown, 1, ?) AS markdown
|
|
3707
|
+
FROM content WHERE mirror_hash = ?`
|
|
3708
|
+
)
|
|
3709
|
+
.get(maxChars + 1, referrerRow.mirror_hash);
|
|
3710
|
+
|
|
3711
|
+
if (!contentRow) {
|
|
3712
|
+
truncationReasons.push("referrer_content_missing");
|
|
3713
|
+
referrers.push({
|
|
3714
|
+
id: referrerRow.id,
|
|
3715
|
+
uri: referrerRow.uri,
|
|
3716
|
+
relPath: referrerRow.rel_path,
|
|
3717
|
+
collection: referrerRow.collection,
|
|
3718
|
+
title: referrerRow.title,
|
|
3719
|
+
content: null,
|
|
3720
|
+
contentTruncated: false,
|
|
3721
|
+
contentMissing: true,
|
|
3722
|
+
editable: caps.editable,
|
|
3723
|
+
editableReason: caps.editable
|
|
3724
|
+
? undefined
|
|
3725
|
+
: caps.reason
|
|
3726
|
+
? "read_only_document"
|
|
3727
|
+
: "capability_denied",
|
|
3728
|
+
sourceExt: referrerRow.source_ext,
|
|
3729
|
+
sourceMime: referrerRow.source_mime,
|
|
3730
|
+
recordKey: referrerRow.record_key,
|
|
3731
|
+
});
|
|
3732
|
+
continue;
|
|
3733
|
+
}
|
|
3734
|
+
|
|
3735
|
+
const contentTruncated = contentRow.markdown.length > maxChars;
|
|
3736
|
+
if (contentTruncated) {
|
|
3737
|
+
truncationReasons.push("referrer_content_truncated");
|
|
3738
|
+
}
|
|
3739
|
+
const content = contentTruncated
|
|
3740
|
+
? contentRow.markdown.slice(0, maxChars)
|
|
3741
|
+
: contentRow.markdown;
|
|
3742
|
+
totalContentChars += content.length;
|
|
3743
|
+
if (totalContentChars > maxTotalChars) {
|
|
3744
|
+
truncationReasons.push("total_content_truncated");
|
|
3745
|
+
referrers.push({
|
|
3746
|
+
id: referrerRow.id,
|
|
3747
|
+
uri: referrerRow.uri,
|
|
3748
|
+
relPath: referrerRow.rel_path,
|
|
3749
|
+
collection: referrerRow.collection,
|
|
3750
|
+
title: referrerRow.title,
|
|
3751
|
+
content: null,
|
|
3752
|
+
contentTruncated: false,
|
|
3753
|
+
contentMissing: true,
|
|
3754
|
+
editable: caps.editable,
|
|
3755
|
+
editableReason: caps.editable
|
|
3756
|
+
? undefined
|
|
3757
|
+
: caps.reason
|
|
3758
|
+
? "read_only_document"
|
|
3759
|
+
: "capability_denied",
|
|
3760
|
+
sourceExt: referrerRow.source_ext,
|
|
3761
|
+
sourceMime: referrerRow.source_mime,
|
|
3762
|
+
recordKey: referrerRow.record_key,
|
|
3763
|
+
});
|
|
3764
|
+
continue;
|
|
3765
|
+
}
|
|
3766
|
+
|
|
3767
|
+
referrers.push({
|
|
3768
|
+
id: referrerRow.id,
|
|
3769
|
+
uri: referrerRow.uri,
|
|
3770
|
+
relPath: referrerRow.rel_path,
|
|
3771
|
+
collection: referrerRow.collection,
|
|
3772
|
+
title: referrerRow.title,
|
|
3773
|
+
content,
|
|
3774
|
+
contentTruncated,
|
|
3775
|
+
contentMissing: false,
|
|
3776
|
+
editable: caps.editable,
|
|
3777
|
+
editableReason: caps.editable
|
|
3778
|
+
? undefined
|
|
3779
|
+
: caps.reason
|
|
3780
|
+
? "read_only_document"
|
|
3781
|
+
: "capability_denied",
|
|
3782
|
+
sourceExt: referrerRow.source_ext,
|
|
3783
|
+
sourceMime: referrerRow.source_mime,
|
|
3784
|
+
recordKey: referrerRow.record_key,
|
|
3785
|
+
});
|
|
3786
|
+
}
|
|
3787
|
+
|
|
3788
|
+
const snapshot: FileRefactorResolutionSnapshot = {
|
|
3789
|
+
source: {
|
|
3790
|
+
id: sourceRow.id,
|
|
3791
|
+
uri: sourceRow.uri,
|
|
3792
|
+
relPath: sourceRow.rel_path,
|
|
3793
|
+
collection: sourceRow.collection,
|
|
3794
|
+
title: sourceRow.title,
|
|
3795
|
+
mirrorHash: sourceRow.mirror_hash,
|
|
3796
|
+
sourceExt: sourceRow.source_ext,
|
|
3797
|
+
sourceMime: sourceRow.source_mime,
|
|
3798
|
+
recordKey: sourceRow.record_key,
|
|
3799
|
+
content: sourceContent,
|
|
3800
|
+
contentTruncated: sourceContentTruncated,
|
|
3801
|
+
editable: sourceCaps.editable,
|
|
3802
|
+
editableReason: sourceCaps.editable
|
|
3803
|
+
? undefined
|
|
3804
|
+
: sourceCaps.reason
|
|
3805
|
+
? "read_only_document"
|
|
3806
|
+
: "capability_denied",
|
|
3807
|
+
},
|
|
3808
|
+
catalog,
|
|
3809
|
+
referrers,
|
|
3810
|
+
occupiedRelPaths,
|
|
3811
|
+
truncated: truncationReasons.length > 0,
|
|
3812
|
+
truncationReasons: [...new Set(truncationReasons)].sort(),
|
|
3813
|
+
};
|
|
3814
|
+
return ok(snapshot);
|
|
3815
|
+
} catch (cause) {
|
|
3816
|
+
return err(
|
|
3817
|
+
"QUERY_FAILED",
|
|
3818
|
+
cause instanceof Error
|
|
3819
|
+
? cause.message
|
|
3820
|
+
: "Failed to load file refactor resolution snapshot",
|
|
3821
|
+
cause
|
|
3822
|
+
);
|
|
3823
|
+
}
|
|
3824
|
+
}
|
|
3825
|
+
|
|
3374
3826
|
/**
|
|
3375
3827
|
* Set semantic edges for a document.
|
|
3376
3828
|
* Replaces edges from the given source.
|