opencode-lossless 0.1.2 → 0.1.3
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 +13 -0
- package/README.md +18 -13
- package/dist/index.d.mts +18 -65
- package/dist/index.mjs +643 -75
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/skills/opencode-lossless/SKILL.md +31 -26
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# opencode-lossless
|
|
2
2
|
|
|
3
|
+
## 0.1.3
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 9c0fdc5: Harden `lossless-gc` against deleting sidecars that are live in another process. Sweeps skip stores active within the last 60 minutes and name them. Bare `--older-than 0` without `--session` is refused. `--session` on a store active within 60 minutes needs `--force`. Candidates younger than 24 hours carry a warning.
|
|
8
|
+
- 470a7b7: Verify file bytes and sha256 against the linked message text before inserting file rows on import. A repeated entry id with different text, or a file row whose text differs from the stored message, also refuses the import without writing. Existing rows stay untouched.
|
|
9
|
+
- 470a7b7: Add a mechanical tier for noisy tools. Name tools in `mechanicalTools` in summarizer-config, `/lcm` config, or the OpenCode plugin options. Their spans compact into deterministic `mechanical` leaves with zero summarizer spend at compaction time. Every message stays stored verbatim and covered, so the integrity coverage check passes, and heal re-derives a skipped leaf from provenance on demand. There is no ingest filtering.
|
|
10
|
+
- 9c0fdc5: Change the default `sidecarDir` to the auto-detected global path. The plugin uses `XDG_DATA_HOME` with a `~/.local/share` fallback, uses `LOCALAPPDATA` with an `APPDATA` fallback and then a `<home>/AppData/Local` fallback on Windows, and uses `./.lossless` when no home resolves. To keep per-project storage, set `"sidecarDir": "./.lossless"`. After upgrading a project that used `./.lossless`, keep that setting to keep its history: `/lossless-migrate` upgrades in place in the configured directory only (dry run by default) and moves nothing, so it cannot recover history left in `./.lossless`. To carry history across, export per session under the old config and import into an empty store under the new one, or stop the server first and copy the `.sqlite`, `-wal`, and `-shm` files across and then migrate. The plugin never moves sidecars.
|
|
11
|
+
- 470a7b7: Report orphan sidecars in doctor. `integritySnapshot` now lists sidecar files and stale `wal` and `shm` files with no live session (`.sqlite` by default, `.db` for Pi). `checkIntegrity` reports them as a read-only `orphan-sidecar` finding through `lcm doctor` and the diagnose bundle. Report only. Deletion stays manual.
|
|
12
|
+
- 470a7b7: Upgrade recall search. `lcm_grep` takes `role`, `date_start`/`date_end`, and `tool_name` filters. Role and time are SQL predicates on the stored columns with a covering index. Tool scope is an FTS rewrite against `[tool:Name]` markers with no new table or index. `lcm_expand` takes an `anchor` entry id that centers the listing window with edge clamping. The recall manifest and the retrieval brief order by stop-word stripped query-word overlap over summary headers. A read-only files view lists each linked file once with an incomplete-coverage flag and a `large-inline` mark. No migration and no new writer.
|
|
13
|
+
- 470a7b7: Add a read-only static sidecar dump. `/lcm dump` and `/lossless-dump` open the session sidecar `queryOnly` and reuse the recall views and metric rows. The dump redacts displayed seams, labels removed rows, and reports old generations as named skips. Output is capped at 16 KB.
|
|
14
|
+
- 0c70748: Ask providers for a whole number of tokens. A leaf target was half of the calibrated chunk budget, so it was fractional whenever that budget was odd, and a provider that validates `max_tokens` as an unsigned integer rejected the call with a 422. The ladder then stored the deterministic truncate: in one week of Pi sessions that was 1,315 of 5,358 summaries, with 540 rejected calls naming values such as `max_tokens: 5543.5`. The request builder now rounds to nearest, never below one, and treats a non-finite budget as that floor, before the reasoning headroom is added. Integer budgets produce the same request as before. No config key, migration or metric row changes.
|
|
15
|
+
|
|
3
16
|
## 0.1.2
|
|
4
17
|
|
|
5
18
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
**Lossless Context Management (LCM) for OpenCode v2. Long sessions keep working past the point where the model would forget, and every verbatim message stays searchable and readable.**
|
|
4
4
|
|
|
5
|
-
Install it, and the adapter mirrors every prompt, assistant reply, and tool exchange into a per-session SQLite sidecar. The model reads that history back through `lcm_grep`, `lcm_describe`, and `lcm_expand
|
|
5
|
+
Install it, and the adapter mirrors every prompt, assistant reply, and tool exchange into a per-session SQLite sidecar. The model reads that history back through `lcm_grep`, `lcm_describe`, and `lcm_expand`. With `assembly` true (the default) it also gets `lcm_expand_query`, which answers through a child session without pulling the originals into the parent. With assembly on, the adapter also owns the context boundary. Past the swap point the DAG projection replaces the aged history, and when the host compacts, the adapter hands it the frontier as the checkpoint instead of letting it summarize.
|
|
6
6
|
|
|
7
7
|
This package is the OpenCode v2 adapter over
|
|
8
8
|
[`lossless-core`](https://npmx.dev/package/lossless-core), the engine that
|
|
9
9
|
ingests the history and builds the summaries. Verified against OpenCode v2 in
|
|
10
|
-
live sessions
|
|
10
|
+
live sessions. The plugin loads from its directory, all mirrored text matches
|
|
11
11
|
verbatim, and host compactions store the DAG frontier as their checkpoint.
|
|
12
12
|
|
|
13
13
|
## Install
|
|
@@ -20,14 +20,16 @@ The equivalent entry in `opencode.json`:
|
|
|
20
20
|
|
|
21
21
|
```json
|
|
22
22
|
{
|
|
23
|
-
"plugins": [{ "package": "opencode-lossless"
|
|
23
|
+
"plugins": [{ "package": "opencode-lossless" }]
|
|
24
24
|
}
|
|
25
25
|
```
|
|
26
26
|
|
|
27
|
+
To keep sidecars inside the project, set `sidecarDir` to `"./.lossless"`.
|
|
28
|
+
|
|
27
29
|
## Quick start
|
|
28
30
|
|
|
29
|
-
|
|
30
|
-
once context crosses the swap point.
|
|
31
|
+
The plugin needs no configuration. Passive mirroring starts immediately, and swaps begin
|
|
32
|
+
once context crosses the swap point. The commands all start with `lossless-*`:
|
|
31
33
|
|
|
32
34
|
```sh
|
|
33
35
|
/lossless-status # message and compaction summary counts per live sidecar
|
|
@@ -40,11 +42,14 @@ once context crosses the swap point. Ten commands, all `lossless-*`:
|
|
|
40
42
|
/lossless-diagnose # redacted, pasteable diagnostics block; --save writes it at mode 0600
|
|
41
43
|
/lossless-migrate # upgrade older-schema sidecars in place (dry-run by default)
|
|
42
44
|
/lossless-gc # list old sidecars, or export and delete them (never the current session)
|
|
45
|
+
/lossless-dump # read-only dump of this session's sidecar; --include-removed keeps removed rows, --save writes mode 0600
|
|
43
46
|
```
|
|
44
47
|
|
|
45
|
-
The model gets
|
|
46
|
-
reaches past sessions
|
|
47
|
-
|
|
48
|
+
The model gets recall tools: `lcm_grep` (search this session, `scope`
|
|
49
|
+
reaches past sessions, `role`, `date_start`, `date_end`, and `tool_name`
|
|
50
|
+
filter rows), `lcm_describe` (inspect one summary without expanding
|
|
51
|
+
it), `lcm_expand` (read the originals a summary covers, `anchor` centers
|
|
52
|
+
the listing on one entry), and
|
|
48
53
|
`lcm_expand_query` (a bounded child session reads and answers, so the
|
|
49
54
|
originals never enter the parent's context).
|
|
50
55
|
|
|
@@ -58,12 +63,12 @@ originals never enter the parent's context).
|
|
|
58
63
|
}
|
|
59
64
|
```
|
|
60
65
|
|
|
61
|
-
`sidecarDir` holds one SQLite file per session (0700 dir, 0600 files
|
|
62
|
-
one to forget that session
|
|
63
|
-
and drops `/lossless-pass` and `lcm_expand_query`.
|
|
64
|
-
summarizer chain and budgets, heal window, reader timeout) lives on the
|
|
66
|
+
The example stores sidecars in the project. Without `sidecarDir`, the plugin uses the global auto-detected path, which holds sessions from every project. The [config reference](https://stainless-code.com/lossless/reference/opencode/config) lists the exact default paths. `sidecarDir` holds one SQLite file per session (0700 dir, 0600 files).
|
|
67
|
+
Delete one file to forget that session. `assembly: false` leaves compaction to the host
|
|
68
|
+
and drops `/lossless-pass` and `lcm_expand_query`. The
|
|
65
69
|
[config reference](https://stainless-code.com/lossless/reference/opencode/config)
|
|
66
|
-
|
|
70
|
+
documents every other key and its default: thresholds,
|
|
71
|
+
summarizer chain and budgets, heal window, and reader timeout.
|
|
67
72
|
|
|
68
73
|
## Verify
|
|
69
74
|
|
package/dist/index.d.mts
CHANGED
|
@@ -252,91 +252,44 @@ interface OpencodeContext {
|
|
|
252
252
|
readonly generate?: GenerateText;
|
|
253
253
|
readonly model?: ModelDomain;
|
|
254
254
|
}
|
|
255
|
-
/** Options read from the plugin's `plugins[].options` entry. Every field is
|
|
256
|
-
* optional; an unknown or malformed value keeps its default rather than
|
|
257
|
-
* failing the plugin load. */
|
|
258
255
|
interface OpencodeLosslessOptions {
|
|
259
|
-
/**
|
|
260
|
-
* the flag is absent, in which case listing the plugin is intent enough.
|
|
261
|
-
* @default true */
|
|
256
|
+
/** @default true */
|
|
262
257
|
readonly enabled?: boolean;
|
|
263
|
-
/**
|
|
264
|
-
* @default "./.lossless" (resolved from the server working directory) */
|
|
258
|
+
/** @default global sidecar dir, `./.lossless` only as fallback */
|
|
265
259
|
readonly sidecarDir?: string;
|
|
266
|
-
/**
|
|
267
|
-
* on-demand `lossless-pass` command. `false` leaves compaction to the host and
|
|
268
|
-
* registers only the mirror, the three recall tools, and the commands.
|
|
269
|
-
* @default true
|
|
260
|
+
/** @default true
|
|
270
261
|
* @example { assembly: false } */
|
|
271
262
|
readonly assembly?: boolean;
|
|
272
|
-
/**
|
|
273
|
-
* model; this host has no synchronous model lookup, so a concrete id falls
|
|
274
|
-
* back to the session model.
|
|
275
|
-
* @default "auto" */
|
|
263
|
+
/** @default "auto" */
|
|
276
264
|
readonly summarizer?: string | string[];
|
|
277
|
-
/**
|
|
278
|
-
* it is refused rather than paid for.
|
|
279
|
-
* @default 60000 */
|
|
265
|
+
/** @default 60000 */
|
|
280
266
|
readonly summarizerTokensPerCall?: number;
|
|
281
|
-
/**
|
|
282
|
-
* provider reported.
|
|
283
|
-
* @default 250000 */
|
|
267
|
+
/** @default 250000 */
|
|
284
268
|
readonly summarizerTokensPerPass?: number;
|
|
285
|
-
/**
|
|
286
|
-
* A dry run spends nothing.
|
|
287
|
-
* @default 120000 */
|
|
269
|
+
/** @default 120000 */
|
|
288
270
|
readonly summarizerTokensPerHeal?: number;
|
|
289
|
-
/**
|
|
290
|
-
|
|
291
|
-
|
|
271
|
+
/** @default [] */
|
|
272
|
+
readonly mechanicalTools?: readonly string[];
|
|
273
|
+
/** @default 0.7 */
|
|
292
274
|
readonly swapAtRatio?: number;
|
|
293
|
-
/**
|
|
294
|
-
* @default 0.85 */
|
|
275
|
+
/** @default 0.85 */
|
|
295
276
|
readonly recutAtRatio?: number;
|
|
296
|
-
/**
|
|
297
|
-
* place of `swapAtRatio`. The recut is derived from it.
|
|
298
|
-
* @default unset */
|
|
277
|
+
/** @default unset */
|
|
299
278
|
readonly smartZone?: number;
|
|
300
|
-
/** Per-model threshold overrides, keyed `provider/model`. */
|
|
301
279
|
readonly zones?: Readonly<Record<string, ThresholdConfig>>;
|
|
302
|
-
/**
|
|
303
|
-
* @default 20000 */
|
|
280
|
+
/** @default 20000 */
|
|
304
281
|
readonly keepRecentTokens?: number;
|
|
305
|
-
/**
|
|
306
|
-
* @default 1500 */
|
|
282
|
+
/** @default 1500 */
|
|
307
283
|
readonly summaryTokens?: number;
|
|
308
|
-
/**
|
|
309
|
-
* `8 * summaryTokens`, clamped to 3,000 through 24,000 and to
|
|
310
|
-
* `summarizerTokensPerCall`. It is a whole-node window, not a per-message
|
|
311
|
-
* clip. Raise it to repair summaries over unusually large source messages.
|
|
312
|
-
* @default 8 x summaryTokens, clamped 3000..24000 */
|
|
284
|
+
/** @default 8 x summaryTokens, clamped 3000..24000 */
|
|
313
285
|
readonly healSourceTokens?: number;
|
|
314
|
-
/**
|
|
315
|
-
* @default 128000 */
|
|
286
|
+
/** @default 128000 */
|
|
316
287
|
readonly contextWindow?: number;
|
|
317
|
-
/**
|
|
318
|
-
* @default 120000 */
|
|
288
|
+
/** @default 120000 */
|
|
319
289
|
readonly readerTimeoutMs?: number;
|
|
320
290
|
}
|
|
321
|
-
/** Wire lossless memory into an OpenCode v2 plugin context: mirror
|
|
322
|
-
* assistant text, tool traffic, and compaction boundaries into per-session
|
|
323
|
-
* sidecars, and register the recall tools plus the `/lossless-status`,
|
|
324
|
-
* `/lossless-report`, `/lossless-pass`, and `/lossless-heal` commands. With
|
|
325
|
-
* `assembly` (the default), also register the context projection and the blocking checkpoint
|
|
326
|
-
* (`session.compaction`); `/lossless-pass` runs one DAG pass over the session's
|
|
327
|
-
* stored span on demand. The host stops summarizing for itself once the sidecar
|
|
328
|
-
* covers the aged span: it stores the DAG frontier as its checkpoint, and the
|
|
329
|
-
* next request's projection continues from it. The sidecar keeps every address
|
|
330
|
-
* the reader can name. Resolves to the cleanup that unregisters everything and
|
|
331
|
-
* closes the sidecars. The context is the local structural subset
|
|
332
|
-
* (`./host.ts`), so the real host context flows in without the bundle naming
|
|
333
|
-
* the host SDK. `rawOptions` is validated at runtime; a malformed value
|
|
334
|
-
* degrades to defaults rather than throwing into the host load. */
|
|
291
|
+
/** Wire lossless memory into an OpenCode v2 plugin context: mirror traffic into per-session sidecars and register recall tools plus lifecycle commands. Resolves to the cleanup that unregisters everything and closes the sidecars. */
|
|
335
292
|
export declare function setupOpencodeLossless(ctx: OpencodeContext, rawOptions?: unknown): Promise<() => Promise<void>>;
|
|
336
|
-
/** The plugin definition the host loads. Options come from the config entry,
|
|
337
|
-
* so the default export reads them late, at setup time. The setup parameter
|
|
338
|
-
* is the local context subset; the host's richer context satisfies it, which
|
|
339
|
-
* `test/host-compat.test.ts` pins against the real host types. */
|
|
340
293
|
declare const definition: {
|
|
341
294
|
id: string;
|
|
342
295
|
setup: (ctx: OpencodeContext) => Promise<() => Promise<void>>;
|