@lawaty/lacode 1.0.3 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -7,6 +7,105 @@ All notable changes to LaCode are recorded here. The format follows
7
7
  Versions come from git release commits; the npm version is bumped in the same
8
8
  commit as the changelog entry it describes.
9
9
 
10
+ ## [1.2.0] — voice, a per-session timeline, and a pool without a cap
11
+
12
+ ### Added
13
+
14
+ - **Voice control for the TUI.** `lacode-voice` runs a local daemon that captures
15
+ audio, transcribes it through Groq, and forwards prompts to the TUI over a
16
+ loopback-only control socket. Wake-word detection is optional: the Vosk and
17
+ Porcupine engines, the recorder and the audio capture path each degrade
18
+ gracefully when their native dependency, key or device is missing. The daemon,
19
+ transport and audio code live in `src/voice/`; the TUI is published as the
20
+ `./tui` export.
21
+ - **A per-session timeline.** `src/plugins/timeline.ts` summarizes a session's
22
+ transcript into an append-only JSONL file under
23
+ `~/.local/share/opencode/lacode/timeline/`, and `/reprocess-timeline` rebuilds
24
+ it from the full transcript through the `timeline_reprocess` tool. Internal
25
+ summarizer sessions stay out of notifications.
26
+ - **`npm run score`** probes every cost-zero model the configured providers
27
+ serve, scores context, output, speed and reliability, and suggests a pool
28
+ order. Results are written to `~/.config/lacode/model-scores.json`.
29
+
30
+ ### Changed
31
+
32
+ - **BREAKING: Slot routing is one pass, and the four-slot cap is gone.** A
33
+ slot's `weight` is now its cap, not half of a two-pass budget: the pool fills
34
+ each slot to its weight in declaration order in one pass, then overflows to the
35
+ least-loaded slot. Every line is a slot, and a model may repeat — each line
36
+ adds seats at its position. A preset tuned for the old two-pass behaviour sees
37
+ roughly half the concurrency it did before; to restore it, double the weights
38
+ or list a model again.
39
+ - **The pool hot-reloads a bucket-only edit.** Changing only a slot's `b:` bucket
40
+ now counts as a change and re-validates the table.
41
+ - **A stated `Retry-After` is honoured up to six hours**, instead of being
42
+ clamped to the fifteen-minute backoff cap.
43
+
44
+ ### Fixed
45
+
46
+ - **A voice daemon shutdown waits for the transcription in flight**, and manual
47
+ recording is bounded at two minutes instead of growing without limit.
48
+ - **The voice control socket stays on loopback** unless a non-local bind is
49
+ explicitly opted into, and the wake engine treats an empty environment value
50
+ as unset.
51
+ - **The timeline strips terminal control sequences** before rendering model
52
+ output, and shares its session state across a double-loaded plugin.
53
+
54
+ ## [1.1.0] — a map contract, feedback, and host credential sync
55
+
56
+ ### Added
57
+
58
+ - **A one-time feedback hint, the `lacode feedback` command, and GitHub issue
59
+ templates.** The hint is local only: no telemetry, no analytics, and it sends
60
+ nothing anywhere. It shows at most once, only when a TUI sink exists, and a
61
+ toast that fails does not consume it. Opt out with `feedbackHint: false` or
62
+ `LACODE_NO_FEEDBACK_HINT=1`; the flag is
63
+ `~/.local/share/opencode/lacode/feedback.json`.
64
+ - **The post-publish host sync now syncs provider credentials.** After
65
+ `npm publish`, `scripts/sync-hosts.mjs` copies the allowlisted providers from
66
+ the local opencode auth store (`OC_AUTH_PROVIDERS`, default
67
+ `opencode-go opencode`) to each host, keeps host-only providers, and writes
68
+ the remote `auth.json` atomically with a timestamped backup.
69
+
70
+ ### Changed
71
+
72
+ - **The context map has one entry schema, a per-file budget and a per-file
73
+ lifecycle.** Every navigation entry is a provenance marker (`[binding]`,
74
+ `[provisional]` or `[disputed]`), a rule of at most three non-blank lines, and
75
+ a `— See <path>[ §Section] (verified YYYY-MM-DD)` pointer. No Context /
76
+ Decision / Consequences / Alternatives blocks. Every file has a hard cap in
77
+ non-blank lines (architecture 150, contexts 200, conventions 150, workflows
78
+ 150, decisions 120, active 60). The 30-day provisional window generalises the
79
+ active backlog's 7-day finished-task window; binding and disputed entries are
80
+ exempt, and an entry whose source is gone is never auto-dropped.
81
+ - **The prompt now lives in `src/lib/cartographer-prompt.ts`,** with the tracked
82
+ copy at `.opencode/prompts/context.txt`; a test pins equality so a reviewer
83
+ reads the text the model actually runs.
84
+
85
+ ### Fixed
86
+
87
+ - **`LACODE_SYNC_DRY_RUN=1` no longer contacts a host.** It used to print the
88
+ plan and then SSH to every host to exercise the credential helper when a local
89
+ auth store existed, which sent provider credentials during a “dry run”. It now
90
+ reads only the local plan and prints the auth summary; no SSH and no `npm view`.
91
+ - **The post-publish host sync accepts a real `opencode.jsonc`.** Comments and
92
+ trailing commas no longer make a host fail as “config not normalized
93
+ (unparseable)”.
94
+ - **A constraints file is no longer a deliberation ledger.** `decisions.md` is
95
+ capped, decision-record blocks are a schema violation, and the prompt tells
96
+ the cartographer to state the constraint and point at the page that owns it.
97
+ - **Restatement and drift are now reported instead of silently trusted.** After
98
+ every run the map is audited for dangling paths/sections, a numeric claim
99
+ absent from its cited source, a possible negation conflict, a source modified
100
+ after `verified`, tables/fenced blocks/verbatim spans, duplicate rules,
101
+ archive-of-record language and charter degeneration. The audit is
102
+ **report-only**: it never rewrites a claim and never deletes content with no
103
+ source, because the map may be the only copy and the page may be the stale
104
+ side. A failure is a loud `context map validation failed` error.
105
+ - **The lifecycle no longer belongs to one file.** `active.md` still uses its
106
+ seven-day finished-task window; every other file now expires provisional
107
+ entries after 30 days, and only when the cited source still resolves.
108
+
10
109
  ## [1.0.3] — one notification even when the plugin is loaded twice
