@hraness/sponge 0.2.3 → 0.2.5
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 +53 -0
- package/dist/migrations/005.d.ts +3 -0
- package/dist/migrations/005.js +19 -0
- package/dist/migrations/006.d.ts +3 -0
- package/dist/migrations/006.js +9 -0
- package/dist/migrations/007.d.ts +3 -0
- package/dist/migrations/007.js +10 -0
- package/dist/src/acquisition/lock.d.ts +1 -1
- package/dist/src/acquisition/lock.js +1 -1
- package/dist/src/acquisition/pins.js +3 -3
- package/dist/src/annotations/quote.d.ts +32 -0
- package/dist/src/annotations/quote.js +135 -0
- package/dist/src/annotations/store.d.ts +50 -0
- package/dist/src/annotations/store.js +89 -0
- package/dist/src/app/source.d.ts +2 -0
- package/dist/src/app/source.js +13 -17
- package/dist/src/cli/arguments.js +24 -7
- package/dist/src/cli/digest.d.ts +10 -0
- package/dist/src/cli/digest.js +63 -0
- package/dist/src/cli/import.d.ts +11 -0
- package/dist/src/cli/import.js +10 -0
- package/dist/src/cli/indexing.d.ts +3 -0
- package/dist/src/cli/indexing.js +5 -2
- package/dist/src/cli/main.js +94 -8
- package/dist/src/cli/runtimes.d.ts +10 -0
- package/dist/src/cli/runtimes.js +32 -0
- package/dist/src/digest/editorial.d.ts +53 -0
- package/dist/src/digest/editorial.js +81 -0
- package/dist/src/digest/endpoint.d.ts +20 -0
- package/dist/src/digest/endpoint.js +103 -0
- package/dist/src/digest/pipeline.d.ts +148 -0
- package/dist/src/digest/pipeline.js +410 -0
- package/dist/src/digest/schema.d.ts +85 -0
- package/dist/src/digest/schema.js +118 -0
- package/dist/src/digest/store.d.ts +57 -0
- package/dist/src/digest/store.js +77 -0
- package/dist/src/identity/query-policy.d.ts +21 -0
- package/dist/src/identity/query-policy.js +55 -0
- package/dist/src/identity/uri.d.ts +30 -0
- package/dist/src/identity/uri.js +94 -0
- package/dist/src/identity/visibility.d.ts +24 -0
- package/dist/src/identity/visibility.js +75 -0
- package/dist/src/importers/apply.d.ts +10 -0
- package/dist/src/importers/apply.js +25 -22
- package/dist/src/importers/jungle-digest.d.ts +97 -0
- package/dist/src/importers/jungle-digest.js +221 -0
- package/dist/src/importers/jungle-store.d.ts +45 -0
- package/dist/src/importers/jungle-store.js +95 -0
- package/dist/src/importers/jungle.d.ts +54 -0
- package/dist/src/importers/jungle.js +134 -0
- package/dist/src/indexing/index.d.ts +7 -0
- package/dist/src/indexing/index.js +31 -8
- package/dist/src/indexing/prune-run.d.ts +22 -0
- package/dist/src/indexing/prune-run.js +67 -0
- package/dist/src/indexing/prune.d.ts +30 -0
- package/dist/src/indexing/prune.js +95 -0
- package/dist/src/indexing/runner.js +5 -5
- package/dist/src/inference/embedding/index.d.ts +25 -0
- package/dist/src/inference/embedding/index.js +11 -0
- package/dist/src/models/artifacts.js +175 -33
- package/dist/src/portability/database.js +3 -0
- package/dist/src/publish/component.d.ts +8 -0
- package/dist/src/publish/component.js +114 -0
- package/dist/src/publish/feed.d.ts +24 -0
- package/dist/src/publish/feed.js +77 -0
- package/dist/src/publish/identity.d.ts +6 -0
- package/dist/src/publish/identity.js +68 -0
- package/dist/src/publish/index.d.ts +34 -0
- package/dist/src/publish/index.js +137 -0
- package/dist/src/publish/projection.d.ts +29 -0
- package/dist/src/publish/projection.js +43 -0
- package/dist/src/search/hybrid.js +2 -2
- package/dist/src/search/lexical.d.ts +11 -0
- package/dist/src/search/lexical.js +6 -0
- package/dist/src/search/query.d.ts +7 -3
- package/dist/src/search/query.js +52 -33
- package/dist/src/search/vector.d.ts +1 -1
- package/dist/src/search/vector.js +6 -5
- package/dist/src/store/changes.d.ts +42 -0
- package/dist/src/store/changes.js +178 -0
- package/dist/src/store/foundation.d.ts +7 -0
- package/dist/src/store/foundation.js +7 -0
- package/dist/src/store/index.d.ts +69 -0
- package/dist/src/store/index.js +134 -51
- package/dist/src/worker/runtime-gc.d.ts +30 -0
- package/dist/src/worker/runtime-gc.js +296 -0
- package/native/runtime-manifest.json +4 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -101,6 +101,35 @@ full-text search. Use `index create --profile NAME` and `search QUERY --profile
|
|
|
101
101
|
to keep separate search profiles. Model changes create separate index generations; a new one
|
|
102
102
|
becomes active only after it covers the current library. `index rollback
|
|
103
103
|
GENERATION` requires a complete generation compatible with the current revisions.
|
|
104
|
+
`index prune --dry-run` lists what pruning would delete; `index prune` deletes the
|
|
105
|
+
vectors of cancelled, failed and retired generations, keeping the active and any
|
|
106
|
+
building generation plus the most recent rollback-ready one per profile (`--keep N`,
|
|
107
|
+
0-16). It refuses while index work, cleanup or a backup is running. Freed pages are
|
|
108
|
+
reused; `--vacuum` also shrinks the file after checking free space. Rollback to a
|
|
109
|
+
pruned generation needs a rebuild.
|
|
110
|
+
|
|
111
|
+
### Digests
|
|
112
|
+
|
|
113
|
+
A digest is a one-sentence gist and 3–5 ideas, each with 1–2 verbatim quotes.
|
|
114
|
+
A local model proposes it; Sponge checks every rule against the captured text
|
|
115
|
+
and stores only a passing draft. Drafting is opt-in and needs a model server you
|
|
116
|
+
start yourself, such as llama.cpp `llama-server`, LM Studio or Ollama:
|
|
117
|
+
|
|
118
|
+
```sh
|
|
119
|
+
llama-server -m gemma-4-12b-it-Q4_K_M.gguf --port 8080
|
|
120
|
+
sponge digest ITEM --endpoint http://127.0.0.1:8080 --model NAME
|
|
121
|
+
sponge digest ITEM
|
|
122
|
+
sponge review DIGEST --accept all --reject quote:1.0
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
`--model` must match an id the server lists at `/v1/models`. Endpoints must be
|
|
126
|
+
literal loopback HTTP (`127.0.0.1` or `[::1]`); Sponge refuses anything else so
|
|
127
|
+
captured text never leaves the machine, and never starts or downloads a model.
|
|
128
|
+
Suggested models are Gemma 4 12B on 16 GB Macs and Gemma 4 E4B on 8 GB, with
|
|
129
|
+
Qwen3.5 9B or 4B as alternatives. Rerunning with the same inputs returns the stored
|
|
130
|
+
draft. Review targets are `all`, `gist`, `idea:N` and `quote:N.M` (0-based); only
|
|
131
|
+
accepted fields can be published. `--check-support` also requires each quote to
|
|
132
|
+
support its claim by local embedding similarity. See [digest drafting](src/digest/README.md).
|
|
104
133
|
|
|
105
134
|
### Export, recovery and background work
|
|
106
135
|
|
|
@@ -110,6 +139,7 @@ sponge backup --output /absolute/new/library.sponge
|
|
|
110
139
|
sponge restore /absolute/library.sponge --into /absolute/new/library
|
|
111
140
|
sponge gc --dry-run
|
|
112
141
|
sponge gc --apply /absolute/path/to/report.json
|
|
142
|
+
sponge gc --runtimes --dry-run
|
|
113
143
|
sponge worker install --language en
|
|
114
144
|
sponge worker status
|
|
115
145
|
sponge worker uninstall
|
|
@@ -119,6 +149,10 @@ Exports contain Markdown, images and saved notes. Backups preserve revisions,
|
|
|
119
149
|
assets, reading state and notes. Restore requires a new directory, verifies every
|
|
120
150
|
file and leaves connections unresolved; runtimes and credentials are excluded.
|
|
121
151
|
Garbage collection removes only unreferenced blobs after rechecking the report.
|
|
152
|
+
`gc --runtimes` removes capture runtimes and model packages this Sponge no longer
|
|
153
|
+
pins, plus settled worker journals; `--dry-run` only lists them. It holds worker
|
|
154
|
+
custody, keeps models an active or building index generation needs, and refuses
|
|
155
|
+
symlinks and anything in use. Successful `setup` runs the same collection.
|
|
122
156
|
|
|
123
157
|
The background worker is opt-in and processes work sequentially. Its LaunchAgent
|
|
124
158
|
pins the installed command; after an upgrade, reinstall the worker to update that
|
|
@@ -126,6 +160,25 @@ binding. Uninstall stops the worker and preserves the library. In-session startu
|
|
|
126
160
|
and cleanup are checked; fresh-login startup remains unqualified. See
|
|
127
161
|
[importing existing captures](docs/importing.md) for a preview-first import flow.
|
|
128
162
|
|
|
163
|
+
### Public reading list
|
|
164
|
+
|
|
165
|
+
```sh
|
|
166
|
+
sponge publish --dry-run
|
|
167
|
+
sponge publish --output /absolute/site --title 'My reads' --base-url https://reads.example.com/ --min-age-days 7
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
Items captured from public sources are public by default; `visibility ITEM private`
|
|
171
|
+
hides one. `publish --output` writes a static site: a JSON Feed (`feed.json`,
|
|
172
|
+
newest 100), monthly shards under `items/`, an Atom `feed.xml`, and an
|
|
173
|
+
`index.html` that uses the bundled `<sponge-list>` element. An Ed25519 key created
|
|
174
|
+
in the library on first publish signs a manifest of every file's hash; the
|
|
175
|
+
private key stays in the library. The same library state gives byte-identical
|
|
176
|
+
files. `--min-age-days N` holds back items listed in the last N days. Nothing is
|
|
177
|
+
uploaded. Embed the list elsewhere with
|
|
178
|
+
`<sponge-list src="https://reads.example.com/feed.json" verify></sponge-list>` and
|
|
179
|
+
`sponge-list.js`; the host must allow cross-origin reads, and `verify` needs
|
|
180
|
+
HTTPS. See [the decision record](docs/decisions/publish-feed.md).
|
|
181
|
+
|
|
129
182
|
### Selected authenticated connections
|
|
130
183
|
|
|
131
184
|
The initial development interface accepts private `connections.json` in the
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
/** Additive sync and publishing foundation: shareable URIs, visibility, change log, annotations, content-addressed derivations. */
|
|
2
|
+
export declare const version = 5;
|
|
3
|
+
export declare const sql = "\nCREATE TABLE item_uris(item_id TEXT NOT NULL REFERENCES items(id),uri TEXT NOT NULL CHECK(length(uri) BETWEEN 3 AND 8192),role TEXT NOT NULL CHECK(role IN ('primary','alias')),resolvable INTEGER NOT NULL CHECK(resolvable IN (0,1)),origin TEXT NOT NULL CHECK(origin IN ('locator','revision','metadata','user')),PRIMARY KEY(item_id,uri)) STRICT;\nCREATE UNIQUE INDEX item_uris_primary ON item_uris(item_id) WHERE role='primary';\nCREATE INDEX item_uris_uri ON item_uris(uri);\nALTER TABLE items ADD COLUMN visibility TEXT CHECK(visibility IN ('public','private'));\nALTER TABLE annotations ADD COLUMN kind TEXT NOT NULL DEFAULT 'note' CHECK(kind IN ('note','highlight','comment'));\nALTER TABLE annotations ADD COLUMN parent_id TEXT REFERENCES annotations(id);\nALTER TABLE annotations ADD COLUMN updated_at TEXT;\nALTER TABLE annotations ADD COLUMN deleted_at TEXT;\nCREATE TABLE device(id INTEGER PRIMARY KEY CHECK(id=1),device_id TEXT NOT NULL CHECK(length(device_id)=32),clock_ms INTEGER NOT NULL DEFAULT 0 CHECK(clock_ms>=0),clock_counter INTEGER NOT NULL DEFAULT 0 CHECK(clock_counter>=0)) STRICT;\nINSERT INTO device(id,device_id) VALUES(1,lower(hex(randomblob(16))));\nCREATE TABLE changes(seq INTEGER PRIMARY KEY AUTOINCREMENT,id TEXT NOT NULL UNIQUE,device_id TEXT NOT NULL,hlc TEXT NOT NULL,entity TEXT NOT NULL CHECK(entity IN ('item','annotation','reading','derivation')),entity_id TEXT NOT NULL,field TEXT NOT NULL,value_json TEXT NOT NULL,created_at TEXT NOT NULL) STRICT;\nCREATE INDEX changes_entity ON changes(entity,entity_id,field,hlc);\nCREATE TABLE derivations(id TEXT PRIMARY KEY,item_id TEXT NOT NULL REFERENCES items(id),revision_id TEXT NOT NULL REFERENCES revisions(id),kind TEXT NOT NULL CHECK(kind IN ('digest')),schema_version INTEGER NOT NULL CHECK(schema_version>0),producer_json TEXT NOT NULL,input_hash TEXT NOT NULL CHECK(length(input_hash)=64),output_json TEXT NOT NULL,review_json TEXT NOT NULL DEFAULT '{}',created_at TEXT NOT NULL) STRICT;\nCREATE INDEX derivations_revision ON derivations(revision_id,kind,input_hash);\nCREATE INDEX derivations_item ON derivations(item_id,kind,created_at);\n";
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/** Additive sync and publishing foundation: shareable URIs, visibility, change log, annotations, content-addressed derivations. */
|
|
2
|
+
export const version = 5;
|
|
3
|
+
export const sql = `
|
|
4
|
+
CREATE TABLE item_uris(item_id TEXT NOT NULL REFERENCES items(id),uri TEXT NOT NULL CHECK(length(uri) BETWEEN 3 AND 8192),role TEXT NOT NULL CHECK(role IN ('primary','alias')),resolvable INTEGER NOT NULL CHECK(resolvable IN (0,1)),origin TEXT NOT NULL CHECK(origin IN ('locator','revision','metadata','user')),PRIMARY KEY(item_id,uri)) STRICT;
|
|
5
|
+
CREATE UNIQUE INDEX item_uris_primary ON item_uris(item_id) WHERE role='primary';
|
|
6
|
+
CREATE INDEX item_uris_uri ON item_uris(uri);
|
|
7
|
+
ALTER TABLE items ADD COLUMN visibility TEXT CHECK(visibility IN ('public','private'));
|
|
8
|
+
ALTER TABLE annotations ADD COLUMN kind TEXT NOT NULL DEFAULT 'note' CHECK(kind IN ('note','highlight','comment'));
|
|
9
|
+
ALTER TABLE annotations ADD COLUMN parent_id TEXT REFERENCES annotations(id);
|
|
10
|
+
ALTER TABLE annotations ADD COLUMN updated_at TEXT;
|
|
11
|
+
ALTER TABLE annotations ADD COLUMN deleted_at TEXT;
|
|
12
|
+
CREATE TABLE device(id INTEGER PRIMARY KEY CHECK(id=1),device_id TEXT NOT NULL CHECK(length(device_id)=32),clock_ms INTEGER NOT NULL DEFAULT 0 CHECK(clock_ms>=0),clock_counter INTEGER NOT NULL DEFAULT 0 CHECK(clock_counter>=0)) STRICT;
|
|
13
|
+
INSERT INTO device(id,device_id) VALUES(1,lower(hex(randomblob(16))));
|
|
14
|
+
CREATE TABLE changes(seq INTEGER PRIMARY KEY AUTOINCREMENT,id TEXT NOT NULL UNIQUE,device_id TEXT NOT NULL,hlc TEXT NOT NULL,entity TEXT NOT NULL CHECK(entity IN ('item','annotation','reading','derivation')),entity_id TEXT NOT NULL,field TEXT NOT NULL,value_json TEXT NOT NULL,created_at TEXT NOT NULL) STRICT;
|
|
15
|
+
CREATE INDEX changes_entity ON changes(entity,entity_id,field,hlc);
|
|
16
|
+
CREATE TABLE derivations(id TEXT PRIMARY KEY,item_id TEXT NOT NULL REFERENCES items(id),revision_id TEXT NOT NULL REFERENCES revisions(id),kind TEXT NOT NULL CHECK(kind IN ('digest')),schema_version INTEGER NOT NULL CHECK(schema_version>0),producer_json TEXT NOT NULL,input_hash TEXT NOT NULL CHECK(length(input_hash)=64),output_json TEXT NOT NULL,review_json TEXT NOT NULL DEFAULT '{}',created_at TEXT NOT NULL) STRICT;
|
|
17
|
+
CREATE INDEX derivations_revision ON derivations(revision_id,kind,input_hash);
|
|
18
|
+
CREATE INDEX derivations_item ON derivations(item_id,kind,created_at);
|
|
19
|
+
`;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
/** Storage diet: readable FTS keeps no text copy; representations.markdown and items.title stay authoritative. */
|
|
2
|
+
export declare const version = 6;
|
|
3
|
+
export declare const sql = "\nCREATE TABLE readable_fts_rows(id INTEGER PRIMARY KEY,item_id TEXT NOT NULL UNIQUE REFERENCES items(id),revision_id TEXT NOT NULL REFERENCES revisions(id)) STRICT;\nDROP TABLE readable_fts;\nCREATE VIRTUAL TABLE readable_fts USING fts5(title,markdown,content='',contentless_delete=1,tokenize='unicode61');\nINSERT INTO readable_fts_rows(item_id,revision_id) SELECT i.id,i.current_revision FROM items i WHERE i.deleted_at IS NULL AND i.current_revision IS NOT NULL AND EXISTS(SELECT 1 FROM representations p WHERE p.revision_id=i.current_revision AND p.kind='markdown' AND p.markdown IS NOT NULL) ORDER BY i.created_at,i.id;\nINSERT INTO readable_fts(rowid,title,markdown) SELECT m.id,i.title,(SELECT p.markdown FROM representations p WHERE p.revision_id=m.revision_id AND p.kind='markdown' AND p.markdown IS NOT NULL ORDER BY p.rowid LIMIT 1) FROM readable_fts_rows m JOIN items i ON i.id=m.item_id ORDER BY m.id;\n";
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/** Storage diet: readable FTS keeps no text copy; representations.markdown and items.title stay authoritative. */
|
|
2
|
+
export const version = 6;
|
|
3
|
+
export const sql = `
|
|
4
|
+
CREATE TABLE readable_fts_rows(id INTEGER PRIMARY KEY,item_id TEXT NOT NULL UNIQUE REFERENCES items(id),revision_id TEXT NOT NULL REFERENCES revisions(id)) STRICT;
|
|
5
|
+
DROP TABLE readable_fts;
|
|
6
|
+
CREATE VIRTUAL TABLE readable_fts USING fts5(title,markdown,content='',contentless_delete=1,tokenize='unicode61');
|
|
7
|
+
INSERT INTO readable_fts_rows(item_id,revision_id) SELECT i.id,i.current_revision FROM items i WHERE i.deleted_at IS NULL AND i.current_revision IS NOT NULL AND EXISTS(SELECT 1 FROM representations p WHERE p.revision_id=i.current_revision AND p.kind='markdown' AND p.markdown IS NOT NULL) ORDER BY i.created_at,i.id;
|
|
8
|
+
INSERT INTO readable_fts(rowid,title,markdown) SELECT m.id,i.title,(SELECT p.markdown FROM representations p WHERE p.revision_id=m.revision_id AND p.kind='markdown' AND p.markdown IS NOT NULL ORDER BY p.rowid LIMIT 1) FROM readable_fts_rows m JOIN items i ON i.id=m.item_id ORDER BY m.id;
|
|
9
|
+
`;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
/** Editorial derivations: a reviewed source note (Jungle Reading) kept losslessly beside Digest v1. SQLite cannot widen a CHECK in place, so the table is rebuilt; rows and ids are unchanged. */
|
|
2
|
+
export declare const version = 7;
|
|
3
|
+
export declare const sql = "\nCREATE TABLE derivations_v7(id TEXT PRIMARY KEY,item_id TEXT NOT NULL REFERENCES items(id),revision_id TEXT NOT NULL REFERENCES revisions(id),kind TEXT NOT NULL CHECK(kind IN ('digest','editorial')),schema_version INTEGER NOT NULL CHECK(schema_version>0),producer_json TEXT NOT NULL,input_hash TEXT NOT NULL CHECK(length(input_hash)=64),output_json TEXT NOT NULL,review_json TEXT NOT NULL DEFAULT '{}',created_at TEXT NOT NULL) STRICT;\nINSERT INTO derivations_v7(rowid,id,item_id,revision_id,kind,schema_version,producer_json,input_hash,output_json,review_json,created_at) SELECT rowid,id,item_id,revision_id,kind,schema_version,producer_json,input_hash,output_json,review_json,created_at FROM derivations ORDER BY rowid;\nDROP TABLE derivations;\nALTER TABLE derivations_v7 RENAME TO derivations;\nCREATE INDEX derivations_revision ON derivations(revision_id,kind,input_hash);\nCREATE INDEX derivations_item ON derivations(item_id,kind,created_at);\n";
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** Editorial derivations: a reviewed source note (Jungle Reading) kept losslessly beside Digest v1. SQLite cannot widen a CHECK in place, so the table is rebuilt; rows and ids are unchanged. */
|
|
2
|
+
export const version = 7;
|
|
3
|
+
export const sql = `
|
|
4
|
+
CREATE TABLE derivations_v7(id TEXT PRIMARY KEY,item_id TEXT NOT NULL REFERENCES items(id),revision_id TEXT NOT NULL REFERENCES revisions(id),kind TEXT NOT NULL CHECK(kind IN ('digest','editorial')),schema_version INTEGER NOT NULL CHECK(schema_version>0),producer_json TEXT NOT NULL,input_hash TEXT NOT NULL CHECK(length(input_hash)=64),output_json TEXT NOT NULL,review_json TEXT NOT NULL DEFAULT '{}',created_at TEXT NOT NULL) STRICT;
|
|
5
|
+
INSERT INTO derivations_v7(rowid,id,item_id,revision_id,kind,schema_version,producer_json,input_hash,output_json,review_json,created_at) SELECT rowid,id,item_id,revision_id,kind,schema_version,producer_json,input_hash,output_json,review_json,created_at FROM derivations ORDER BY rowid;
|
|
6
|
+
DROP TABLE derivations;
|
|
7
|
+
ALTER TABLE derivations_v7 RENAME TO derivations;
|
|
8
|
+
CREATE INDEX derivations_revision ON derivations(revision_id,kind,input_hash);
|
|
9
|
+
CREATE INDEX derivations_item ON derivations(item_id,kind,created_at);
|
|
10
|
+
`;
|