latticesql 4.2.3 → 4.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -4764,6 +4764,74 @@ declare class SQLiteAdapter implements StorageAdapter {
4764
4764
  withClient<T>(fn: (tx: TxClient) => Promise<T>): Promise<T>;
4765
4765
  }
4766
4766
 
4767
+ /**
4768
+ * SQLite adapter backed by the runtime's built-in `node:sqlite` `DatabaseSync`
4769
+ * (synchronous) instead of the `better-sqlite3` native addon. This exists so
4770
+ * Lattice can run under a runtime that ships `node:sqlite` but cannot load
4771
+ * native N-API addons (the desktop build). The surface is a 1:1 mirror of the
4772
+ * better-sqlite3 adapter — same StorageAdapter contract, same SQL — with three
4773
+ * substitutions where the two SQLite bindings differ:
4774
+ *
4775
+ * 1. pragmas are issued via `exec()` (no `.pragma()` helper);
4776
+ * 2. the `data_version` half of changeProbe is read with a plain
4777
+ * `PRAGMA data_version` statement (no `{ simple: true }` option);
4778
+ * 3. BLOB columns read back as `Uint8Array` rather than `Buffer`. Lattice's
4779
+ * own file storage is disk-based (content-addressed blobs), so the core
4780
+ * never round-trips file bytes through a BLOB column; a user-defined
4781
+ * `blob` column consumed specifically as a Node `Buffer` is the only place
4782
+ * the difference is observable. `Buffer` is itself a `Uint8Array`, so byte
4783
+ * access is identical; only Buffer-only methods would differ.
4784
+ */
4785
+ interface NodeSqliteRunResult {
4786
+ changes: number | bigint;
4787
+ lastInsertRowid: number | bigint;
4788
+ }
4789
+ interface NodeStatementSync {
4790
+ run(...params: unknown[]): NodeSqliteRunResult;
4791
+ get(...params: unknown[]): Row | undefined;
4792
+ all(...params: unknown[]): Row[];
4793
+ }
4794
+ interface NodeDatabaseSync {
4795
+ exec(sql: string): void;
4796
+ prepare(sql: string): NodeStatementSync;
4797
+ close(): void;
4798
+ }
4799
+ declare class DenoSqliteAdapter implements StorageAdapter {
4800
+ readonly dialect: "sqlite";
4801
+ private _db;
4802
+ private readonly _path;
4803
+ private readonly _wal;
4804
+ private readonly _busyTimeout;
4805
+ constructor(path: string, options?: {
4806
+ wal?: boolean;
4807
+ busyTimeout?: number;
4808
+ });
4809
+ get db(): NodeDatabaseSync;
4810
+ open(): void;
4811
+ close(): void;
4812
+ run(sql: string, params?: unknown[]): void;
4813
+ get(sql: string, params?: unknown[]): Row | undefined;
4814
+ all(sql: string, params?: unknown[]): Row[];
4815
+ prepare(sql: string): PreparedStatement;
4816
+ introspectColumns(table: string): string[];
4817
+ /** Mirror of SQLiteAdapter.addColumn — SQLite ALTER quirks are binding-agnostic. */
4818
+ addColumn(table: string, column: string, typeSpec: string): void;
4819
+ /**
4820
+ * O(1) watch-loop change-probe — same composition as SQLiteAdapter, but
4821
+ * `data_version` is read with a plain prepared statement because node:sqlite
4822
+ * has no `.pragma(name, { simple: true })` scalar helper.
4823
+ */
4824
+ changeProbe(): string;
4825
+ runAsync(sql: string, params?: unknown[]): Promise<void>;
4826
+ getAsync(sql: string, params?: unknown[]): Promise<Row | undefined>;
4827
+ allAsync(sql: string, params?: unknown[]): Promise<Row[]>;
4828
+ introspectColumnsAsync(table: string): Promise<string[]>;
4829
+ introspectAllColumns(tables: string[]): Promise<Map<string, Set<string>>>;
4830
+ addColumnAsync(table: string, column: string, typeSpec: string): Promise<void>;
4831
+ /** BEGIN/COMMIT around an awaited fn; ROLLBACK on throw. Mirror of SQLiteAdapter. */
4832
+ withClient<T>(fn: (tx: TxClient) => Promise<T>): Promise<T>;
4833
+ }
4834
+
4767
4835
  /**
4768
4836
  * Pluggable Postgres backend for Lattice.
4769
4837
  *
@@ -6707,6 +6775,13 @@ interface StartGuiServerOptions {
6707
6775
  * it overrides `selfUpdate`'s default factory.
6708
6776
  */
6709
6777
  updateServiceFactory?: (emit: (type: string, data: unknown) => void) => UpdateService;
6778
+ /**
6779
+ * Desktop shell only: open an external URL in the OS default browser. The
6780
+ * embedded desktop webview has no tabs, so `target="_blank"` links are routed
6781
+ * to `GET /api/desktop/open` which calls this. Omitted for the web/CLI GUI —
6782
+ * the route then 404s, so a browser-served GUI can never trigger an OS open.
6783
+ */
6784
+ desktopOpenExternal?: (url: string) => void;
6710
6785
  }
