latticesql 3.3.5 → 3.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +25 -0
- package/dist/cli.js +2797 -1503
- package/dist/index.cjs +2882 -1621
- package/dist/index.d.cts +273 -137
- package/dist/index.d.ts +273 -137
- package/dist/index.js +2503 -1237
- package/docs/api-reference.md +48 -0
- package/docs/assistant.md +21 -0
- package/docs/cloud.md +20 -0
- package/docs/workspaces.md +33 -0
- package/package.json +1 -1
package/docs/api-reference.md
CHANGED
|
@@ -608,6 +608,54 @@ const stop = await db.watch('./context', {
|
|
|
608
608
|
stop();
|
|
609
609
|
```
|
|
610
610
|
|
|
611
|
+
---
|
|
612
|
+
|
|
613
|
+
#### `reverseSyncFromFiles(outputDir, opts?): Promise<ReverseSyncResult>`
|
|
614
|
+
|
|
615
|
+
Detect external modifications to rendered context files and apply changelog-aware reverse-sync updates to the database.
|
|
616
|
+
|
|
617
|
+
```ts
|
|
618
|
+
const result = await db.reverseSyncFromFiles('./context');
|
|
619
|
+
console.log(`Scanned ${result.filesScanned} files, changed ${result.filesChanged}`);
|
|
620
|
+
|
|
621
|
+
// With changelog-aware apply and automatic default round-trip:
|
|
622
|
+
await db.reverseSyncFromFiles('./context', {
|
|
623
|
+
apply: async (update) => {
|
|
624
|
+
await db.update(update.table, update.pk, update.set);
|
|
625
|
+
},
|
|
626
|
+
useDefault: true,
|
|
627
|
+
onSkip: (info) => {
|
|
628
|
+
console.log(`Skipped ${info.table}/${info.slug}/${info.filename} (custom render)`);
|
|
629
|
+
},
|
|
630
|
+
});
|
|
631
|
+
```
|
|
632
|
+
|
|
633
|
+
Compares file content hashes against the current manifest, so a render-written file is recognized as an echo and skipped. Unlike `reconcile()` (which runs raw SQL), this is the changelog-aware entry point used by the GUI file-loopback: pass `apply` to route each update through a versioned write (so a file edit lands in the changelog and shows up live, just like a GUI edit), and `useDefault` to round-trip structured frontmatter + body `key: value` fields for files without a hand-written `reverseSync` function. A file whose changes can't be safely parsed (free-form/custom render) is surfaced via `onSkip` rather than guessed at, so a lossy render can't corrupt a row.
|
|
634
|
+
|
|
635
|
+
**`ReverseSyncProcessOptions`** (all optional):
|
|
636
|
+
|
|
637
|
+
| Option | Type | Description |
|
|
638
|
+
| ------------ | ----------------------------------------------------- | ---------------------------------------------------------------------------------------- |
|
|
639
|
+
| `apply` | `(update: ReverseSyncUpdate) => Promise<void>` | Route each update through a changelog-aware path instead of raw SQL |
|
|
640
|
+
| `useDefault` | `boolean` | Derive updates for files lacking a hand-written `reverseSync` (frontmatter + body pairs) |
|
|
641
|
+
| `onSkip` | `(info: { table; slug; filename; filePath }) => void` | Called when a changed file produced no importable update (free-form/custom render) |
|
|
642
|
+
|
|
643
|
+
The result reports `filesScanned`, `filesChanged`, `updatesApplied`, and any per-file `errors`.
|
|
644
|
+
|
|
645
|
+
---
|
|
646
|
+
|
|
647
|
+
#### `rebuildFtsIndexes(): Promise<void>`
|
|
648
|
+
|
|
649
|
+
(Re)build the full-text search indexes for all tables with `fts` configuration, backfilling existing rows. Used after `migrate-to-cloud` to ensure search works on a migrated cloud workspace.
|
|
650
|
+
|
|
651
|
+
```ts
|
|
652
|
+
await db.rebuildFtsIndexes();
|
|
653
|
+
```
|
|
654
|
+
|
|
655
|
+
The `migrate-to-cloud` command calls this automatically after copying rows; use it manually to recover search if an index was omitted or needs rebuilding. Idempotent — running it multiple times is safe.
|
|
656
|
+
|
|
657
|
+
---
|
|
658
|
+
|
|
611
659
|
**`WatchOptions`:**
|
|
612
660
|
|
|
613
661
|
| Option | Type | Default | Description |
|
package/docs/assistant.md
CHANGED
|
@@ -43,6 +43,14 @@ in the GUI via the same mode-aware navigator the activity feed uses; it links th
|
|
|
43
43
|
user-facing record (the contract/person/etc.) rather than an internal `files` id,
|
|
44
44
|
and only ids it actually retrieved.
|
|
45
45
|
|
|
46
|
+
**The assistant reads your organized context.** A new `get_row_context` tool lets
|
|
47
|
+
the assistant pull a record's full rendered context — its own fields, related
|
|
48
|
+
records, and combined summary — in a single call. It leverages the context tree
|
|
49
|
+
Lattice maintains rather than re-stitching together raw reads, so the model can
|
|
50
|
+
answer follow-ups like "summarize this record" or "what are the related items?" in
|
|
51
|
+
one tool call. It falls back to direct row tools when a record hasn't been rendered
|
|
52
|
+
yet.
|
|
53
|
+
|
|
46
54
|
**Deleting a table is guarded + reversible.** The `delete_entity` tool refuses
|
|
47
55
|
built-in tables, tables another table links to, and tables you don't own. An
|
|
48
56
|
**empty** table is soft-deleted immediately; a **non-empty** one is **not**
|
|
@@ -51,6 +59,12 @@ count and the assistant asks, then you choose `delete_data` (soft-delete the row
|
|
|
51
59
|
too) or `move_to` another table. The physical table + rows are kept (no hard
|
|
52
60
|
drop), so the whole thing is revertible from version history.
|
|
53
61
|
|
|
62
|
+
**Adding a field to an existing table.** The `add_column` tool lets the assistant
|
|
63
|
+
add a single column to an existing table on request ("add a priority field to
|
|
64
|
+
projects", "add an email column"). The column is registered live, persisted,
|
|
65
|
+
audited, and revertible. On a cloud, the per-column masking view is rebuilt so
|
|
66
|
+
members see the new field immediately.
|
|
67
|
+
|
|
54
68
|
Conversations persist in the native `chat_threads` / `chat_messages` entities;
|
|
55
69
|
use the thread switcher to revisit them. A new thread is **named from a short AI
|
|
56
70
|
summary** of its first exchange (e.g. "Adding New Notes About Cheese"). The
|
|
@@ -74,6 +88,13 @@ open, the chat passes that record (table + id) as context, so "delete this file"
|
|
|
74
88
|
one. It's a hint only — every action still goes through the same permission-gated
|
|
75
89
|
tools, so it can't reach a record you couldn't otherwise touch.
|
|
76
90
|
|
|
91
|
+
**Pasted GUI links resolve to the actual record.** When you paste a local GUI link
|
|
92
|
+
(the address bar's `…/#/fs/<table>/<id>`) into the chat, the assistant resolves it
|
|
93
|
+
deterministically to its real data in the database (via the same permission-gated
|
|
94
|
+
read as any other access), so it can answer queries about that record without
|
|
95
|
+
needing to fetch or guess. Resolution happens in code; the resolved data appears in
|
|
96
|
+
context alongside the viewed record.
|
|
97
|
+
|
|
77
98
|
The assistant can also **answer questions about Lattice itself.** Ask "what is
|
|
78
99
|
private mode?" or "how do I invite a member?" and it calls the `lattice_help` tool,
|
|
79
100
|
which searches Lattice's own documentation (these `docs/*.md` files — the single
|
package/docs/cloud.md
CHANGED
|
@@ -158,6 +158,10 @@ Lattice only needs the roles to exist and to be members of `lattice_members`.
|
|
|
158
158
|
|
|
159
159
|
---
|
|
160
160
|
|
|
161
|
+
### Cloud sharing internals consolidated (v3.4)
|
|
162
|
+
|
|
163
|
+
The internal machinery backing row sharing was refactored in v3.4 with **no behavior change** to the live features: row `private` / `everyone` / custom "specific people" sharing, table `default_row_visibility` and `never_share`, and the `owner` secret-column mask all work identically. The consolidation removed unreachable masking machinery and moved permission checks into single `SECURITY DEFINER` helpers, eliminating the risk of regressions when sharing logic changes. The changes are additive and idempotent — clouds converge safely on an owner's next open.
|
|
164
|
+
|
|
161
165
|
## Sharing: private by default
|
|
162
166
|
|
|
163
167
|
Every row is **private to its owner** the moment it's written — the per-table
|
|
@@ -236,6 +240,22 @@ now lives canonically in the DB and the mask view regenerates from it on change.
|
|
|
236
240
|
|
|
237
241
|
---
|
|
238
242
|
|
|
243
|
+
## Opening the cloud & the converge
|
|
244
|
+
|
|
245
|
+
When any member opens a cloud, Lattice runs a **converge** pass: it reads the current Postgres schema against the workspace's registered entities and reconciles them — granting table/column privileges to the member group, rebuilding masking views, installing any missing RLS machinery. Since v3.4, the converge is **per-table fault-isolated**: if the connecting role cannot `ALTER` or `GRANT` a table (most often because it was created by a different Postgres role), that one table is skipped with an actionable reason instead of failing the whole workspace and degrading all objects to "Failed to fetch". The skip is reported in `GET /api/dbconfig` as `convergeWarnings`, for example: `"owned by role X, but this workspace connects as Y — fix with: `ALTER TABLE … OWNER TO Y`"`.
|
|
246
|
+
|
|
247
|
+
`POST /api/workspaces/reload` re-reads the config and re-registers entities in place without restarting the GUI, so a table added out-of-band surfaces immediately.
|
|
248
|
+
|
|
249
|
+
### Plaintext database URL heal-on-open
|
|
250
|
+
|
|
251
|
+
If a workspace config stores a raw `postgres://…` connection string (with its password in cleartext) in the `db:` line — typically from an older workspace or a migration — opening it now automatically moves the URL into the encrypted credential store and rewrites the line to a `${LATTICE_DB:<label>}` reference. This is idempotent: configs already using a reference, or pointing to a SQLite file, are untouched. An existing credential is never overwritten, so the operation is safe to repeat.
|
|
252
|
+
|
|
253
|
+
## Rendered context scoped to viewer
|
|
254
|
+
|
|
255
|
+
On a cloud, the background render now reads every table **through the member's row-level-security connection and through the per-column masking view**. The rendered markdown a member's assistant reads off disk contains only the rows they may see (per RLS), with owner-only columns blanked, and with any per-viewer enrichment values they're allowed to see folded in. When sharing changes — a row is shared or un-shared — the affected member's context tree re-renders promptly, so it never lingers on a stale view.
|
|
256
|
+
|
|
257
|
+
Owners and local single-user workspaces render the full tree unchanged, as before.
|
|
258
|
+
|
|
239
259
|
## The three user flows
|
|
240
260
|
|
|
241
261
|
There are exactly three things you do with a cloud: **migrate** into one, **join**
|
package/docs/workspaces.md
CHANGED
|
@@ -67,6 +67,19 @@ join one. Creating/joining switches into the new workspace; the normal layout
|
|
|
67
67
|
returns on reload. The last workspace can now be deleted (it drops you back to the
|
|
68
68
|
welcome screen rather than being refused).
|
|
69
69
|
|
|
70
|
+
## Seamless GUI auto-update (3.4)
|
|
71
|
+
|
|
72
|
+
When `lattice gui` is launched from a published install (global or project-local npm install), it runs as a small supervisor that silently installs the latest published version before opening the browser. While you work, the supervisor keeps checking for updates in the background; when a new version lands it installs it and relaunches the server on the same port. The open tab reconnects, notices the version changed, and reloads onto the new build — **no manual refresh, no reinstall**.
|
|
73
|
+
|
|
74
|
+
A git checkout or `npx` copy is left untouched (auto-update is disabled there); a failed install surfaces in the GUI rather than being swallowed.
|
|
75
|
+
|
|
76
|
+
**HTTP endpoints** (for polling / UI integration):
|
|
77
|
+
|
|
78
|
+
| Route | Method | Returns |
|
|
79
|
+
| -------------------- | ------ | ------------------------- |
|
|
80
|
+
| `/api/version` | GET | `{ version: string }` |
|
|
81
|
+
| `/api/update/status` | GET | Update state and progress |
|
|
82
|
+
|
|
70
83
|
## Auto-render (SQL → markdown)
|
|
71
84
|
|
|
72
85
|
`enableAutoRender(outputDir)` debounces a re-render on every
|
|
@@ -79,6 +92,26 @@ A bare `new Lattice(path)` does **not** auto-render (`_scheduleAutoRender`
|
|
|
79
92
|
early-returns when no output dir is set) — call `render(dir)` / `reconcile(dir)`
|
|
80
93
|
manually, or opt in with `enableAutoRender(dir)`.
|
|
81
94
|
|
|
95
|
+
## File loopback (3.4)
|
|
96
|
+
|
|
97
|
+
When the GUI is serving a workspace, editing a rendered `.md` file on disk is automatically captured back into the database through the normal write path — so the change lands in the changelog (versioned/undoable) and appears live in the GUI, exactly as if the edit had been made there. Structured frontmatter and body `key: value` fields round-trip automatically; edits that can't be safely parsed (free-form or custom renders) are surfaced as a notice rather than guessed at, so a lossy render can't corrupt a row. Render echoes are suppressed via the manifest, so there is no write loop.
|
|
98
|
+
|
|
99
|
+
**For embedders**, `reverseSyncFromFiles()` exposes the same changelog-aware reverse-sync the GUI loopback uses:
|
|
100
|
+
|
|
101
|
+
```ts
|
|
102
|
+
import { Lattice } from 'latticesql';
|
|
103
|
+
|
|
104
|
+
const db = new Lattice(config);
|
|
105
|
+
await db.init();
|
|
106
|
+
|
|
107
|
+
// Round-trip frontmatter + body `key: value` edits from the rendered tree
|
|
108
|
+
// back into the DB. Pass `apply` to route each update through a versioned
|
|
109
|
+
// write (so a file edit is recorded exactly like a GUI edit).
|
|
110
|
+
const result = await db.reverseSyncFromFiles('./context', { useDefault: true });
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
`reverseSyncFromFiles(outputDir, opts)` compares file hashes against the current manifest (so a render-written file is recognized as an echo and skipped), parses the changed files, applies the updates, and returns a summary of what was applied.
|
|
114
|
+
|
|
82
115
|
The canonical `Context/` layout is DB-aligned and zero-config: table → folder,
|
|
83
116
|
row → subfolder, `<ENTITY>.md` plus relation rollups, derived from the schema
|
|
84
117
|
via `deriveCanonicalContexts`.
|
package/package.json
CHANGED