@lapis-notes/history 0.1.2 → 0.2.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/CHANGELOG.md +32 -0
- package/LICENSE.md +3 -7
- package/README.md +2 -2
- package/dist/history-compare-panel.css +28 -6
- package/dist/history-compare-panel.svelte +115 -108
- package/dist/repository/NOTICE.md +11 -0
- package/dist/repository/components/RepositoryAuthorAvatar.svelte +77 -0
- package/dist/repository/components/RepositoryAuthorAvatar.svelte.d.ts +11 -0
- package/dist/repository/components/RepositoryBackupStatus.svelte +236 -0
- package/dist/repository/components/RepositoryBackupStatus.svelte.d.ts +11 -0
- package/dist/repository/components/RepositoryChangedFiles.svelte +104 -0
- package/dist/repository/components/RepositoryChangedFiles.svelte.d.ts +13 -0
- package/dist/repository/components/RepositoryCommitMessage.svelte +93 -0
- package/dist/repository/components/RepositoryCommitMessage.svelte.d.ts +6 -0
- package/dist/repository/components/RepositoryCommitPicker.svelte +205 -0
- package/dist/repository/components/RepositoryCommitPicker.svelte.d.ts +17 -0
- package/dist/repository/components/RepositoryComparisonBar.svelte +71 -0
- package/dist/repository/components/RepositoryComparisonBar.svelte.d.ts +9 -0
- package/dist/repository/components/RepositoryComparisonTime.svelte +32 -0
- package/dist/repository/components/RepositoryComparisonTime.svelte.d.ts +6 -0
- package/dist/repository/components/RepositoryDiff.svelte +56 -0
- package/dist/repository/components/RepositoryDiff.svelte.d.ts +11 -0
- package/dist/repository/components/RepositoryDiffColumn.svelte +78 -0
- package/dist/repository/components/RepositoryDiffColumn.svelte.d.ts +14 -0
- package/dist/repository/components/RepositoryDiffControls.svelte +117 -0
- package/dist/repository/components/RepositoryDiffControls.svelte.d.ts +8 -0
- package/dist/repository/components/RepositoryFileHistory.svelte +170 -0
- package/dist/repository/components/RepositoryFileHistory.svelte.d.ts +10 -0
- package/dist/repository/components/RepositoryFileTitle.svelte +30 -0
- package/dist/repository/components/RepositoryFileTitle.svelte.d.ts +6 -0
- package/dist/repository/components/RepositoryGraph.svelte +216 -0
- package/dist/repository/components/RepositoryGraph.svelte.d.ts +19 -0
- package/dist/repository/components/RepositoryGraphSvg.svelte +110 -0
- package/dist/repository/components/RepositoryGraphSvg.svelte.d.ts +11 -0
- package/dist/repository/components/RepositoryIdentifiers.svelte +221 -0
- package/dist/repository/components/RepositoryIdentifiers.svelte.d.ts +15 -0
- package/dist/repository/components/RepositoryLogHeader.svelte +90 -0
- package/dist/repository/components/RepositoryLogHeader.svelte.d.ts +23 -0
- package/dist/repository/components/RepositoryOperationArguments.svelte +52 -0
- package/dist/repository/components/RepositoryOperationArguments.svelte.d.ts +6 -0
- package/dist/repository/components/RepositoryOperationColumn.svelte +163 -0
- package/dist/repository/components/RepositoryOperationColumn.svelte.d.ts +11 -0
- package/dist/repository/components/RepositoryOperationFiles.svelte +245 -0
- package/dist/repository/components/RepositoryOperationFiles.svelte.d.ts +14 -0
- package/dist/repository/components/RepositoryOperationMessage.svelte +169 -0
- package/dist/repository/components/RepositoryOperationMessage.svelte.d.ts +10 -0
- package/dist/repository/components/RepositoryOperationOption.svelte +183 -0
- package/dist/repository/components/RepositoryOperationOption.svelte.d.ts +10 -0
- package/dist/repository/components/RepositoryOperationParentPicker.svelte +188 -0
- package/dist/repository/components/RepositoryOperationParentPicker.svelte.d.ts +14 -0
- package/dist/repository/components/RepositoryOperationPinPicker.svelte +170 -0
- package/dist/repository/components/RepositoryOperationPinPicker.svelte.d.ts +13 -0
- package/dist/repository/components/RepositoryOperationRail.svelte +136 -0
- package/dist/repository/components/RepositoryOperationRail.svelte.d.ts +9 -0
- package/dist/repository/components/RepositoryOperationTarget.svelte +99 -0
- package/dist/repository/components/RepositoryOperationTarget.svelte.d.ts +8 -0
- package/dist/repository/components/RepositoryOperations.svelte +199 -0
- package/dist/repository/components/RepositoryOperations.svelte.d.ts +12 -0
- package/dist/repository/components/RepositoryPanel.svelte +207 -0
- package/dist/repository/components/RepositoryPanel.svelte.d.ts +15 -0
- package/dist/repository/components/RepositoryParentSummary.svelte +52 -0
- package/dist/repository/components/RepositoryParentSummary.svelte.d.ts +10 -0
- package/dist/repository/components/RepositoryPickerSearch.svelte +51 -0
- package/dist/repository/components/RepositoryPickerSearch.svelte.d.ts +11 -0
- package/dist/repository/components/RepositoryRestoreDialog.svelte +81 -0
- package/dist/repository/components/RepositoryRestoreDialog.svelte.d.ts +7 -0
- package/dist/repository/components/RepositoryRevisionActions.svelte +53 -0
- package/dist/repository/components/RepositoryRevisionActions.svelte.d.ts +9 -0
- package/dist/repository/components/RepositoryRevisionFiles.svelte +110 -0
- package/dist/repository/components/RepositoryRevisionFiles.svelte.d.ts +14 -0
- package/dist/repository/components/RepositoryRevisionOption.svelte +60 -0
- package/dist/repository/components/RepositoryRevisionOption.svelte.d.ts +9 -0
- package/dist/repository/components/RepositoryRevisionPicker.svelte +165 -0
- package/dist/repository/components/RepositoryRevisionPicker.svelte.d.ts +14 -0
- package/dist/repository/components/RepositoryRevisions.svelte +115 -0
- package/dist/repository/components/RepositoryRevisions.svelte.d.ts +20 -0
- package/dist/repository/components/RepositoryShell.svelte +44 -0
- package/dist/repository/components/RepositoryShell.svelte.d.ts +11 -0
- package/dist/repository/components/RepositorySkeleton.svelte +138 -0
- package/dist/repository/components/RepositorySkeleton.svelte.d.ts +7 -0
- package/dist/repository/components/RepositorySourcePicker.svelte +114 -0
- package/dist/repository/components/RepositorySourcePicker.svelte.d.ts +7 -0
- package/dist/repository/components/RepositoryUpstreamActions.svelte +125 -0
- package/dist/repository/components/RepositoryUpstreamActions.svelte.d.ts +8 -0
- package/dist/repository/components/RepositoryWorkingCopyStatus.svelte +290 -0
- package/dist/repository/components/RepositoryWorkingCopyStatus.svelte.d.ts +11 -0
- package/dist/repository/components/RepositoryWorkspacePicker.svelte +158 -0
- package/dist/repository/components/RepositoryWorkspacePicker.svelte.d.ts +11 -0
- package/dist/repository/components/backup/AdoptionSettings.svelte +95 -0
- package/dist/repository/components/backup/AdoptionSettings.svelte.d.ts +7 -0
- package/dist/repository/components/backup/BackupCard.svelte +79 -0
- package/dist/repository/components/backup/BackupCard.svelte.d.ts +14 -0
- package/dist/repository/components/backup/BackupField.svelte +45 -0
- package/dist/repository/components/backup/BackupField.svelte.d.ts +10 -0
- package/dist/repository/components/backup/BackupSelect.svelte +71 -0
- package/dist/repository/components/backup/BackupSelect.svelte.d.ts +35 -0
- package/dist/repository/components/backup/BackupSettings.svelte +122 -0
- package/dist/repository/components/backup/BackupSettings.svelte.d.ts +18 -0
- package/dist/repository/components/backup/BackupSettingsField.svelte +13 -0
- package/dist/repository/components/backup/BackupSettingsField.svelte.d.ts +4 -0
- package/dist/repository/components/backup/ForgeAccounts.svelte +231 -0
- package/dist/repository/components/backup/ForgeAccounts.svelte.d.ts +9 -0
- package/dist/repository/components/backup/ForgeAuthorization.svelte +267 -0
- package/dist/repository/components/backup/ForgeAuthorization.svelte.d.ts +9 -0
- package/dist/repository/components/backup/ForgeIcon.svelte +21 -0
- package/dist/repository/components/backup/ForgeIcon.svelte.d.ts +7 -0
- package/dist/repository/components/backup/PublicationRecovery.svelte +129 -0
- package/dist/repository/components/backup/PublicationRecovery.svelte.d.ts +11 -0
- package/dist/repository/components/backup/RemoteSettings.svelte +288 -0
- package/dist/repository/components/backup/RemoteSettings.svelte.d.ts +11 -0
- package/dist/repository/components/backup/RepositorySettingsPage.svelte +51 -0
- package/dist/repository/components/backup/RepositorySettingsPage.svelte.d.ts +4 -0
- package/dist/repository/components/backup/StorageSettings.svelte +158 -0
- package/dist/repository/components/backup/StorageSettings.svelte.d.ts +7 -0
- package/dist/repository/components/backup/SyncConflictEditor.svelte +158 -0
- package/dist/repository/components/backup/SyncConflictEditor.svelte.d.ts +9 -0
- package/dist/repository/components/backup/SyncSettings.svelte +97 -0
- package/dist/repository/components/backup/SyncSettings.svelte.d.ts +9 -0
- package/dist/repository/components/backup/adoption-settings.d.ts +7 -0
- package/dist/repository/components/backup/adoption-settings.js +42 -0
- package/dist/repository/components/backup/backup-settings.d.ts +35 -0
- package/dist/repository/components/backup/backup-settings.js +96 -0
- package/dist/repository/components/backup/forge-icons.d.ts +10 -0
- package/dist/repository/components/backup/forge-icons.js +11 -0
- package/dist/repository/components/backup/remote-restore.d.ts +3 -0
- package/dist/repository/components/backup/remote-restore.js +17 -0
- package/dist/repository/components/backup/storage-settings.d.ts +8 -0
- package/dist/repository/components/backup/storage-settings.js +23 -0
- package/dist/repository/components/blame/RepositoryBlameCommitTitle.svelte +212 -0
- package/dist/repository/components/blame/RepositoryBlameCommitTitle.svelte.d.ts +14 -0
- package/dist/repository/components/blame/RepositoryBlameGroup.svelte +189 -0
- package/dist/repository/components/blame/RepositoryBlameGroup.svelte.d.ts +20 -0
- package/dist/repository/components/blame/RepositoryBlamePanel.svelte +148 -0
- package/dist/repository/components/blame/RepositoryBlamePanel.svelte.d.ts +13 -0
- package/dist/repository/components/blame/RepositoryBlameRows.svelte +137 -0
- package/dist/repository/components/blame/RepositoryBlameRows.svelte.d.ts +32 -0
- package/dist/repository/components/blame/RepositoryBlameView.svelte +121 -0
- package/dist/repository/components/blame/RepositoryBlameView.svelte.d.ts +16 -0
- package/dist/repository/components/blame/blame-view.d.ts +16 -0
- package/dist/repository/components/blame/blame-view.js +73 -0
- package/dist/repository/components/blame/editor-actions.d.ts +3 -0
- package/dist/repository/components/blame/editor-actions.js +53 -0
- package/dist/repository/components/conflicts/RepositoryConflictActions.svelte +83 -0
- package/dist/repository/components/conflicts/RepositoryConflictActions.svelte.d.ts +13 -0
- package/dist/repository/components/conflicts/RepositoryConflictBody.svelte +93 -0
- package/dist/repository/components/conflicts/RepositoryConflictBody.svelte.d.ts +16 -0
- package/dist/repository/components/conflicts/RepositoryConflictFileTree.svelte +84 -0
- package/dist/repository/components/conflicts/RepositoryConflictFileTree.svelte.d.ts +21 -0
- package/dist/repository/components/conflicts/RepositoryConflictPath.svelte +35 -0
- package/dist/repository/components/conflicts/RepositoryConflictPath.svelte.d.ts +9 -0
- package/dist/repository/components/conflicts/RepositoryConflictResolution.svelte +133 -0
- package/dist/repository/components/conflicts/RepositoryConflictResolution.svelte.d.ts +12 -0
- package/dist/repository/components/conflicts/RepositoryConflictSurface.svelte +105 -0
- package/dist/repository/components/conflicts/RepositoryConflictSurface.svelte.d.ts +23 -0
- package/dist/repository/components/conflicts/RepositoryConflictText.svelte +104 -0
- package/dist/repository/components/conflicts/RepositoryConflictText.svelte.d.ts +26 -0
- package/dist/repository/components/conflicts/RepositorySidebarToggleIcon.svelte +52 -0
- package/dist/repository/components/conflicts/RepositorySidebarToggleIcon.svelte.d.ts +7 -0
- package/dist/repository/components/conflicts/repository-conflict-file-tree.css +73 -0
- package/dist/repository/components/conflicts/repository-conflicts.css +125 -0
- package/dist/repository/components/file-history-view.d.ts +15 -0
- package/dist/repository/components/file-history-view.js +110 -0
- package/dist/repository/components/operation-view.d.ts +16 -0
- package/dist/repository/components/operation-view.js +95 -0
- package/dist/repository/components/repository-backup.d.ts +22 -0
- package/dist/repository/components/repository-backup.js +75 -0
- package/dist/repository/components/repository-column-chrome.css +35 -0
- package/dist/repository/components/repository-commit-picker.css +55 -0
- package/dist/repository/components/repository-feedback.d.ts +7 -0
- package/dist/repository/components/repository-feedback.js +40 -0
- package/dist/repository/components/repository-identifiers.css +199 -0
- package/dist/repository/components/repository-navigation.d.ts +4 -0
- package/dist/repository/components/repository-navigation.js +16 -0
- package/dist/repository/components/repository-operation-column.css +112 -0
- package/dist/repository/components/repository-picker-options.css +11 -0
- package/dist/repository/components/repository-plugin.d.ts +33 -0
- package/dist/repository/components/repository-plugin.js +191 -0
- package/dist/repository/components/repository-review-identifiers.css +50 -0
- package/dist/repository/components/repository-status.d.ts +13 -0
- package/dist/repository/components/repository-status.js +227 -0
- package/dist/repository/components/repository-sync.d.ts +13 -0
- package/dist/repository/components/repository-sync.js +93 -0
- package/dist/repository/components/repository-tools.d.ts +3 -0
- package/dist/repository/components/repository-tools.js +13 -0
- package/dist/repository/components/repository-view.d.ts +16 -0
- package/dist/repository/components/repository-view.js +140 -0
- package/dist/repository/components/restore-controller.d.ts +9 -0
- package/dist/repository/components/restore-controller.js +44 -0
- package/dist/repository/components/search/search-provider.d.ts +3 -0
- package/dist/repository/components/search/search-provider.js +185 -0
- package/dist/repository/controllers/adoption-controller.d.ts +29 -0
- package/dist/repository/controllers/adoption-controller.js +145 -0
- package/dist/repository/controllers/adoption.d.ts +30 -0
- package/dist/repository/controllers/adoption.js +21 -0
- package/dist/repository/controllers/ai-history.d.ts +57 -0
- package/dist/repository/controllers/ai-history.js +51 -0
- package/dist/repository/controllers/author.d.ts +2 -0
- package/dist/repository/controllers/author.js +11 -0
- package/dist/repository/controllers/background-work.d.ts +14 -0
- package/dist/repository/controllers/background-work.js +57 -0
- package/dist/repository/controllers/backup-follow.d.ts +5 -0
- package/dist/repository/controllers/backup-follow.js +29 -0
- package/dist/repository/controllers/backup.d.ts +39 -0
- package/dist/repository/controllers/backup.js +129 -0
- package/dist/repository/controllers/blame-chunks.d.ts +13 -0
- package/dist/repository/controllers/blame-chunks.js +51 -0
- package/dist/repository/controllers/blame-controller.d.ts +17 -0
- package/dist/repository/controllers/blame-controller.js +148 -0
- package/dist/repository/controllers/blame-model.d.ts +25 -0
- package/dist/repository/controllers/blame-model.js +31 -0
- package/dist/repository/controllers/blame-preferences.d.ts +3 -0
- package/dist/repository/controllers/blame-preferences.js +18 -0
- package/dist/repository/controllers/commit-cards.d.ts +4 -0
- package/dist/repository/controllers/commit-cards.js +38 -0
- package/dist/repository/controllers/conflict-menu.d.ts +2 -0
- package/dist/repository/controllers/conflict-menu.js +1 -0
- package/dist/repository/controllers/file-history-controller.d.ts +29 -0
- package/dist/repository/controllers/file-history-controller.js +182 -0
- package/dist/repository/controllers/forge-accounts.d.ts +48 -0
- package/dist/repository/controllers/forge-accounts.js +1 -0
- package/dist/repository/controllers/forge-controller.d.ts +24 -0
- package/dist/repository/controllers/forge-controller.js +168 -0
- package/dist/repository/controllers/graph/model.d.ts +20 -0
- package/dist/repository/controllers/graph/model.js +33 -0
- package/dist/repository/controllers/graph/repository-log-graph.d.ts +44 -0
- package/dist/repository/controllers/graph/repository-log-graph.js +182 -0
- package/dist/repository/controllers/graph/repository-log-lanes.d.ts +7 -0
- package/dist/repository/controllers/graph/repository-log-lanes.js +19 -0
- package/dist/repository/controllers/graph/revision-id.d.ts +3 -0
- package/dist/repository/controllers/graph/revision-id.js +10 -0
- package/dist/repository/controllers/history-canvas.d.ts +2 -0
- package/dist/repository/controllers/history-canvas.js +45 -0
- package/dist/repository/controllers/history-controller.d.ts +31 -0
- package/dist/repository/controllers/history-controller.js +238 -0
- package/dist/repository/controllers/history-files.d.ts +7 -0
- package/dist/repository/controllers/history-files.js +18 -0
- package/dist/repository/controllers/history-graph.d.ts +20 -0
- package/dist/repository/controllers/history-graph.js +89 -0
- package/dist/repository/controllers/history-index-controller.d.ts +22 -0
- package/dist/repository/controllers/history-index-controller.js +77 -0
- package/dist/repository/controllers/history-lifetime.d.ts +13 -0
- package/dist/repository/controllers/history-lifetime.js +40 -0
- package/dist/repository/controllers/history-reader.d.ts +22 -0
- package/dist/repository/controllers/history-reader.js +1 -0
- package/dist/repository/controllers/history-search-expression.d.ts +9 -0
- package/dist/repository/controllers/history-search-expression.js +86 -0
- package/dist/repository/controllers/history-selection.d.ts +5 -0
- package/dist/repository/controllers/history-selection.js +32 -0
- package/dist/repository/controllers/history-source.d.ts +10 -0
- package/dist/repository/controllers/history-source.js +7 -0
- package/dist/repository/controllers/history-state.d.ts +34 -0
- package/dist/repository/controllers/history-state.js +55 -0
- package/dist/repository/controllers/indexed-search-validation.d.ts +4 -0
- package/dist/repository/controllers/indexed-search-validation.js +64 -0
- package/dist/repository/controllers/indexed-search.d.ts +11 -0
- package/dist/repository/controllers/indexed-search.js +1 -0
- package/dist/repository/controllers/log-canvas.d.ts +2 -0
- package/dist/repository/controllers/log-canvas.js +25 -0
- package/dist/repository/controllers/native-indexed-search.d.ts +4 -0
- package/dist/repository/controllers/native-indexed-search.js +10 -0
- package/dist/repository/controllers/open-history-revision.d.ts +3 -0
- package/dist/repository/controllers/open-history-revision.js +8 -0
- package/dist/repository/controllers/operation-command.d.ts +2 -0
- package/dist/repository/controllers/operation-command.js +55 -0
- package/dist/repository/controllers/operation-controller.d.ts +33 -0
- package/dist/repository/controllers/operation-controller.js +267 -0
- package/dist/repository/controllers/operation-files.d.ts +33 -0
- package/dist/repository/controllers/operation-files.js +182 -0
- package/dist/repository/controllers/operation-graph.d.ts +17 -0
- package/dist/repository/controllers/operation-graph.js +50 -0
- package/dist/repository/controllers/operation-message.d.ts +5 -0
- package/dist/repository/controllers/operation-message.js +18 -0
- package/dist/repository/controllers/operation-metadata.d.ts +5 -0
- package/dist/repository/controllers/operation-metadata.js +26 -0
- package/dist/repository/controllers/operation-parent.d.ts +5 -0
- package/dist/repository/controllers/operation-parent.js +46 -0
- package/dist/repository/controllers/operation-state.d.ts +28 -0
- package/dist/repository/controllers/operation-state.js +26 -0
- package/dist/repository/controllers/parent-candidates.d.ts +4 -0
- package/dist/repository/controllers/parent-candidates.js +27 -0
- package/dist/repository/controllers/plugin-data.d.ts +9 -0
- package/dist/repository/controllers/plugin-data.js +33 -0
- package/dist/repository/controllers/preparation-queue.d.ts +9 -0
- package/dist/repository/controllers/preparation-queue.js +55 -0
- package/dist/repository/controllers/remote-controller.d.ts +23 -0
- package/dist/repository/controllers/remote-controller.js +98 -0
- package/dist/repository/controllers/remote.d.ts +48 -0
- package/dist/repository/controllers/remote.js +13 -0
- package/dist/repository/controllers/restore-recovery.d.ts +3 -0
- package/dist/repository/controllers/restore-recovery.js +32 -0
- package/dist/repository/controllers/restore.d.ts +66 -0
- package/dist/repository/controllers/restore.js +201 -0
- package/dist/repository/controllers/revision-comparison.d.ts +20 -0
- package/dist/repository/controllers/revision-comparison.js +89 -0
- package/dist/repository/controllers/search-controller.d.ts +19 -0
- package/dist/repository/controllers/search-controller.js +105 -0
- package/dist/repository/controllers/search-page.d.ts +2 -0
- package/dist/repository/controllers/search-page.js +39 -0
- package/dist/repository/controllers/search.d.ts +51 -0
- package/dist/repository/controllers/search.js +8 -0
- package/dist/repository/controllers/services.d.ts +7 -0
- package/dist/repository/controllers/services.js +24 -0
- package/dist/repository/controllers/storage-controller.d.ts +30 -0
- package/dist/repository/controllers/storage-controller.js +130 -0
- package/dist/repository/controllers/storage.d.ts +26 -0
- package/dist/repository/controllers/storage.js +1 -0
- package/dist/repository/controllers/sync-application.d.ts +17 -0
- package/dist/repository/controllers/sync-application.js +45 -0
- package/dist/repository/controllers/sync-controller.d.ts +31 -0
- package/dist/repository/controllers/sync-controller.js +300 -0
- package/dist/repository/controllers/sync-publication.d.ts +7 -0
- package/dist/repository/controllers/sync-publication.js +29 -0
- package/dist/repository/controllers/sync-recovery.d.ts +7 -0
- package/dist/repository/controllers/sync-recovery.js +27 -0
- package/dist/repository/controllers/sync.d.ts +62 -0
- package/dist/repository/controllers/sync.js +38 -0
- package/dist/repository/controllers/tags.d.ts +7 -0
- package/dist/repository/controllers/tags.js +71 -0
- package/dist/repository/controllers/transcript-paths.d.ts +2 -0
- package/dist/repository/controllers/transcript-paths.js +17 -0
- package/dist/repository/controllers/transcript-writers.d.ts +9 -0
- package/dist/repository/controllers/transcript-writers.js +37 -0
- package/dist/repository/controllers/working-copy-controller.d.ts +22 -0
- package/dist/repository/controllers/working-copy-controller.js +58 -0
- package/dist/repository/controllers/working-copy-status.d.ts +16 -0
- package/dist/repository/controllers/working-copy-status.js +57 -0
- package/dist/repository/controllers/workspaces.d.ts +7 -0
- package/dist/repository/controllers/workspaces.js +4 -0
- package/dist/repository/index.d.ts +9 -0
- package/dist/repository/index.js +6 -0
- package/manifest.json +12 -3
- package/package.json +43 -10
- package/registry-content/overview.md +10 -0
- package/registry.json +131 -2
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
const bindings = new WeakMap();
|
|
2
|
+
export function bindAiHistory(app, binding) {
|
|
3
|
+
if (bindings.has(app))
|
|
4
|
+
throw new Error("AI history is already bound");
|
|
5
|
+
bindings.set(app, binding);
|
|
6
|
+
return () => {
|
|
7
|
+
if (bindings.get(app) === binding)
|
|
8
|
+
bindings.delete(app);
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
export const ownedAiHistory = (app) => app ? bindings.get(app) : undefined;
|
|
12
|
+
export function parseAiTurn(value) {
|
|
13
|
+
const row = value;
|
|
14
|
+
const checkpoint = (p) => p &&
|
|
15
|
+
/^[0-9a-f]{40,128}$/u.test(p.commit) &&
|
|
16
|
+
/^[0-9a-f]{40,128}$/u.test(p.operation) &&
|
|
17
|
+
typeof p.description === "string" &&
|
|
18
|
+
Number.isSafeInteger(p.timestamp_millis);
|
|
19
|
+
if (!row ||
|
|
20
|
+
row.version !== 1 ||
|
|
21
|
+
!row.context ||
|
|
22
|
+
!["running", "complete", "incomplete"].includes(row.phase) ||
|
|
23
|
+
!Number.isSafeInteger(row.started_at) ||
|
|
24
|
+
(row.ended_at !== null && !Number.isSafeInteger(row.ended_at)) ||
|
|
25
|
+
(row.outcome !== null &&
|
|
26
|
+
!["completed", "failed", "cancelled", "unknown"].includes(row.outcome)) ||
|
|
27
|
+
(row.phase === "complete" &&
|
|
28
|
+
(!row.after || !row.outcome || row.outcome === "unknown")) ||
|
|
29
|
+
!checkpoint(row.before) ||
|
|
30
|
+
(row.after !== null && !checkpoint(row.after)))
|
|
31
|
+
throw new Error("Invalid AI history record");
|
|
32
|
+
for (const id of [row.context.conversation, row.context.turn])
|
|
33
|
+
if (typeof id !== "string" || !/^[a-zA-Z0-9-]{1,128}$/u.test(id))
|
|
34
|
+
throw new Error("Invalid AI history identity");
|
|
35
|
+
for (const text of [
|
|
36
|
+
row.context.agent,
|
|
37
|
+
row.context.harness,
|
|
38
|
+
row.context.message,
|
|
39
|
+
row.context.binding,
|
|
40
|
+
row.context.session,
|
|
41
|
+
row.context.requested_model,
|
|
42
|
+
row.context.resolved_model,
|
|
43
|
+
])
|
|
44
|
+
if (text !== null &&
|
|
45
|
+
(typeof text !== "string" ||
|
|
46
|
+
!text.length ||
|
|
47
|
+
text.length > 256 ||
|
|
48
|
+
/[\u0000-\u001f\u007f]/u.test(text)))
|
|
49
|
+
throw new Error("Invalid AI history context");
|
|
50
|
+
return row;
|
|
51
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** Display-only lookup; native identities and profile resolution stay host-owned. */
|
|
2
|
+
export async function reviewGravatar(email) {
|
|
3
|
+
const normalized = email.trim().toLowerCase();
|
|
4
|
+
if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/u.test(normalized))
|
|
5
|
+
return;
|
|
6
|
+
if (normalized.endsWith("@nostr.invalid"))
|
|
7
|
+
return;
|
|
8
|
+
const digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(normalized));
|
|
9
|
+
const hash = Array.from(new Uint8Array(digest), (byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
10
|
+
return `https://www.gravatar.com/avatar/${hash}?d=404&s=80`;
|
|
11
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { App, NotificationProgressHandle } from "@lapis-notes/api";
|
|
2
|
+
/** App-owned status progress; the caller retains error feedback and lifetime. */
|
|
3
|
+
export declare class BackgroundWork {
|
|
4
|
+
#private;
|
|
5
|
+
constructor(notifications: Pick<App["notifications"], "createProgress">, source: string);
|
|
6
|
+
begin(title: string, message?: string): NotificationProgressHandle;
|
|
7
|
+
run<T>(title: string, task: () => Promise<T>): Promise<T>;
|
|
8
|
+
follow(title: string, controller: {
|
|
9
|
+
subscribe(listener: (state: {
|
|
10
|
+
busy: boolean;
|
|
11
|
+
phase: string;
|
|
12
|
+
}) => void): () => void;
|
|
13
|
+
}): () => void;
|
|
14
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { untrack } from "svelte";
|
|
2
|
+
/** App-owned status progress; the caller retains error feedback and lifetime. */
|
|
3
|
+
export class BackgroundWork {
|
|
4
|
+
#notifications;
|
|
5
|
+
#source;
|
|
6
|
+
constructor(notifications, source) {
|
|
7
|
+
this.#notifications = notifications;
|
|
8
|
+
this.#source = source;
|
|
9
|
+
}
|
|
10
|
+
begin(title, message) {
|
|
11
|
+
return untrack(() => this.#notifications.createProgress({
|
|
12
|
+
title,
|
|
13
|
+
message,
|
|
14
|
+
source: this.#source,
|
|
15
|
+
location: "status",
|
|
16
|
+
cancellable: false,
|
|
17
|
+
persistOnComplete: false,
|
|
18
|
+
persistOnError: false,
|
|
19
|
+
}));
|
|
20
|
+
}
|
|
21
|
+
async run(title, task) {
|
|
22
|
+
const progress = this.begin(title);
|
|
23
|
+
try {
|
|
24
|
+
// Progress publication and imperative task setup must not become inputs
|
|
25
|
+
// of a Svelte effect that invokes this command.
|
|
26
|
+
const value = await untrack(task);
|
|
27
|
+
progress.complete();
|
|
28
|
+
return value;
|
|
29
|
+
}
|
|
30
|
+
catch (error) {
|
|
31
|
+
progress.fail(error);
|
|
32
|
+
throw error;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
follow(title, controller) {
|
|
36
|
+
let progress;
|
|
37
|
+
const unsubscribe = controller.subscribe((state) => {
|
|
38
|
+
if (state.busy) {
|
|
39
|
+
progress ??= this.begin(title);
|
|
40
|
+
progress.report({
|
|
41
|
+
message: state.phase === "loading"
|
|
42
|
+
? "Preparing pinned repository data"
|
|
43
|
+
: "Reading repository changes",
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
progress?.complete();
|
|
48
|
+
progress = undefined;
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
return () => {
|
|
52
|
+
unsubscribe();
|
|
53
|
+
progress?.complete();
|
|
54
|
+
progress = undefined;
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { BackupController } from "./backup.js";
|
|
2
|
+
/** Coalesce captures while retaining independent, explicitly pinned views. */
|
|
3
|
+
export declare function followBackup(backup: BackupController | undefined, controller: {
|
|
4
|
+
checkpointChanged(operation: string): Promise<void>;
|
|
5
|
+
}): () => void;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/** Coalesce captures while retaining independent, explicitly pinned views. */
|
|
2
|
+
export function followBackup(backup, controller) {
|
|
3
|
+
let closed = false, running = false;
|
|
4
|
+
let next;
|
|
5
|
+
const dispose = backup?.subscribe((state) => {
|
|
6
|
+
if (state.phase !== "ready" || !state.checkpoint)
|
|
7
|
+
return;
|
|
8
|
+
next = state.checkpoint.operation;
|
|
9
|
+
if (!running)
|
|
10
|
+
void drain();
|
|
11
|
+
});
|
|
12
|
+
async function drain() {
|
|
13
|
+
running = true;
|
|
14
|
+
try {
|
|
15
|
+
while (!closed && next) {
|
|
16
|
+
const operation = next;
|
|
17
|
+
next = undefined;
|
|
18
|
+
await controller.checkpointChanged(operation);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
finally {
|
|
22
|
+
running = false;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return () => {
|
|
26
|
+
closed = true;
|
|
27
|
+
dispose?.();
|
|
28
|
+
};
|
|
29
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export type BackupCheckpoint = {
|
|
2
|
+
operation: string;
|
|
3
|
+
commit: string;
|
|
4
|
+
change_id: string;
|
|
5
|
+
description: string;
|
|
6
|
+
timestamp_millis: number;
|
|
7
|
+
};
|
|
8
|
+
export type BackupStatus = {
|
|
9
|
+
phase: "saving" | "ready" | "failed" | "closed";
|
|
10
|
+
checkpoint: BackupCheckpoint | null;
|
|
11
|
+
error: string | null;
|
|
12
|
+
};
|
|
13
|
+
export interface BackupService {
|
|
14
|
+
/** Optional native selection persists the setting; start/stop only observe. */
|
|
15
|
+
setEnabled?(enabled: boolean): Promise<void>;
|
|
16
|
+
start(changed: (status: BackupStatus) => void): Promise<BackupStatus>;
|
|
17
|
+
capture(): Promise<BackupStatus>;
|
|
18
|
+
stop(): Promise<void>;
|
|
19
|
+
}
|
|
20
|
+
/** Plugin owns this independently of the optional status-bar contribution. */
|
|
21
|
+
export declare class BackupController {
|
|
22
|
+
#private;
|
|
23
|
+
readonly service: BackupService;
|
|
24
|
+
readonly feedback: {
|
|
25
|
+
report(error: unknown): void;
|
|
26
|
+
recovered(): void;
|
|
27
|
+
};
|
|
28
|
+
constructor(service: BackupService, feedback: {
|
|
29
|
+
report(error: unknown): void;
|
|
30
|
+
recovered(): void;
|
|
31
|
+
});
|
|
32
|
+
subscribe(listener: (status: BackupStatus) => void): () => boolean;
|
|
33
|
+
start(): Promise<void>;
|
|
34
|
+
/** Reattach after a cancelled leave without consuming the retained worker. */
|
|
35
|
+
resume(): Promise<void>;
|
|
36
|
+
refresh(): Promise<void>;
|
|
37
|
+
pause(): Promise<void>;
|
|
38
|
+
close(): Promise<void>;
|
|
39
|
+
}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/** Plugin owns this independently of the optional status-bar contribution. */
|
|
2
|
+
export class BackupController {
|
|
3
|
+
#state = { phase: "saving", checkpoint: null, error: null };
|
|
4
|
+
#listeners = new Set();
|
|
5
|
+
#closed = false;
|
|
6
|
+
#running = false;
|
|
7
|
+
#attempted = false;
|
|
8
|
+
#epoch = 0;
|
|
9
|
+
#starting;
|
|
10
|
+
service;
|
|
11
|
+
feedback;
|
|
12
|
+
constructor(service, feedback) {
|
|
13
|
+
this.service = service;
|
|
14
|
+
this.feedback = feedback;
|
|
15
|
+
}
|
|
16
|
+
subscribe(listener) {
|
|
17
|
+
this.#listeners.add(listener);
|
|
18
|
+
listener(this.#state);
|
|
19
|
+
return () => this.#listeners.delete(listener);
|
|
20
|
+
}
|
|
21
|
+
#set(status) {
|
|
22
|
+
if (this.#closed)
|
|
23
|
+
return;
|
|
24
|
+
this.#state = status;
|
|
25
|
+
if (status.phase === "failed")
|
|
26
|
+
this.feedback.report(new Error(status.error ?? "Vault backup failed"));
|
|
27
|
+
else if (status.phase === "ready")
|
|
28
|
+
this.feedback.recovered();
|
|
29
|
+
for (const listener of this.#listeners)
|
|
30
|
+
listener(status);
|
|
31
|
+
}
|
|
32
|
+
async start() {
|
|
33
|
+
await this.#start(true);
|
|
34
|
+
}
|
|
35
|
+
/** Reattach after a cancelled leave without consuming the retained worker. */
|
|
36
|
+
async resume() {
|
|
37
|
+
await this.#start(false);
|
|
38
|
+
}
|
|
39
|
+
async #start(drain) {
|
|
40
|
+
if (this.#running || this.#closed)
|
|
41
|
+
return;
|
|
42
|
+
// A lost response can leave a native owner. Drain it before admitting a
|
|
43
|
+
// replacement rather than treating an unknown stop as successful.
|
|
44
|
+
if (drain && this.#attempted)
|
|
45
|
+
await this.pause();
|
|
46
|
+
if (this.#closed)
|
|
47
|
+
return;
|
|
48
|
+
this.#running = true;
|
|
49
|
+
this.#attempted = true;
|
|
50
|
+
const epoch = ++this.#epoch;
|
|
51
|
+
try {
|
|
52
|
+
let events = 0;
|
|
53
|
+
const opening = this.service.start((state) => {
|
|
54
|
+
if (epoch !== this.#epoch)
|
|
55
|
+
return;
|
|
56
|
+
events++;
|
|
57
|
+
this.#set(state);
|
|
58
|
+
});
|
|
59
|
+
this.#starting = opening;
|
|
60
|
+
const initial = await opening;
|
|
61
|
+
if (this.#starting === opening)
|
|
62
|
+
this.#starting = undefined;
|
|
63
|
+
if (events === 0 && epoch === this.#epoch)
|
|
64
|
+
this.#set(initial);
|
|
65
|
+
}
|
|
66
|
+
catch (error) {
|
|
67
|
+
this.#starting = undefined;
|
|
68
|
+
if (epoch !== this.#epoch)
|
|
69
|
+
return;
|
|
70
|
+
this.#running = false;
|
|
71
|
+
this.#set({
|
|
72
|
+
...this.#state,
|
|
73
|
+
phase: "failed",
|
|
74
|
+
error: error instanceof Error ? error.message : String(error),
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
async refresh() {
|
|
79
|
+
if (this.#closed)
|
|
80
|
+
return;
|
|
81
|
+
this.#set({ ...this.#state, phase: "saving", error: null });
|
|
82
|
+
if (!this.#running) {
|
|
83
|
+
await this.start();
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
const epoch = this.#epoch;
|
|
87
|
+
try {
|
|
88
|
+
const result = await this.service.capture();
|
|
89
|
+
if (epoch === this.#epoch)
|
|
90
|
+
this.#set(result);
|
|
91
|
+
}
|
|
92
|
+
catch (error) {
|
|
93
|
+
if (epoch !== this.#epoch)
|
|
94
|
+
return;
|
|
95
|
+
this.#set({
|
|
96
|
+
...this.#state,
|
|
97
|
+
phase: "failed",
|
|
98
|
+
error: error instanceof Error ? error.message : String(error),
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
async pause() {
|
|
103
|
+
this.#epoch++;
|
|
104
|
+
this.#running = false;
|
|
105
|
+
try {
|
|
106
|
+
// A startup already admitted by the host must finish before its stop;
|
|
107
|
+
// otherwise a late start could outlive the close barrier.
|
|
108
|
+
if (this.#starting)
|
|
109
|
+
await Promise.allSettled([this.#starting]);
|
|
110
|
+
if (this.#attempted)
|
|
111
|
+
await this.service.stop();
|
|
112
|
+
}
|
|
113
|
+
catch (error) {
|
|
114
|
+
this.#set({
|
|
115
|
+
...this.#state,
|
|
116
|
+
phase: "failed",
|
|
117
|
+
error: error instanceof Error ? error.message : String(error),
|
|
118
|
+
});
|
|
119
|
+
throw error;
|
|
120
|
+
}
|
|
121
|
+
this.#attempted = false;
|
|
122
|
+
this.#set({ ...this.#state, phase: "closed", error: null });
|
|
123
|
+
}
|
|
124
|
+
async close() {
|
|
125
|
+
await this.pause();
|
|
126
|
+
this.#closed = true;
|
|
127
|
+
this.#listeners.clear();
|
|
128
|
+
}
|
|
129
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { BlameRange } from "./blame-model.js";
|
|
2
|
+
export declare const BLAME_UNAVAILABLE = "Blame is not available on this server yet. Source remains available.";
|
|
3
|
+
export declare function sourceLines(contents: string): string[];
|
|
4
|
+
/** Matches the recorded-file admission of the shared JJ annotation adapter. */
|
|
5
|
+
export declare function blameSizeReason(contents: string): string | undefined;
|
|
6
|
+
export interface BlameChunk {
|
|
7
|
+
start: number;
|
|
8
|
+
end: number;
|
|
9
|
+
commitId?: string;
|
|
10
|
+
continued: boolean;
|
|
11
|
+
}
|
|
12
|
+
/** Split long groups into bounded render chunks, retaining continuation attribution. */
|
|
13
|
+
export declare function blameChunks(lineCount: number, ranges: readonly BlameRange[]): BlameChunk[];
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
export const BLAME_UNAVAILABLE = "Blame is not available on this server yet. Source remains available.";
|
|
2
|
+
export function sourceLines(contents) {
|
|
3
|
+
if (!contents)
|
|
4
|
+
return [];
|
|
5
|
+
const lines = contents.split("\n");
|
|
6
|
+
if (lines.at(-1) === "")
|
|
7
|
+
lines.pop();
|
|
8
|
+
return lines;
|
|
9
|
+
}
|
|
10
|
+
/** Matches the recorded-file admission of the shared JJ annotation adapter. */
|
|
11
|
+
export function blameSizeReason(contents) {
|
|
12
|
+
return new TextEncoder().encode(contents).byteLength > 256 * 1024 ||
|
|
13
|
+
sourceLines(contents).length > 32_768
|
|
14
|
+
? "Blame is unavailable for files larger than 256 KiB or 32,768 lines."
|
|
15
|
+
: undefined;
|
|
16
|
+
}
|
|
17
|
+
/** Split long groups into bounded render chunks, retaining continuation attribution. */
|
|
18
|
+
export function blameChunks(lineCount, ranges) {
|
|
19
|
+
const groups = [];
|
|
20
|
+
let cursor = 1;
|
|
21
|
+
for (const native of ranges) {
|
|
22
|
+
const range = {
|
|
23
|
+
start: native.start,
|
|
24
|
+
end: native.end,
|
|
25
|
+
commitId: native.commit_id,
|
|
26
|
+
};
|
|
27
|
+
if (range.start > cursor)
|
|
28
|
+
groups.push({ start: cursor, end: range.start });
|
|
29
|
+
const previous = groups.at(-1);
|
|
30
|
+
if (previous &&
|
|
31
|
+
previous.commitId === range.commitId &&
|
|
32
|
+
previous.end === range.start)
|
|
33
|
+
previous.end = range.end;
|
|
34
|
+
else
|
|
35
|
+
groups.push({ ...range });
|
|
36
|
+
cursor = range.end;
|
|
37
|
+
}
|
|
38
|
+
if (cursor <= lineCount)
|
|
39
|
+
groups.push({ start: cursor, end: lineCount + 1 });
|
|
40
|
+
return groups.flatMap((group) => {
|
|
41
|
+
const chunks = [];
|
|
42
|
+
for (let start = group.start; start < group.end; start += 32)
|
|
43
|
+
chunks.push({
|
|
44
|
+
...group,
|
|
45
|
+
start,
|
|
46
|
+
end: Math.min(start + 32, group.end),
|
|
47
|
+
continued: start !== group.start,
|
|
48
|
+
});
|
|
49
|
+
return chunks;
|
|
50
|
+
});
|
|
51
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { HistoryReader } from "./history-reader.js";
|
|
2
|
+
import { type BlameSelection, type BlameState } from "./blame-model.js";
|
|
3
|
+
/** An explicit main-panel file selection owns its pin, worker progress and drain. */
|
|
4
|
+
export declare class BlameController {
|
|
5
|
+
#private;
|
|
6
|
+
readonly reader: HistoryReader;
|
|
7
|
+
readonly feedback: {
|
|
8
|
+
report(error: unknown): void;
|
|
9
|
+
recovered(): void;
|
|
10
|
+
};
|
|
11
|
+
constructor(reader: HistoryReader, feedback: BlameController["feedback"]);
|
|
12
|
+
get state(): BlameState;
|
|
13
|
+
subscribe(listener: (state: BlameState) => void): () => void;
|
|
14
|
+
open(selection: BlameSelection): Promise<void>;
|
|
15
|
+
refresh(): Promise<void>;
|
|
16
|
+
close(): Promise<void>;
|
|
17
|
+
}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { HistoryLifetime } from "./history-lifetime.js";
|
|
2
|
+
import { check, prepared } from "./history-selection.js";
|
|
3
|
+
import { sourceLines, blameSizeReason } from "./blame-chunks.js";
|
|
4
|
+
import { validateBlame, } from "./blame-model.js";
|
|
5
|
+
/** An explicit main-panel file selection owns its pin, worker progress and drain. */
|
|
6
|
+
export class BlameController {
|
|
7
|
+
#state = { status: "loading", busy: false };
|
|
8
|
+
#listeners = new Set();
|
|
9
|
+
#generation = 0;
|
|
10
|
+
#abort = new AbortController();
|
|
11
|
+
#handle;
|
|
12
|
+
#closed = false;
|
|
13
|
+
#closing;
|
|
14
|
+
#lifetime;
|
|
15
|
+
reader;
|
|
16
|
+
feedback;
|
|
17
|
+
constructor(reader, feedback) {
|
|
18
|
+
this.reader = reader;
|
|
19
|
+
this.feedback = feedback;
|
|
20
|
+
this.#lifetime = new HistoryLifetime(reader);
|
|
21
|
+
}
|
|
22
|
+
get state() {
|
|
23
|
+
return this.#state;
|
|
24
|
+
}
|
|
25
|
+
subscribe(listener) {
|
|
26
|
+
this.#listeners.add(listener);
|
|
27
|
+
listener(this.#state);
|
|
28
|
+
return () => {
|
|
29
|
+
this.#listeners.delete(listener);
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
#set(patch) {
|
|
33
|
+
if (this.#closed)
|
|
34
|
+
return;
|
|
35
|
+
this.#state = { ...this.#state, ...patch };
|
|
36
|
+
for (const listener of this.#listeners)
|
|
37
|
+
listener(this.#state);
|
|
38
|
+
}
|
|
39
|
+
#valid(generation) {
|
|
40
|
+
return !this.#closed && generation === this.#generation;
|
|
41
|
+
}
|
|
42
|
+
open(selection) {
|
|
43
|
+
if (this.#closed)
|
|
44
|
+
return Promise.resolve();
|
|
45
|
+
const generation = ++this.#generation;
|
|
46
|
+
this.#abort.abort();
|
|
47
|
+
const abort = (this.#abort = new AbortController());
|
|
48
|
+
const prior = this.#handle;
|
|
49
|
+
this.#handle = undefined;
|
|
50
|
+
this.#set({
|
|
51
|
+
selection,
|
|
52
|
+
contents: undefined,
|
|
53
|
+
progress: undefined,
|
|
54
|
+
busy: true,
|
|
55
|
+
status: "loading",
|
|
56
|
+
});
|
|
57
|
+
return this.#lifetime.run(async () => {
|
|
58
|
+
try {
|
|
59
|
+
if (prior)
|
|
60
|
+
await this.#lifetime.closeHandle(prior);
|
|
61
|
+
if (!this.#valid(generation))
|
|
62
|
+
return;
|
|
63
|
+
if (!this.reader.blame)
|
|
64
|
+
throw new Error("Blame is unavailable for this repository reader.");
|
|
65
|
+
const handle = await this.reader.open(selection.operation);
|
|
66
|
+
this.#lifetime.handles.add(handle);
|
|
67
|
+
if (!this.#valid(generation)) {
|
|
68
|
+
await this.#lifetime.closeHandle(handle);
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
this.#handle = handle;
|
|
72
|
+
const snapshot = await prepared(this.reader, handle, abort.signal);
|
|
73
|
+
check(snapshot.operation === selection.operation);
|
|
74
|
+
const cursors = new Set();
|
|
75
|
+
let continuation = null;
|
|
76
|
+
let file;
|
|
77
|
+
for (let page = 0; page < 128 && this.#valid(generation); page++) {
|
|
78
|
+
const reply = await this.reader.blame(handle, {
|
|
79
|
+
commit: selection.commit,
|
|
80
|
+
path: selection.path,
|
|
81
|
+
continuation,
|
|
82
|
+
});
|
|
83
|
+
if (!this.#valid(generation))
|
|
84
|
+
return;
|
|
85
|
+
const progress = validateBlame(reply, selection);
|
|
86
|
+
check(progress.repository === snapshot.repository);
|
|
87
|
+
if (!file) {
|
|
88
|
+
file = progress.file_id;
|
|
89
|
+
const response = await this.reader.read(handle, {
|
|
90
|
+
kind: "file_at",
|
|
91
|
+
query: { commit: selection.commit, path: selection.path, file },
|
|
92
|
+
});
|
|
93
|
+
if (!this.#valid(generation))
|
|
94
|
+
return;
|
|
95
|
+
check(response.kind === "file_at");
|
|
96
|
+
const contents = response.data.text;
|
|
97
|
+
if (response.data.binary ||
|
|
98
|
+
response.data.too_large ||
|
|
99
|
+
typeof contents !== "string")
|
|
100
|
+
throw new Error("Blame requires a bounded recorded text file.");
|
|
101
|
+
const reason = blameSizeReason(contents);
|
|
102
|
+
if (reason)
|
|
103
|
+
throw new Error(reason);
|
|
104
|
+
check(sourceLines(contents).length === progress.line_count);
|
|
105
|
+
this.#set({ contents });
|
|
106
|
+
}
|
|
107
|
+
check(progress.file_id === file);
|
|
108
|
+
this.#set({ progress });
|
|
109
|
+
if (progress.complete) {
|
|
110
|
+
this.#set({ status: "ready" });
|
|
111
|
+
this.feedback.recovered();
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
check(progress.continuation && !cursors.has(progress.continuation));
|
|
115
|
+
continuation = progress.continuation;
|
|
116
|
+
cursors.add(continuation);
|
|
117
|
+
}
|
|
118
|
+
if (this.#valid(generation))
|
|
119
|
+
throw new Error("Blame exceeded its bounded progress window. Refresh to try again.");
|
|
120
|
+
}
|
|
121
|
+
catch (error) {
|
|
122
|
+
if (this.#valid(generation)) {
|
|
123
|
+
this.#set({ status: "failed" });
|
|
124
|
+
this.feedback.report(error);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
finally {
|
|
128
|
+
if (this.#valid(generation))
|
|
129
|
+
this.#set({ busy: false });
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
refresh() {
|
|
134
|
+
return this.#state.selection
|
|
135
|
+
? this.open(this.#state.selection)
|
|
136
|
+
: Promise.resolve();
|
|
137
|
+
}
|
|
138
|
+
close() {
|
|
139
|
+
this.#closed = true;
|
|
140
|
+
this.#generation++;
|
|
141
|
+
this.#abort.abort();
|
|
142
|
+
this.#listeners.clear();
|
|
143
|
+
return (this.#closing ??= this.#lifetime.drain().catch((error) => {
|
|
144
|
+
this.#closing = undefined;
|
|
145
|
+
throw error;
|
|
146
|
+
}));
|
|
147
|
+
}
|
|
148
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { BlamePage } from "@lapismd/jj-history";
|
|
2
|
+
export type { BlameCommit } from "@lapismd/jj-history";
|
|
3
|
+
export type BlameRange = {
|
|
4
|
+
start: number;
|
|
5
|
+
end: number;
|
|
6
|
+
commit_id: string;
|
|
7
|
+
};
|
|
8
|
+
export type BlameProgress = Omit<BlamePage, "line_count" | "ranges"> & {
|
|
9
|
+
line_count: number;
|
|
10
|
+
ranges: BlameRange[];
|
|
11
|
+
};
|
|
12
|
+
export type BlameSelection = {
|
|
13
|
+
operation: string;
|
|
14
|
+
commit: string;
|
|
15
|
+
path: string;
|
|
16
|
+
};
|
|
17
|
+
export type BlameState = {
|
|
18
|
+
selection?: BlameSelection;
|
|
19
|
+
contents?: string;
|
|
20
|
+
progress?: BlameProgress;
|
|
21
|
+
status: "loading" | "ready" | "failed";
|
|
22
|
+
busy: boolean;
|
|
23
|
+
};
|
|
24
|
+
/** Keep the copied presentation boundary exact even for injected host readers. */
|
|
25
|
+
export declare function validateBlame(page: BlamePage, selection: BlameSelection): BlameProgress;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { check } from "./history-selection.js";
|
|
2
|
+
/** Keep the copied presentation boundary exact even for injected host readers. */
|
|
3
|
+
export function validateBlame(page, selection) {
|
|
4
|
+
const line = (value) => {
|
|
5
|
+
check(typeof value === "bigint" || Number.isSafeInteger(value));
|
|
6
|
+
check(BigInt(value) >= 0n && BigInt(value) <= 32769n);
|
|
7
|
+
return Number(value);
|
|
8
|
+
};
|
|
9
|
+
const lineCount = line(page.line_count);
|
|
10
|
+
check(page.operation === selection.operation &&
|
|
11
|
+
page.commit === selection.commit &&
|
|
12
|
+
page.path === selection.path &&
|
|
13
|
+
lineCount <= 32_768 &&
|
|
14
|
+
page.complete === (page.continuation === null));
|
|
15
|
+
let end = 1;
|
|
16
|
+
const ranges = page.ranges.map((range) => ({
|
|
17
|
+
...range,
|
|
18
|
+
start: line(range.start),
|
|
19
|
+
end: line(range.end),
|
|
20
|
+
}));
|
|
21
|
+
for (const range of ranges) {
|
|
22
|
+
check(Number.isSafeInteger(range.start) &&
|
|
23
|
+
Number.isSafeInteger(range.end) &&
|
|
24
|
+
range.start >= end &&
|
|
25
|
+
range.end > range.start &&
|
|
26
|
+
range.end <= lineCount + 1 &&
|
|
27
|
+
page.commits[range.commit_id]?.id === range.commit_id);
|
|
28
|
+
end = range.end;
|
|
29
|
+
}
|
|
30
|
+
return { ...page, line_count: lineCount, ranges };
|
|
31
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
const key = "lapis.desktop.repository.blame.wrap";
|
|
2
|
+
/** A local display preference shared by blame files, independent of the vault. */
|
|
3
|
+
export function readBlameWrap() {
|
|
4
|
+
try {
|
|
5
|
+
return localStorage.getItem(key) !== "false";
|
|
6
|
+
}
|
|
7
|
+
catch {
|
|
8
|
+
return true;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
export function saveBlameWrap(wrap) {
|
|
12
|
+
try {
|
|
13
|
+
localStorage.setItem(key, String(wrap));
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
// Optional browser persistence must not prevent reading recorded source.
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { LocalGraphCommit } from "@lapismd/jj-history";
|
|
2
|
+
import type { TagListItem } from "@lapismd/design-core/shadcn/tag-list";
|
|
3
|
+
export declare function commitCardTags(commit?: LocalGraphCommit): TagListItem[];
|
|
4
|
+
export declare function commitCardSearch(id: string, commit?: LocalGraphCommit): string;
|