6711
6786
  interface GuiServerHandle {
6712
6787
  server: Server;
@@ -7117,4 +7192,4 @@ declare function dedupeAndDetectViews(plan: ProposedSchema, data: Record<string,
7117
7192
  views: DetectedView[];
7118
7193
  };
7119
7194
 
7120
- export { ALL_PROVENANCE_FIELDS, type AddWorkspaceOptions, type AdoptNativeOptions, type AdoptResult, type AggregateFunction, type AggregateHaving, type AggregateOptions, type AggregateResult, type AggregateSpec, type ApplyWriteResult, type AsOfCandidate, type AsOfColumnCandidate, type AsOfInputs, type AudienceRowCtx, type AuditEvent, type AutoUpdateResult, type BacklinkSignal, type BelongsToRelation, type BelongsToSource, type BenchmarkOptions, type BenchmarkReport, type BenchmarkScale, type BlobMetadata, BoundedReadError, type BuiltinTemplateName, CLOUD_SETTING_SYSTEM_PROMPT, CLOUD_SETTING_WORKSPACE_LOGO, CLOUD_SETTING_WORKSPACE_LOGO_ETAG, CONFIG_SUBDIR, type CatalogEntity, type CatalogRecord, type ChangeEntry, type ChangelogOptions, type ChunkedMigrationOptions, type ChunkedMigrationResult, type ChunkerFn, type ClassifyMatch, type CleanupOptions, type CleanupResult, type CloudProbeResult, type CloudS3Secret, ComputedColumnCycleError, type ComputedColumnSpec, type CountOptions, type CrawlOptions, type CrawlResult, type CustomSignal, type CustomSource, DEFAULT_ENTRY_TYPES, DEFAULT_MAX_NODES, DEFAULT_TYPE_ALIASES, type DetectedView, type DiagnoseOptions, type DiscoveredTable, EMBEDDINGS_TABLE, EmbeddingDimensionMismatchError, type EmbeddingRefreshResult, EmbeddingScanTooLargeError, type EmbeddingsConfig, type EnrichOptions, type EnrichResult, type EnrichedSource, type EnrichmentLookup, type EntityContextDefinition, type EntityContextManifestEntry, type EntityFileManifestInfo, type EntityFileSource, type EntityFileSpec, type EntityMatch, type EntityProfileField, type EntityProfileSection, type EntityProfileTemplate, type EntityRenderSpec, type EntityRenderTemplate, type EntitySectionPerRow, type EntitySectionsTemplate, type EntityTableColumn, type EntityTableTemplate, type EvalQuery, type EvalRegression, type ExistingTable, type ExtensionAvailability, type ExtractEdgesSpec, type ExtractedObject, FileSourceKeyStore, type FileSourceKeyStoreOptions, type FilesRow, type Filter, type FilterAnd, type FilterExpr, type FilterOp, type FilterOr, FoldCache, type FtsConfig, type FtsGroup, type FtsHit, type FtsOptions, type FtsResult, type GraphBoostOptions, type GraphBoostResult, type GraphEdge, type GraphNode, type GraphTraversalResult, type GuiServerHandle, type HasManyRelation, type HasManySource, type HealthIssueKind, type HealthSeverity, type HybridScoreBreakdown, type HybridSearchOptions, type HybridSearchResult, type ImportMode, type ImportProgress, InMemorySourceKeyStore, InMemoryStateStore, type InferredColumn, type InferredDimension, type InferredEntity, type InferredLinkage, type InferredType, type InitOptions, LEGACY_MEMBER_GROUP, LOCAL_DB_RELPATH, type LatencyStats, Lattice, type LatticeConfig, type LatticeConfigInput, type LatticeEntityDef, type LatticeEntityRenderSpec, type LatticeFieldDef, type LatticeFieldType, type LatticeManifest, type LatticeOptions, type LinkOptions, type LlmClient, type LlmMessage, MAX_TRAVERSAL_DEPTH, type ManyToManySource, type MarkdownTableColumn, type MaterializeCtx, type MaterializeOptions, type MaterializeResult, type MaterializedRollupSpec, type MigrateResult, type Migration, type MigrationCheckpoint, type MigrationOptions, type MigrationProgress, type MigrationResult, type MigrationStatus, type MultiTableDefinition, NATIVE_ENTITY_DEFS, NATIVE_ENTITY_NAMES, NATIVE_REGISTRY_TABLE, type Observation, type OrderBySpec, type OrganizeOptions, type OrganizeResult, type OrganizedCreation, type OrganizedLink, type ParseError, type ParseResult, type ParsedConfig, type PdfOptions, type PdfSenderInput, type PerQueryEval, type PkLookup, PostgresAdapter, type PostgresAdapterOptions, type PreparedStatement, type PrimaryKey, ProgressThrottle, type ProposedSchema, type ProvenanceConfig, type ProvenanceField, ProvenanceImmutableError, type QueryOptions, type QueryPageOptions, type QueryPageResult, type QueryProjection, READ_ONLY_HEADER, ROOT_DIRNAME, type RankingOptions, type ReadOnlyHeaderOptions, type RecencySignal, type ReconcileOptions, type ReconcileResult, type RefKind, type RefProvider, type ReferenceMetadata, ReferenceUnavailableError, type RefreshEmbeddingsOptions, type Relation, type RelevanceLabel, type RemoteBlobStore, type RenderHooks, type RenderOptions, type RenderProgress, type RenderProgressCallback, type RenderProgressKind, type RenderResult, type RenderSpec, type ReportConfig, type ReportResult, type ReportSection, type ReportSectionResult, type RerankCandidate, type RerankScore, type RerankerFn, type ResolveOptions, type RetrievalEvalOptions, type RetrievalEvalSummary, type RetrievalHealthIssue, type RetrievalHealthReport, type RetrievalHealthSpec, type RetrievalSlo, type Retriever, type RetryOptions, type ReverseSeedDetection, type ReverseSeedResult, type ReverseSeedTableResult, type ReverseSyncError, type ReverseSyncResult, type ReverseSyncUpdate, type RewardScores, type RewardSignal, type RollupFunction, type Row, type RowVisibilityDefault, type S3Config, type S3StoreConfig, S3UnavailableError, S3_SECRET_TABLE, SQLiteAdapter, type SchemaEntity, type SchemaMatch, type SearchOptions, type SearchResult, type SecurityOptions, type SeedConfig, type SeedLinkSpec, SeedReconciliationError, type SeedResult, type SelfSource, type SemanticChunkerOptions, type SessionEntry, type SessionParseOptions, type SessionWriteEntry, type SessionWriteOp, type SessionWriteParseResult, type SloViolation, type SourceHandle, type SourceKeyStore, type SourceMetadata, type SourceQueryOptions, SourceShreddedError, type StartGuiServerOptions, type StopFn, type StorageAdapter, type SyncResult, TRUST_COLUMNS, type TableDefinition, type TableHealth, type TablePolicy, type TemplateRenderSpec, type TextChunk, type TraversalDirection, type TraversalNode, type TraversalOptions, type TrustConfig, type TrustState, type TurnParams, type TurnResult, type UnresolvedLink, type UpsertByNaturalKeyOptions, type UserIdentity, type UserPreferences, type VectorHit, type Viewer, type VisionOptions, type VisionSenderInput, WORKSPACES_SUBDIR, type WatchOptions, type WorkspacePaths, type WorkspaceRecord, type WorkspaceRegistry, type WriteHook, type WriteHookContext, type WritebackDefinition, type WritebackStateStore, type WritebackValidationResult, activeWorkspaceLabel, addEdge, addEdges, addWorkspace, adoptNativeEntities, allComputedDeps, analyticsEnabled, applyChunkedMigration, applyReranker, applyTokenBudget, applyWriteEntry, archiveLocalSqlite, assertSafeUrl, attachBlob, audiencePredicate, audienceViewSql, autoFtsColumns, autoUpdate, backfillOwnership, backlinkBoost, benchmarkRetrieval, buildVectorIndex, canManageRoles, checkSlos, chunkText, classifyLinks, cloudRlsInstalled, computeColumns, computedColumnDdl, computedColumnOrder, concatRowText, configDir, contentHash, cosineSimilarity, crawlUrl, createReadOnlyHeader, createS3Store, createSQLiteStateStore, decrypt, dedupeAndDetectViews, defaultWorkspaceYaml, deleteDbCredential, deleteToken, deriveCanonicalContexts, deriveKey, describeImage, describePdf, detectAsOf, detectAsOfCandidates, detectAsOfColumns, detectRetrievalRegressions, diagnoseRetrieval, discoverCloudTables, dropVectorIndex, enableAudienceView, enableChangelogRls, enableRlsForTable, encrypt, enrichKnowledge, ensureCheckpointTable, ensureEdgesTable, ensureEmbeddingsTable, ensureFtsIndex, ensureLatticeRoot, entityFileNames, estimateTokens, evaluateRetrieval, excelToRecords, extractEdgesFromColumn, extractObjects, filePresignSql, findLatticeRoot, fixSchemaConflicts, foldEntity, formatHealthReport, frontmatter, ftsTableName, fullTextSearch, generateEntryId, generateMemberPassword, generateWriteEntryId, getActiveWorkspace, getCloudSetting, getDbCredential, getMigrationCheckpoint, getOrCreateMasterKey, getTablePolicy, getWorkspace, grantPresignerToMemberGroup, graphAdjacencyBoost, hasFilePresigner, hasFtsIndex, hasVectorIndex, hashFile, hybridSearch, importLegacyUserConfig, inferFieldType, inferSchema, installCloudRls, installCloudSettings, installFilePresigner, isEncrypted, isNativeEntity, isPostgresUrl, isPrivateIp, isRetryableDbError, isRowAudience, latencyStats, listDbCredentials, listMigrationCheckpoints, listNativeBindings, listTokens, listWorkspaces, loadColumnPolicy, manifestPath, markdownTable, matchSchemaToExisting, materializeImport, memberGroupFor, memberRoleName, migrateLatticeData, neighbors, normalizeName, observationVisible, observationsFromChange, openTargetLatticeForMigration, openUnderSource, organizeSource, parseCellDate, parseConfigFile, parseConfigString, parseMarkdownEntries, parseMatches, parseObjects, parseSessionMD, parseSessionWrites, percentile, probeCloud, provenanceColumns, providerForUrl, provisionMemberRole, rankingBoost, readIdentity, readManifest, readPreferences, readRegistry, readToken, recencyBoost, referenceLocalFile, referenceUrl, refreshEmbeddings, regenerateAudienceViewFromDb, registerNativeEntities, registryPath, removeEdge, removeEmbedding, renameEntities, resolveActiveS3Config, resolveLatticeRoot, resolveProvenanceFields, resolveSource, resolveTrustDefault, resolveWorkspacePaths, resumeMigration, revertMigration, revokeMemberRole, rewardBoost, rollupColumnDdl, rootConfigDir, s3Key, saveDbCredential, saveDbCredentialForTeam, sealUnderSource, searchByEmbedding, searchVectorIndex, secureCloud, seedColumnPolicyFromYaml, semanticChunker, setActiveWorkspace, setCloudS3Secret, setCloudSetting, setColumnAudience, setRowVisibility, setTableDefaultVisibility, setTableNeverShare, shredSource, slugify, sourceRecords, startGuiServer, storeEmbedding, summarizeText, tableNeedsAudienceView, toSafeDirName, traverse, truncate, validateEntryId, vectorIndexAvailable, vectorIndexName, withRetry, workspaceBlobsDir, workspaceConfigPath, workspaceContextDir, workspaceDataDir, workspaceDbPath, workspaceDir, workspacesDir, writeIdentity, writeManifest, writePreferences, writeRegistry, writeToken };
7195
+ export { ALL_PROVENANCE_FIELDS, type AddWorkspaceOptions, type AdoptNativeOptions, type AdoptResult, type AggregateFunction, type AggregateHaving, type AggregateOptions, type AggregateResult, type AggregateSpec, type ApplyWriteResult, type AsOfCandidate, type AsOfColumnCandidate, type AsOfInputs, type AudienceRowCtx, type AuditEvent, type AutoUpdateResult, type BacklinkSignal, type BelongsToRelation, type BelongsToSource, type BenchmarkOptions, type BenchmarkReport, type BenchmarkScale, type BlobMetadata, BoundedReadError, type BuiltinTemplateName, CLOUD_SETTING_SYSTEM_PROMPT, CLOUD_SETTING_WORKSPACE_LOGO, CLOUD_SETTING_WORKSPACE_LOGO_ETAG, CONFIG_SUBDIR, type CatalogEntity, type CatalogRecord, type ChangeEntry, type ChangelogOptions, type ChunkedMigrationOptions, type ChunkedMigrationResult, type ChunkerFn, type ClassifyMatch, type CleanupOptions, type CleanupResult, type CloudProbeResult, type CloudS3Secret, ComputedColumnCycleError, type ComputedColumnSpec, type CountOptions, type CrawlOptions, type CrawlResult, type CustomSignal, type CustomSource, DEFAULT_ENTRY_TYPES, DEFAULT_MAX_NODES, DEFAULT_TYPE_ALIASES, DenoSqliteAdapter, type DetectedView, type DiagnoseOptions, type DiscoveredTable, EMBEDDINGS_TABLE, EmbeddingDimensionMismatchError, type EmbeddingRefreshResult, EmbeddingScanTooLargeError, type EmbeddingsConfig, type EnrichOptions, type EnrichResult, type EnrichedSource, type EnrichmentLookup, type EntityContextDefinition, type EntityContextManifestEntry, type EntityFileManifestInfo, type EntityFileSource, type EntityFileSpec, type EntityMatch, type EntityProfileField, type EntityProfileSection, type EntityProfileTemplate, type EntityRenderSpec, type EntityRenderTemplate, type EntitySectionPerRow, type EntitySectionsTemplate, type EntityTableColumn, type EntityTableTemplate, type EvalQuery, type EvalRegression, type ExistingTable, type ExtensionAvailability, type ExtractEdgesSpec, type ExtractedObject, FileSourceKeyStore, type FileSourceKeyStoreOptions, type FilesRow, type Filter, type FilterAnd, type FilterExpr, type FilterOp, type FilterOr, FoldCache, type FtsConfig, type FtsGroup, type FtsHit, type FtsOptions, type FtsResult, type GraphBoostOptions, type GraphBoostResult, type GraphEdge, type GraphNode, type GraphTraversalResult, type GuiServerHandle, type HasManyRelation, type HasManySource, type HealthIssueKind, type HealthSeverity, type HybridScoreBreakdown, type HybridSearchOptions, type HybridSearchResult, type ImportMode, type ImportProgress, InMemorySourceKeyStore, InMemoryStateStore, type InferredColumn, type InferredDimension, type InferredEntity, type InferredLinkage, type InferredType, type InitOptions, LEGACY_MEMBER_GROUP, LOCAL_DB_RELPATH, type LatencyStats, Lattice, type LatticeConfig, type LatticeConfigInput, type LatticeEntityDef, type LatticeEntityRenderSpec, type LatticeFieldDef, type LatticeFieldType, type LatticeManifest, type LatticeOptions, type LinkOptions, type LlmClient, type LlmMessage, MAX_TRAVERSAL_DEPTH, type ManyToManySource, type MarkdownTableColumn, type MaterializeCtx, type MaterializeOptions, type MaterializeResult, type MaterializedRollupSpec, type MigrateResult, type Migration, type MigrationCheckpoint, type MigrationOptions, type MigrationProgress, type MigrationResult, type MigrationStatus, type MultiTableDefinition, NATIVE_ENTITY_DEFS, NATIVE_ENTITY_NAMES, NATIVE_REGISTRY_TABLE, type Observation, type OrderBySpec, type OrganizeOptions, type OrganizeResult, type OrganizedCreation, type OrganizedLink, type ParseError, type ParseResult, type ParsedConfig, type PdfOptions, type PdfSenderInput, type PerQueryEval, type PkLookup, PostgresAdapter, type PostgresAdapterOptions, type PreparedStatement, type PrimaryKey, ProgressThrottle, type ProposedSchema, type ProvenanceConfig, type ProvenanceField, ProvenanceImmutableError, type QueryOptions, type QueryPageOptions, type QueryPageResult, type QueryProjection, READ_ONLY_HEADER, ROOT_DIRNAME, type RankingOptions, type ReadOnlyHeaderOptions, type RecencySignal, type ReconcileOptions, type ReconcileResult, type RefKind, type RefProvider, type ReferenceMetadata, ReferenceUnavailableError, type RefreshEmbeddingsOptions, type Relation, type RelevanceLabel, type RemoteBlobStore, type RenderHooks, type RenderOptions, type RenderProgress, type RenderProgressCallback, type RenderProgressKind, type RenderResult, type RenderSpec, type ReportConfig, type ReportResult, type ReportSection, type ReportSectionResult, type RerankCandidate, type RerankScore, type RerankerFn, type ResolveOptions, type RetrievalEvalOptions, type RetrievalEvalSummary, type RetrievalHealthIssue, type RetrievalHealthReport, type RetrievalHealthSpec, type RetrievalSlo, type Retriever, type RetryOptions, type ReverseSeedDetection, type ReverseSeedResult, type ReverseSeedTableResult, type ReverseSyncError, type ReverseSyncResult, type ReverseSyncUpdate, type RewardScores, type RewardSignal, type RollupFunction, type Row, type RowVisibilityDefault, type S3Config, type S3StoreConfig, S3UnavailableError, S3_SECRET_TABLE, SQLiteAdapter, type SchemaEntity, type SchemaMatch, type SearchOptions, type SearchResult, type SecurityOptions, type SeedConfig, type SeedLinkSpec, SeedReconciliationError, type SeedResult, type SelfSource, type SemanticChunkerOptions, type SessionEntry, type SessionParseOptions, type SessionWriteEntry, type SessionWriteOp, type SessionWriteParseResult, type SloViolation, type SourceHandle, type SourceKeyStore, type SourceMetadata, type SourceQueryOptions, SourceShreddedError, type StartGuiServerOptions, type StopFn, type StorageAdapter, type SyncResult, TRUST_COLUMNS, type TableDefinition, type TableHealth, type TablePolicy, type TemplateRenderSpec, type TextChunk, type TraversalDirection, type TraversalNode, type TraversalOptions, type TrustConfig, type TrustState, type TurnParams, type TurnResult, type UnresolvedLink, type UpsertByNaturalKeyOptions, type UserIdentity, type UserPreferences, type VectorHit, type Viewer, type VisionOptions, type VisionSenderInput, WORKSPACES_SUBDIR, type WatchOptions, type WorkspacePaths, type WorkspaceRecord, type WorkspaceRegistry, type WriteHook, type WriteHookContext, type WritebackDefinition, type WritebackStateStore, type WritebackValidationResult, activeWorkspaceLabel, addEdge, addEdges, addWorkspace, adoptNativeEntities, allComputedDeps, analyticsEnabled, applyChunkedMigration, applyReranker, applyTokenBudget, applyWriteEntry, archiveLocalSqlite, assertSafeUrl, attachBlob, audiencePredicate, audienceViewSql, autoFtsColumns, autoUpdate, backfillOwnership, backlinkBoost, benchmarkRetrieval, buildVectorIndex, canManageRoles, checkSlos, chunkText, classifyLinks, cloudRlsInstalled, computeColumns, computedColumnDdl, computedColumnOrder, concatRowText, configDir, contentHash, cosineSimilarity, crawlUrl, createReadOnlyHeader, createS3Store, createSQLiteStateStore, decrypt, dedupeAndDetectViews, defaultWorkspaceYaml, deleteDbCredential, deleteToken, deriveCanonicalContexts, deriveKey, describeImage, describePdf, detectAsOf, detectAsOfCandidates, detectAsOfColumns, detectRetrievalRegressions, diagnoseRetrieval, discoverCloudTables, dropVectorIndex, enableAudienceView, enableChangelogRls, enableRlsForTable, encrypt, enrichKnowledge, ensureCheckpointTable, ensureEdgesTable, ensureEmbeddingsTable, ensureFtsIndex, ensureLatticeRoot, entityFileNames, estimateTokens, evaluateRetrieval, excelToRecords, extractEdgesFromColumn, extractObjects, filePresignSql, findLatticeRoot, fixSchemaConflicts, foldEntity, formatHealthReport, frontmatter, ftsTableName, fullTextSearch, generateEntryId, generateMemberPassword, generateWriteEntryId, getActiveWorkspace, getCloudSetting, getDbCredential, getMigrationCheckpoint, getOrCreateMasterKey, getTablePolicy, getWorkspace, grantPresignerToMemberGroup, graphAdjacencyBoost, hasFilePresigner, hasFtsIndex, hasVectorIndex, hashFile, hybridSearch, importLegacyUserConfig, inferFieldType, inferSchema, installCloudRls, installCloudSettings, installFilePresigner, isEncrypted, isNativeEntity, isPostgresUrl, isPrivateIp, isRetryableDbError, isRowAudience, latencyStats, listDbCredentials, listMigrationCheckpoints, listNativeBindings, listTokens, listWorkspaces, loadColumnPolicy, manifestPath, markdownTable, matchSchemaToExisting, materializeImport, memberGroupFor, memberRoleName, migrateLatticeData, neighbors, normalizeName, observationVisible, observationsFromChange, openTargetLatticeForMigration, openUnderSource, organizeSource, parseCellDate, parseConfigFile, parseConfigString, parseMarkdownEntries, parseMatches, parseObjects, parseSessionMD, parseSessionWrites, percentile, probeCloud, provenanceColumns, providerForUrl, provisionMemberRole, rankingBoost, readIdentity, readManifest, readPreferences, readRegistry, readToken, recencyBoost, referenceLocalFile, referenceUrl, refreshEmbeddings, regenerateAudienceViewFromDb, registerNativeEntities, registryPath, removeEdge, removeEmbedding, renameEntities, resolveActiveS3Config, resolveLatticeRoot, resolveProvenanceFields, resolveSource, resolveTrustDefault, resolveWorkspacePaths, resumeMigration, revertMigration, revokeMemberRole, rewardBoost, rollupColumnDdl, rootConfigDir, s3Key, saveDbCredential, saveDbCredentialForTeam, sealUnderSource, searchByEmbedding, searchVectorIndex, secureCloud, seedColumnPolicyFromYaml, semanticChunker, setActiveWorkspace, setCloudS3Secret, setCloudSetting, setColumnAudience, setRowVisibility, setTableDefaultVisibility, setTableNeverShare, shredSource, slugify, sourceRecords, startGuiServer, storeEmbedding, summarizeText, tableNeedsAudienceView, toSafeDirName, traverse, truncate, validateEntryId, vectorIndexAvailable, vectorIndexName, withRetry, workspaceBlobsDir, workspaceConfigPath, workspaceContextDir, workspaceDataDir, workspaceDbPath, workspaceDir, workspacesDir, writeIdentity, writeManifest, writePreferences, writeRegistry, writeToken };
package/dist/index.js CHANGED
@@ -719,17 +719,179 @@ var init_sqlite = __esm({
719
719
  }
720
720
  });