11
110
 
12
111
  ### Fixed
@@ -820,7 +919,9 @@ experimental; `latest` remains 0.4.2.
820
919
 
821
920
  - First published release: pooled subagents over a shared set of models.
822
921
 
823
- [Unreleased]: https://github.com/lawaty/lacode/compare/v1.0.0...HEAD
922
+ [Unreleased]: https://github.com/lawaty/lacode/compare/v1.2.0...HEAD
923
+ [1.2.0]: https://github.com/lawaty/lacode/compare/v1.1.0...v1.2.0
924
+ [1.1.0]: https://github.com/lawaty/lacode/compare/v1.0.0...v1.1.0
824
925
  [1.0.0]: https://github.com/lawaty/lacode/compare/v0.11.0...v1.0.0
825
926
  [0.11.0]: https://github.com/lawaty/lacode/compare/v0.10.0...v0.11.0
826
927
  [0.10.0]: https://github.com/lawaty/lacode/compare/v0.9.0...v0.10.0
package/README.md CHANGED
@@ -104,6 +104,23 @@ In a repository with no `.opencode/context/` yet, the first session builds it in
104
104
  the background; `/context-init` forces it, and [Context map](#context-map)
105
105
  explains what it is for.
106
106
 
107
+ ## Feedback
108
+
109
+ The feedback path has no telemetry and no analytics — it sends nothing anywhere
110
+ — but I would still like to hear from you.
111
+
112
+ - **Bug or feature request?** [Open an issue](https://github.com/lawaty/lacode/issues).
113
+ - **Question, or want to say how you use it?** [Start a discussion](https://github.com/lawaty/lacode/discussions).
114
+ - **Found it useful?** A ⭐ on [the repo](https://github.com/lawaty/lacode) helps
115
+ other people find it.
116
+
117
+ `lacode feedback` prints both links. The one-time hint that points at the issue
118
+ tracker is opt-out: set `feedbackHint: false` in the plugin options, or
119
+ `LACODE_NO_FEEDBACK_HINT=1` in the environment. It is shown at most once, only
120
+ when there is a TUI to show it in; piped, CI and test runs leave the flag
121
+ untouched. A toast that fails does not consume the note, so a later interactive
122
+ run can still show it.
123
+
107
124
  ## Configure
108
125
 
109
126
  Plugin options are a tuple — the package name, then an options object. Every
@@ -128,11 +145,12 @@ option is optional:
128
145
  | Option | Default | Meaning |
129
146
  | --- | --- | --- |
130
147
  | `enabled` | `true` | The single off switch. `false` injects nothing at all and does no writes. |
131
- | `models` | — | An inline slot list. Highest-priority source. |
148
+ | `models` | — | An inline slot list; `weight` is that line's budget and cap, a model may repeat, and there is no slot cap. Highest-priority source. |
132
149
  | `modelsFile` | — | An explicit slot file; short-circuits the [resolution chain](docs/CONFIGURATION.md#pool-preset-resolution). |
133
150
  | `reapMs` | `30000` | Hang-reaper interval. |
134
151
  | `probeMs` | `900000` | How often benched models are checked by actually using them. `0` turns the periodic check off and leaves the `pool_recheck` tool as the only way to ask. |
135
152
  | `selfUpdate` | `true` | Check for a newer release at most once per ~6h and install it in the background; it applies on the next opencode start. `false` — or `LACODE_NO_SELFUPDATE=1` — turns the check off. |
153
+ | `feedbackHint` | `true` | Show the one-time feedback note on the first interactive run. `false` — or `LACODE_NO_FEEDBACK_HINT=1` — turns it off. The flag lives in `~/.local/share/opencode/lacode/feedback.json`; nothing is sent anywhere. |
136
154
  | `sound` | `true` | Play a short tone with each notification, one per outcome, so you can tell a finished session from a question or a permission prompt without reading the popup. It is opt-out: `false` — or `LACODE_SOUND=0` (`false`, `off`, `no` work too, and beat the option) — turns the sound off, and anything else, a typo included, leaves it on. |
137
155
  | `omniroute` | — | Optional [OmniRoute](docs/OMNIROUTE.md) gateway integration. Absent or `{ enabled: false }` changes nothing. |
138
156
  | `watchMs` | `1000` | How often the pool files are checked for changes. `0` disables live reload. |
@@ -195,11 +213,17 @@ When it reports `stale`, rebuild with `npm run build`. No network is touched;
195
213
  ## What you get
196
214
 
197
215
  Three pooled agents: `explore`, `implement` and `context`. You spawn the base
198
- name and the pool picks a cheap model slot for it. Behind each base sits up to
199
- four hidden variants — one per slot — and a spawn of the bare name is the only
200
- thing that works: a hand-named variant such as `explore-1` is coerced to its
201
- base and routed by the pool, so naming one cannot pin a provider or skip
202
- ordered slot filling.
216
+ name and the pool picks a cheap model slot for it. Behind each base sits one
217
+ hidden variant per slot — however many the pool declares — and a spawn of the
218
+ bare name is the only thing that works: a hand-named variant such as `explore-1`
219
+ is coerced to its base and routed by the pool, so naming one cannot pin a
220
+ provider or skip ordered slot filling.
221
+
222
+ A slot's `weight` is both its concurrency budget and its cap: the pool fills
223
+ slots in declaration order in one pass, then overflows to the least-loaded slot.
224
+ There is no slot cap, and a model may appear on more than one line — each line
225
+ is a separate slot with its own weight — so to give a model more capacity, list
226
+ it again.
203
227
 
204
228
  A model that rate-limits or runs out of quota is benched until its window ends,
205
229
  so one sick provider does not take the pool with it.
@@ -217,9 +241,9 @@ serve at all is benched for the quota cap and named in the report.
217
241
  A change is reported as a toast and a log line; a pass that finds nothing changed says
218
242
  nothing at all.
219
243
 
220
- Nine commands: `/context-init`, `/context-update`, `/context-review`,
221
- `/lacode-doctor`, `/agent-instructions`, `/pool`, `/pool-recheck`, `/image-in-cb`
222
- and `/image`. Everything is added **only when your config does not already
244
+ Ten commands: `/context-init`, `/context-update`, `/context-review`,
245
+ `/lacode-doctor`, `/agent-instructions`, `/pool`, `/pool-recheck`,
246
+ `/reprocess-timeline`, `/image-in-cb` and `/image`. Everything is added **only when your config does not already
223
247
  define it** — an agent or command you wrote yourself is left byte-identical,
224
248
  never patched or partially merged. `{"enabled": false}` turns the whole thing off
225
249
  without leaving a trace. The exact injection list, and the five keys that are
@@ -373,6 +397,12 @@ to emit a number they cannot derive — an unpriced model reports `unknown`, nev
373
397
  `0`. How the two modes differ is in [docs/BENCHMARKS.md](docs/BENCHMARKS.md),
374
398
  which explains the harness and deliberately contains no results.
375
399
 
400
+ `npm run score` is the other measurement: it probes each configured provider's
401
+ free models with one tiny request and ranks them by measured latency, context and
402
+ output limit. It prints a suggested `pool.txt` but never edits it, and writes the
403
+ raw rows to `~/.config/lacode/model-scores.json`. Run it every few days — free
404
+ models and quota windows move.
405
+
376
406
  ## Remote hosts
377
407
 
378
408
  Notifications raised on a remote host need a way back to your desktop. The
@@ -393,12 +423,13 @@ and **Deny**, and macOS gets a plain notice without buttons.
393
423
  `lacode forward HOST -- COMMAND` runs a command on another host over ssh and
394
424
  exits with its status.
395
425
 
396
- The full CLI is `notify`, `forward`, `doctor`, `version`, `update`, `receive`
397
- and `tunnel setup`. `version` reports which copy of LaCode is running — and
398
- whether opencode is loading that same copy — and `update [--check]` refreshes an
399
- installed one. `receive` is the desktop end of the tunnel (the forced command a
400
- remote key is restricted to) and `tunnel setup` provisions the key and the
401
- forward.
426
+ The full CLI is `notify`, `forward`, `doctor`, `feedback`, `version`, `update`,
427
+ `receive` and `tunnel setup`. `version` reports which copy of LaCode is running —
428
+ and whether opencode is loading that same copy — and `update [--check]` refreshes
429
+ an installed one. `feedback` prints the Issues and Discussions links; it opens
430
+ nothing and sends nothing. `receive` is the desktop end of the tunnel (the forced
431
+ command a remote key is restricted to) and `tunnel setup` provisions the key and
432
+ the forward.
402
433
 
403
434
  Configuration, the payload format, the receiver contract and holding the forward
404
435
  open are in [docs/TUNNEL.md](docs/TUNNEL.md).
@@ -426,6 +457,7 @@ want it.
426
457
  npm run build # esbuild -> dist/ (what the tarball ships)
427
458
  npm test # node --test tests/ — offline, no network, no running server
428
459
  npm run benchmark # the cost harness; see docs/BENCHMARKS.md
460
+ npm run score # rank free models by context, output and measured latency
429
461
  ```
430
462
 
431
463
  Node ≥ 22.18.