721
721
 
722
+ // src/db/sqlite-deno.ts
723
+ import { createRequire as createRequire2 } from "module";
724
+ function runtimeRequire2() {
725
+ const importMetaUrl = import.meta.url;
726
+ return importMetaUrl ? createRequire2(importMetaUrl) : __require;
727
+ }
728
+ function loadNodeSqlite() {
729
+ if (_ctor2) return _ctor2;
730
+ const mod = runtimeRequire2()("node:sqlite");
731
+ if (!mod.DatabaseSync) {
732
+ throw new Error(
733
+ "node:sqlite is unavailable in this runtime \u2014 cannot open the Deno SQLite adapter"
734
+ );
735
+ }
736
+ _ctor2 = mod.DatabaseSync;
737
+ return _ctor2;
738
+ }
739
+ var _ctor2, DenoSqliteAdapter;
740
+ var init_sqlite_deno = __esm({
741
+ "src/db/sqlite-deno.ts"() {
742
+ "use strict";
743
+ _ctor2 = null;
744
+ DenoSqliteAdapter = class {
745
+ dialect = "sqlite";
746
+ _db = null;
747
+ _path;
748
+ _wal;
749
+ _busyTimeout;
750
+ constructor(path3, options) {
751
+ this._path = path3;
752
+ this._wal = options?.wal ?? true;
753
+ this._busyTimeout = options?.busyTimeout ?? 5e3;
754
+ }
755
+ get db() {
756
+ if (!this._db) throw new Error("DenoSqliteAdapter: not open \u2014 call open() first");
757
+ return this._db;
758
+ }
759
+ open() {
760
+ const Ctor = loadNodeSqlite();
761
+ this._db = new Ctor(this._path);
762
+ this._db.exec(`PRAGMA busy_timeout = ${this._busyTimeout.toString()}`);
763
+ if (this._wal) {
764
+ this._db.exec("PRAGMA journal_mode = WAL");
765
+ }
766
+ }
767
+ close() {
768
+ this._db?.close();
769
+ this._db = null;
770
+ }
771
+ run(sql, params = []) {
772
+ this.db.prepare(sql).run(...params);
773
+ }
774
+ get(sql, params = []) {
775
+ return this.db.prepare(sql).get(...params);
776
+ }
777
+ all(sql, params = []) {
778
+ return this.db.prepare(sql).all(...params);
779
+ }
780
+ prepare(sql) {
781
+ const stmt = this.db.prepare(sql);
782
+ return {
783
+ run: (...params) => {
784
+ const info = stmt.run(...params);
785
+ return {
786
+ changes: Number(info.changes),
787
+ lastInsertRowid: info.lastInsertRowid
788
+ };
789
+ },
790
+ get: (...params) => stmt.get(...params),
791
+ all: (...params) => stmt.all(...params)
792
+ };
793
+ }
794
+ introspectColumns(table) {
795
+ const rows = this.all(`PRAGMA table_info("${table}")`);
796
+ return rows.map((r6) => r6.name);
797
+ }
798
+ /** Mirror of SQLiteAdapter.addColumn — SQLite ALTER quirks are binding-agnostic. */
799
+ addColumn(table, column, typeSpec) {
800
+ const upperType = typeSpec.toUpperCase();
801
+ if (upperType.includes("PRIMARY KEY")) return;
802
+ const hasNonConstantDefault = upperType.includes("CURRENT_TIMESTAMP") || /DATETIME\s*\(\s*'NOW'\s*\)/i.test(typeSpec) || upperType.includes("RANDOM()");
803
+ if (hasNonConstantDefault) {
804
+ const safeType = typeSpec.replace(/\bNOT\s+NULL\b/gi, "").replace(/\bDEFAULT\s+\(?\s*CURRENT_TIMESTAMP\s*\)?/gi, "").replace(/\bDEFAULT\s+\(?\s*datetime\([^)]*\)\s*\)?/gi, "").replace(/\bDEFAULT\s+\(?\s*RANDOM\(\)\s*\)?/gi, "").replace(/\s+/g, " ").trim();
805
+ this.run(`ALTER TABLE "${table}" ADD COLUMN "${column}" ${safeType || "TEXT"}`);
806
+ this.run(`UPDATE "${table}" SET "${column}" = CURRENT_TIMESTAMP WHERE "${column}" IS NULL`);
807
+ } else {
808
+ this.run(`ALTER TABLE "${table}" ADD COLUMN "${column}" ${typeSpec}`);
809
+ }
810
+ }
811
+ /**
812
+ * O(1) watch-loop change-probe — same composition as SQLiteAdapter, but
813
+ * `data_version` is read with a plain prepared statement because node:sqlite
814
+ * has no `.pragma(name, { simple: true })` scalar helper.
815
+ */
816
+ changeProbe() {
817
+ const dataVersion = this.db.prepare("PRAGMA data_version").get().data_version;
818
+ const totalChanges = this.db.prepare("SELECT total_changes() AS n").get().n;
819
+ return `${String(dataVersion)}:${String(totalChanges)}`;
820
+ }
821
+ // ── Async surface (sync under the hood; mirrors SQLiteAdapter) ──────────
822
+ // eslint-disable-next-line @typescript-eslint/require-await
823
+ async runAsync(sql, params) {
824
+ this.run(sql, params);
825
+ }
826
+ // eslint-disable-next-line @typescript-eslint/require-await
827
+ async getAsync(sql, params) {
828
+ return this.get(sql, params);
829
+ }
830
+ // eslint-disable-next-line @typescript-eslint/require-await
831
+ async allAsync(sql, params) {
832
+ return this.all(sql, params);
833
+ }
834
+ // eslint-disable-next-line @typescript-eslint/require-await
835
+ async introspectColumnsAsync(table) {
836
+ return this.introspectColumns(table);
837
+ }
838
+ // eslint-disable-next-line @typescript-eslint/require-await
839
+ async introspectAllColumns(tables) {
840
+ const map = /* @__PURE__ */ new Map();
841
+ for (const t8 of tables) {
842
+ try {
843
+ const cols = this.introspectColumns(t8);
844
+ if (cols.length > 0) map.set(t8, new Set(cols));
845
+ } catch {
846
+ }
847
+ }
848
+ return map;
849
+ }
850
+ // eslint-disable-next-line @typescript-eslint/require-await
851
+ async addColumnAsync(table, column, typeSpec) {
852
+ this.addColumn(table, column, typeSpec);
853
+ }
854
+ /** BEGIN/COMMIT around an awaited fn; ROLLBACK on throw. Mirror of SQLiteAdapter. */
855
+ async withClient(fn) {
856
+ const dbRef = this.db;
857
+ const getSync = this.get.bind(this);
858
+ const allSync = this.all.bind(this);
859
+ const tx = {
860
+ run: (sql, params) => {
861
+ const info = dbRef.prepare(sql).run(...params ?? []);
862
+ return Promise.resolve({ changes: Number(info.changes) });
863
+ },
864
+ get: (sql, params) => Promise.resolve(getSync(sql, params ?? [])),
865
+ all: (sql, params) => Promise.resolve(allSync(sql, params ?? []))
866
+ };
867
+ this.run("BEGIN");
868
+ try {
869
+ const result = await fn(tx);
870
+ this.run("COMMIT");
871
+ return result;
872
+ } catch (err) {
873
+ try {
874
+ this.run("ROLLBACK");
875
+ } catch {
876
+ }
877
+ throw err;
878
+ }
879
+ }
880
+ };
881
+ }
882
+ });
883
+
722
884
  // src/db/postgres.ts
723
885
  import path2 from "path";
724
886
  import { fileURLToPath } from "url";
725
- import { createRequire as createRequire2 } from "module";
887
+ import { createRequire as createRequire3 } from "module";
726
888
  function moduleContext() {
727
889
  if (_moduleContext) return _moduleContext;
728
890
  const importMetaUrl = import.meta.url;
729
891
  if (importMetaUrl) {
730
892
  _moduleContext = {
731
893
  dir: path2.dirname(fileURLToPath(importMetaUrl)),
732
- require: createRequire2(importMetaUrl)
894
+ require: createRequire3(importMetaUrl)
733
895
  };
734
896
  } else {
735
897
  _moduleContext = { dir: __dirname, require: __require };
@@ -9937,6 +10099,9 @@ function buildAdapter(dbPath, options) {
9937
10099
  const adapterOpts = {};
9938
10100
  if (options.wal !== void 0) adapterOpts.wal = options.wal;
9939
10101
  if (options.busyTimeout !== void 0) adapterOpts.busyTimeout = options.busyTimeout;
10102
+ if (typeof globalThis.Deno !== "undefined") {
10103
+ return new DenoSqliteAdapter(sqlitePath, adapterOpts);
10104
+ }
9940
10105
  return new SQLiteAdapter(sqlitePath, adapterOpts);
9941
10106
  }
9942
10107
  function _resolveTemplateName(render) {
@@ -9956,6 +10121,7 @@ var init_lattice = __esm({
9956
10121
  init_render_cursor();
9957
10122
  init_adapter();
9958
10123
  init_sqlite();
10124
+ init_sqlite_deno();
9959
10125
  init_postgres();
9960
10126
  init_pk();
9961
10127
  init_manager();
@@ -52484,7 +52650,7 @@ var init_table_policy = __esm({
52484
52650
  });
52485
52651
 
52486
52652
  // src/ai/llm-client.ts
52487
- import { createRequire as createRequire3 } from "module";
52653
+ import { createRequire as createRequire4 } from "module";
52488
52654
  var DEFAULT_MODEL, CHEAPEST_MODEL;
52489
52655
  var init_llm_client = __esm({
52490
52656
  "src/ai/llm-client.ts"() {
@@ -52658,7 +52824,7 @@ var init_summarize = __esm({
52658
52824
  import { JSDOM } from "jsdom";
52659
52825
  import { Readability } from "@mozilla/readability";
52660
52826
  import { basename as basename5 } from "path";
52661
- import { createRequire as createRequire4 } from "module";
52827
+ import { createRequire as createRequire5 } from "module";
52662
52828
  async function crawlUrl(rawUrl, opts = {}) {
52663
52829
  const u2 = await assertSafeUrl(rawUrl, opts.allowPrivate ?? false);
52664
52830
  const fetchImpl = opts.fetcher ?? fetch;
@@ -52905,7 +53071,7 @@ async function renderViaPlaywright(url, timeoutMs, warnIfMissing = false) {
52905
53071
  let chromium;
52906
53072
  try {
52907
53073
  const importMetaUrl = import.meta.url;
52908
- const req = importMetaUrl ? createRequire4(importMetaUrl) : __require;
53074
+ const req = importMetaUrl ? createRequire5(importMetaUrl) : __require;
52909
53075
  const pw = req("playwright");
52910
53076
  chromium = pw.chromium;
52911
53077
  } catch {
@@ -54105,9 +54271,6 @@ async function resolveClaudeAuth(db) {
54105
54271
  const apiKey = await resolveAnthropicKey(db);
54106
54272
  return apiKey ? { apiKey } : null;
54107
54273
  }
54108
- async function hasClaudeAuth(db) {
54109
- return Boolean(await readMachineCredential(db, CLAUDE_OAUTH_KIND)) || await hasCredential(db, "anthropic", "ANTHROPIC_API_KEY");
54110
- }
54111
54274
  async function claudeAuthKind(db) {
54112
54275
  if (await readMachineCredential(db, CLAUDE_OAUTH_KIND)) return "oauth";
54113
54276
  if (await hasCredential(db, "anthropic", "ANTHROPIC_API_KEY")) return "key";
@@ -54135,7 +54298,6 @@ async function dispatchAssistantRoute(req, res, ctx) {
54135
54298
  hasAnthropicKey,
54136
54299
  hasOpenaiKey,
54137
54300
  hasElevenlabsKey,
54138
- hasClaudeAuth: await hasClaudeAuth(db),
54139
54301
  claudeAuthKind: await claudeAuthKind(db),
54140
54302
  hasVoiceKey: voice !== null,
54141
54303
  sttProvider: voice?.provider ?? null,
@@ -54263,13 +54425,17 @@ async function dispatchAssistantRoute(req, res, ctx) {
54263
54425
  const verifier = generatePkceVerifier();
54264
54426
  const state2 = generateState();
54265
54427
  const cookieOpts = "HttpOnly; Path=/; Max-Age=600; SameSite=Lax";
54266
- res.writeHead(302, {
54267
- Location: buildAuthorizeUrl(cfg, state2, pkceChallengeFor(verifier)),
54268
- "Set-Cookie": [
54269
- `lat_oauth_verifier=${verifier}; ${cookieOpts}`,
54270
- `lat_oauth_state=${state2}; ${cookieOpts}`
54271
- ]
54272
- });
54428
+ const setCookie = [
54429
+ `lat_oauth_verifier=${verifier}; ${cookieOpts}`,
54430
+ `lat_oauth_state=${state2}; ${cookieOpts}`
54431
+ ];
54432
+ const authorizeUrl = buildAuthorizeUrl(cfg, state2, pkceChallengeFor(verifier));
54433
+ if ((req.headers.accept ?? "").includes("application/json")) {
54434
+ res.writeHead(200, { "Content-Type": "application/json", "Set-Cookie": setCookie });
54435
+ res.end(JSON.stringify({ authorizeUrl }));
54436
+ return true;
54437
+ }
54438
+ res.writeHead(302, { Location: authorizeUrl, "Set-Cookie": setCookie });
54273
54439
  res.end();
54274
54440
  return true;
54275
54441
  }
@@ -57580,7 +57746,7 @@ var init_tools = __esm({
57580
57746
  });
57581
57747
 
57582
57748
  // src/gui/ai/chat.ts
57583
- import { createRequire as createRequire7 } from "module";
57749
+ import { createRequire as createRequire8 } from "module";
57584
57750
  function capToolResult(s2) {
57585
57751
  if (s2.length <= MAX_TOOL_RESULT_CHARS) return s2;
57586
57752
  if (s2.length > MAX_TOOL_RESULT_SKIP)
@@ -57813,7 +57979,7 @@ async function* runChat(opts) {
57813
57979
  function loadSdk() {
57814
57980
  if (!_sdk) {
57815
57981
  const importMetaUrl = import.meta.url;
57816
- const req = importMetaUrl ? createRequire7(importMetaUrl) : __require;
57982
+ const req = importMetaUrl ? createRequire8(importMetaUrl) : __require;
57817
57983
  try {
57818
57984
  _sdk = req("@anthropic-ai/sdk");
57819
57985
  } catch (err) {
@@ -58428,6 +58594,7 @@ async function autoUpdate(opts) {
58428
58594
 
58429
58595
  // src/index.ts
58430
58596
  init_sqlite();
58597
+ init_sqlite_deno();
58431
58598
  init_postgres();
58432
58599
  init_computed();
58433
58600
  init_governance();
@@ -59751,7 +59918,7 @@ function isBetter(next, prev) {
59751
59918
 
59752
59919
  // src/ai/vision.ts
59753
59920
  init_llm_client();
59754
- import { createRequire as createRequire5 } from "module";
59921
+ import { createRequire as createRequire6 } from "module";
59755
59922
  import { readFile as readFile5 } from "fs/promises";
59756
59923
  var DEFAULT_PROMPT = "Describe this image for a knowledge base in 2-4 factual sentences: what it shows, any visible text, and notable details. No preamble.";
59757
59924
  var MAX_DIM = 1568;
@@ -59813,7 +59980,7 @@ function buildVisionAnthropicConfig(auth) {
59813
59980
  function defaultSender(auth) {
59814
59981
  return async (input) => {
59815
59982
  const importMetaUrl = import.meta.url;
59816
- const req = importMetaUrl ? createRequire5(importMetaUrl) : __require;
59983
+ const req = importMetaUrl ? createRequire6(importMetaUrl) : __require;
59817
59984
  const sdk = req("@anthropic-ai/sdk");
59818
59985
  const Anthropic = sdk.Anthropic ?? sdk.default;
59819
59986
  if (!Anthropic) throw new Error("Could not resolve Anthropic from '@anthropic-ai/sdk'");
@@ -59840,7 +60007,7 @@ function defaultSender(auth) {
59840
60007
  function defaultPdfSender(auth) {
59841
60008
  return async (input) => {
59842
60009
  const importMetaUrl = import.meta.url;
59843
- const req = importMetaUrl ? createRequire5(importMetaUrl) : __require;
60010
+ const req = importMetaUrl ? createRequire6(importMetaUrl) : __require;
59844
60011
  const sdk = req("@anthropic-ai/sdk");
59845
60012
  const Anthropic = sdk.Anthropic ?? sdk.default;
59846
60013
  if (!Anthropic) throw new Error("Could not resolve Anthropic from '@anthropic-ai/sdk'");
@@ -60151,12 +60318,12 @@ init_postgres();
60151
60318
 
60152
60319
  // src/gui/realtime.ts
60153
60320
  import { EventEmitter } from "events";
60154
- import { createRequire as createRequire6 } from "module";
60321
+ import { createRequire as createRequire7 } from "module";
60155
60322
  var _pgModule = null;
60156
60323
  function loadPg() {
60157
60324
  if (_pgModule) return _pgModule;
60158
60325
  const importMetaUrl = import.meta.url;
60159
- const requireFromHere = importMetaUrl ? createRequire6(importMetaUrl) : (
60326
+ const requireFromHere = importMetaUrl ? createRequire7(importMetaUrl) : (
60160
60327
  // CJS fallback — Node provides `require` on every CJS module scope.
60161
60328
  __require
60162
60329
  );
@@ -63515,6 +63682,20 @@ var displayConfigJs = `
63515
63682
  });
63516
63683
  }
63517
63684
 
63685
+ // SINGLE SOURCE OF TRUTH for the assistant's Claude connection state, derived
63686
+ // from /api/assistant/config's claudeAuthKind (oauth | key | null). EVERY
63687
+ // place that shows "Connected with Claude" / opens the API-key panel / gates
63688
+ // on "the assistant has auth" MUST go through this \u2014 never re-derive from raw
63689
+ // fields, or the signals disagree (a stray "or hasAnthropicKey" once made
63690
+ // onboarding show "Connected with Claude" for an API-key-only setup while the
63691
+ // settings panel showed not-connected).
63692
+ // .oauth -> a Claude SUBSCRIPTION is connected ("Connected with Claude")
63693
+ // .any -> some working auth exists (subscription OR API key)
63694
+ function claudeAuth(cfg) {
63695
+ var kind = (cfg && cfg.claudeAuthKind) || null; // 'oauth' | 'key' | null
63696
+ return { kind: kind, oauth: kind === 'oauth', any: kind != null };
63697
+ }
63698
+
63518
63699
  // Disable a button + show an inline spinner for the duration of an
63519
63700
  // async action so a slow server round-trip can't be double-clicked.
63520
63701
  // The fn arg should return a Promise; the button is restored on settle.
@@ -64305,7 +64486,12 @@ var offlineEditQueueJs = ` // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u250
64305
64486
  if (eventStreamClosed) return;
64306
64487
  // Unexpected drop: show the disconnect on the pill and auto-reconnect with
64307
64488
  // backoff (the server replays state + render snapshot on reconnect).
64308
- setStatusPill('cloud', 'disconnected');
64489
+ // Preserve the KNOWN mode (cloudMode is the single source of truth, set
64490
+ // from the server's realtime-state message) \u2014 never hardcode 'cloud',
64491
+ // which on a LOCAL (SQLite) workspace would flip cloudMode=true and divert
64492
+ // writes into the offline queue with a bogus "will sync when cloud
64493
+ // reconnects" toast against a workspace that has no cloud.
64494
+ setStatusPill(cloudMode ? 'cloud' : 'local', 'disconnected');
64309
64495
  scheduleEventStreamReconnect();
64310
64496
  };
64311
64497
  }
@@ -68213,7 +68399,7 @@ var rowContextJs = ` // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u250
68213
68399
  var cfg = res[1];
68214
68400
  st.name = (id && id.display_name) || '';
68215
68401
  st.email = (id && id.email) || '';
68216
- st.connected = !!(cfg && (cfg.claudeAuthKind === 'oauth' || cfg.hasAnthropicKey));
68402
+ st.connected = claudeAuth(cfg).oauth;
68217
68403
  if (!st.wsName && st.name) st.wsName = st.name + "'s Workspace";
68218
68404
  render();
68219
68405
  });
@@ -68874,7 +69060,7 @@ var dataModelJs = ` // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
68874
69060
  '</p>' +
68875
69061
  // Connect-with-Claude is the primary path (use your subscription, no
68876
69062
  // API key). A pasted API key is demoted to an "Advanced" disclosure.
68877
- (cfg.claudeAuthKind === 'oauth'
69063
+ (claudeAuth(cfg).oauth
68878
69064
  ? '<div style="display:flex;align-items:center;gap:10px;margin-bottom:10px">' +
68879
69065
  '<span class="feed-source" style="background:var(--accent-soft);color:var(--accent)">Connected with Claude</span>' +
68880
69066
  '<button id="asst-oauth-disconnect" class="btn">Disconnect</button>' +
@@ -68896,7 +69082,7 @@ var dataModelJs = ` // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
68896
69082
  '</div>' +
68897
69083
  '<div id="connect-claude-msg" style="margin-top:6px;font-size:12px;color:var(--text-muted)"></div>' +
68898
69084
  '</div>') +
68899
- '<details style="margin-bottom:12px"' + (cfg.claudeAuthKind === 'key' ? ' open' : '') + '>' +
69085
+ '<details style="margin-bottom:12px"' + (claudeAuth(cfg).kind === 'key' ? ' open' : '') + '>' +
68900
69086
  '<summary style="cursor:pointer;font-size:12px;color:var(--text-muted)">Advanced \u2014 use an API key instead</summary>' +
68901
69087
  '<div style="margin-top:8px">' +
68902
69088
  rowHtml('asst-anthropic', 'Claude API token (chat)', !!cfg.hasAnthropicKey, 'sk-ant-\u2026') +
@@ -70888,7 +71074,7 @@ var createDatabaseWizardJs = ` // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\
70888
71074
  function renderComposer() {
70889
71075
  var host = document.getElementById('rail-composer'); if (!host) return;
70890
71076
  fetchJson('/api/assistant/config').then(function (cfg) {
70891
- if (cfg && cfg.hasClaudeAuth) {
71077
+ if (claudeAuth(cfg).any) {
70892
71078
  var micHtml = cfg.hasVoiceKey
70893
71079
  ? '<button class="composer-mic" id="chat-mic" title="Record voice">\u{1F399}</button>'
70894
71080
  : '';
@@ -77239,6 +77425,7 @@ async function startGuiServer(options) {
77239
77425
  }
77240
77426
  const autoRender = options.autoRender ?? false;
77241
77427
  const guiVersion = options.version ?? "";
77428
+ const desktopOpenExternal = options.desktopOpenExternal;
77242
77429
  const sessionId = crypto.randomUUID();
77243
77430
  let updateService = null;
77244
77431
  let activeRef = bootConfigPath && bootOutputDir ? await openConfig(bootConfigPath, bootOutputDir, autoRender, options.realtimeWatchdogMs) : null;
@@ -77421,6 +77608,20 @@ async function startGuiServer(options) {
77421
77608
  sendJson(res, { version: guiVersion });
77422
77609
  return;
77423
77610
  }
77611
+ if (method === "GET" && pathname === "/api/desktop/open") {
77612
+ if (!desktopOpenExternal) {
77613
+ sendJson(res, { error: "not found" }, 404);
77614
+ return;
77615
+ }
77616
+ const target = new URL(req.url ?? "", "http://localhost").searchParams.get("url");
77617
+ if (!target || !/^https?:\/\//i.test(target)) {
77618
+ sendJson(res, { error: "url must be http(s)" }, 400);
77619
+ return;
77620
+ }
77621
+ desktopOpenExternal(target);
77622
+ sendJson(res, { ok: true });
77623
+ return;
77624
+ }
77424
77625
  if (method === "GET" && pathname === "/api/update/status") {
77425
77626
  sendJson(
77426
77627
  res,
@@ -77988,6 +78189,7 @@ export {
77988
78189
  DEFAULT_ENTRY_TYPES,
77989
78190
  DEFAULT_MAX_NODES,
77990
78191
  DEFAULT_TYPE_ALIASES,
78192
+ DenoSqliteAdapter,
77991
78193
  EMBEDDINGS_TABLE,
77992
78194
  EmbeddingDimensionMismatchError,
77993
78195
  EmbeddingScanTooLargeError,
@@ -0,0 +1,75 @@
1
+ # Lattice Desktop app
2
+
3
+ A downloadable, double-click desktop build of the Lattice GUI — no terminal, no
4
+ `npm install`. It runs the **exact same** GUI server as `lattice gui`, served into
5
+ a native window, so there is only one GUI to maintain.
6
+
7
+ ## Install
8
+
9
+ Download the installer for your OS from **[latticesql.com/install](https://latticesql.com/install)**:
10
+
11
+ - **macOS** — `Lattice.dmg` (Apple silicon + Intel)
12
+ - **Windows** — `Lattice.msi`
13
+
14
+ The CLI path keeps working unchanged: `npm i -g latticesql && lattice gui`.
15
+
16
+ > **Unsigned builds (current):** the v1 installers are not yet code-signed, so the
17
+ > first launch shows an "unidentified developer" (macOS Gatekeeper) or "unknown
18
+ > publisher" (Windows SmartScreen) prompt. Choose **Open anyway** / **Run anyway**.
19
+ > Signed builds remove this step.
20
+
21
+ ## How it works
22
+
23
+ The desktop app is built with [`deno desktop`](https://docs.deno.com/runtime/desktop/).
24
+ It boots the standard `startGuiServer()` on a local port and points a native
25
+ webview window at it — the webview talks to the local server exactly like a
26
+ browser tab.
27
+
28
+ - **Same version as the web GUI.** The app and its installer report the same
29
+ `latticesql` version the web GUI shows (one build constant; `deno.json`'s
30
+ version is kept in lockstep with `package.json` by `scripts/sync-desktop-version.mjs`).
31
+ - **SQLite without native addons.** `better-sqlite3` is a native N-API addon that
32
+ cannot load under Deno, so the desktop build uses [`DenoSqliteAdapter`](../src/db/sqlite-deno.ts),
33
+ a drop-in adapter over the runtime's built-in `node:sqlite` `DatabaseSync`. The
34
+ npm/Node distribution is unchanged and still uses `better-sqlite3`.
35
+ - **External links open in your browser.** A webview has no tabs/popups, so the
36
+ desktop shell routes `target="_blank"` links and `window.open()` to the system
37
+ default browser. "Connect with Claude" opens the provider page in your browser
38
+ while keeping the auth session local to the app.
39
+ - **Upgrade-on-run.** On launch the app checks the release channel via
40
+ `Deno.autoUpdate()` and the `latest.json` manifest published with each release.
41
+ - **Upgrade-on-install.** The download page always links the latest release, so a
42
+ fresh install is always current.
43
+
44
+ ## Build from source
45
+
46
+ Requires a Deno **canary** build (`deno desktop` is canary-only for now):
47
+
48
+ ```bash
49
+ deno upgrade canary
50
+ npm ci
51
+
52
+ # macOS .dmg → dist-desktop/Lattice.dmg
53
+ npm run desktop:build:mac
54
+
55
+ # Windows .msi → dist-desktop/Lattice.msi
56
+ npm run desktop:build:win
57
+
58
+ # Run the windowed app directly during development
59
+ npm run desktop:dev
60
+ ```
61
+
62
+ The app identity (name, bundle id, per-platform icons, update base URL) lives in
63
+ [`deno.json`](../deno.json) under the `desktop` key.
64
+
65
+ Releases are cut by the `Desktop Release` workflow on a `v*` tag: it builds both
66
+ OSes, generates `latest.json`, and uploads the installers + manifest to the
67
+ GitHub Release.
68
+
69
+ ## Limitations
70
+
71
+ - **Image processing (`sharp`) and `sqlite-vec` acceleration are unavailable** in
72
+ the desktop build — both are native addons that do not load under Deno. Vector
73
+ search falls back to an in-process scan; image-dependent features are disabled.
74
+ Use the npm/Node build if you need them.
75
+ - The build is large (it embeds its runtime + dependencies) and currently unsigned.