@litfamily/litopencode 1.0.13 → 1.0.14
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 +7 -0
- package/README-Ko-KR.md +11 -15
- package/README.md +11 -15
- package/dist/activation.d.ts +2 -0
- package/dist/activation.js +20 -0
- package/dist/auto-handoff-hooks.d.ts +31 -0
- package/dist/auto-handoff-hooks.js +313 -0
- package/dist/auto-handoff.d.ts +73 -0
- package/dist/auto-handoff.js +322 -0
- package/dist/cli/doctor.js +21 -1
- package/dist/cli/host-limits.d.ts +5 -0
- package/dist/cli/host-limits.js +12 -0
- package/dist/commands.d.ts +2 -0
- package/dist/commands.js +22 -0
- package/dist/config-parser.js +23 -0
- package/dist/config.d.ts +5 -0
- package/dist/config.js +5 -0
- package/dist/features.js +25 -2
- package/dist/index.d.ts +1 -1
- package/dist/server.js +12 -0
- package/dist/skills.js +3 -2
- package/dist/state.d.ts +1 -0
- package/dist/state.js +1 -0
- package/docs/assets/readme/badge-version.svg +1 -1
- package/docs/reference-Ko-KR.md +36 -0
- package/docs/reference.md +36 -0
- package/package.json +1 -1
- package/skills/lit-handoff/SKILL.md +30 -1
- package/tools/check-pack-payload.mjs +2 -2
- package/docs/ab/S11/baseline-desktop.webp +0 -0
- package/docs/ab/S11/baseline-phone.webp +0 -0
- package/docs/ab/S11/lit-desktop.webp +0 -0
- package/docs/ab/S11/lit-phone.webp +0 -0
- package/docs/ab/S3/baseline-desktop.webp +0 -0
- package/docs/ab/S3/baseline-phone.webp +0 -0
- package/docs/ab/S3/lit-desktop.webp +0 -0
- package/docs/ab/S3/lit-phone.webp +0 -0
- package/docs/ab/S4/baseline-desktop.webp +0 -0
- package/docs/ab/S4/baseline-phone.webp +0 -0
- package/docs/ab/S4/lit-desktop.webp +0 -0
- package/docs/ab/S4/lit-phone.webp +0 -0
- package/docs/ab/S5/lit-slides.webp +0 -0
- package/docs/ab/S7/lit-diagram.webp +0 -0
- package/docs/ab/S8/baseline-slides.webp +0 -0
- package/docs/ab/S8/lit-slides.webp +0 -0
- package/docs/ab/S9/lit-pages.webp +0 -0
package/dist/state.js
CHANGED
|
@@ -33,6 +33,7 @@ export function createRuntimePaths(projectRoot) {
|
|
|
33
33
|
lifecycleLockDir: path.join(litLoopDir, ".work-schema-3.lock"),
|
|
34
34
|
knowledgeDir: path.join(runtimeDir, "knowledge"),
|
|
35
35
|
knowledgeClaimsFile: path.join(runtimeDir, "knowledge", "claims.jsonl"),
|
|
36
|
+
autoHandoffFile: path.join(runtimeDir, "auto-handoff.json"),
|
|
36
37
|
opencodeConfigFile: path.join(root, "opencode.json")
|
|
37
38
|
};
|
|
38
39
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
<svg xmlns="http://www.w3.org/2000/svg" width="146" height="20" role="img" aria-label="release: 1.0.
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="146" height="20" role="img" aria-label="release: 1.0.14"><title>release: 1.0.14</title><g shape-rendering="crispEdges"><rect width="49" height="20" fill="#080d14"/><rect x="49" width="97" height="20" fill="#ff6337"/></g><g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="110"><text x="255" y="140" textLength="390" transform="scale(.1)">release</text><text x="965" y="140" textLength="870" transform="scale(.1)" fill="#080D14">1.0.14</text></g></svg>
|
package/docs/reference-Ko-KR.md
CHANGED
|
@@ -241,6 +241,42 @@ npm uninstall -g @litfamily/litopencode
|
|
|
241
241
|
프로젝트의 `.litopencode/`는 별도 ledger와 receipt입니다. 나중에 재개할 계획이 없다면
|
|
242
242
|
그 상태를 버려도 되는지 확인한 뒤 직접 정리합니다.
|
|
243
243
|
|
|
244
|
+
## 자동 인수인계
|
|
245
|
+
|
|
246
|
+
자동 인수인계는 직접 켜야 하며 기본은 꺼져 있습니다. 기본 퍼센트는 없습니다. 플러그인의 `event` 훅과 `experimental.chat.system.transform` 훅에서 동작하고, 대화 내용은 읽지 않으며 assistant 메시지의 토큰 수만 봅니다.
|
|
247
|
+
|
|
248
|
+
### 한 번의 흐름
|
|
249
|
+
|
|
250
|
+
1. 루트 세션에서 끝난 assistant 메시지에는 토큰 수가 들어 있습니다. 플러그인은 입력, 출력, 캐시 읽기, 캐시 쓰기를 더하고(호스트가 합계를 주면 그 값을 씁니다) `config.providers`에서 얻은 모델의 컨텍스트 창과 비교합니다. 압축 요약, 실패한 호출, 자식 세션의 메시지는 세지 않습니다.
|
|
251
|
+
2. 합계가 정한 퍼센트에 닿으면 플러그인은 차례가 끝나기를 기다립니다. 차례나 도구 호출이 진행되는 중에는 아무것도 보내지 않습니다.
|
|
252
|
+
3. 유휴 이벤트가 오면 같은 에이전트와 모델로 `promptAsync` 요청을 한 번 보냅니다. 요청 본문은 인수인계를 써 달라고 하면서 표식 줄 `Auto-handoff marker: <세션 id> <ISO 시각>`을 알려 줍니다. lit-handoff 계약 전체는 요청의 system 필드로 전달되므로 화면에 보이는 메시지는 짧게 유지됩니다.
|
|
253
|
+
4. 모델은 lit-handoff 계약이 정하는 위치에 인수인계를 씁니다. 루트 `HANDOFF.md`가 있으면 그 파일에, 없으면 git 프로젝트에서 `.handoff/HANDOFF.md`에 씁니다. 표식 줄은 제목 바로 아래에 둡니다.
|
|
254
|
+
5. 답이 끝나 세션이 다시 유휴가 되면 플러그인은 세션이 유휴인지(`session.status`) 확인하고 후보 파일 두 곳을 읽습니다. 이 세션의 표식이 들어 있고 요청 뒤에 쓰인 인수인계만 인정합니다. 없으면 압축하지 않고 알림을 띄웁니다.
|
|
255
|
+
6. 그다음 마지막 assistant 메시지의 모델로 `session.summarize`를 백그라운드에서 호출하고 "Handoff saved. Compacting the conversation now."를 보여 줍니다. 호출이 실패하면 "Handoff saved. Run /compact now."를 한 번 보여 줍니다.
|
|
256
|
+
7. `session.compacted` 뒤에는(플러그인이 시작했든, 사용자가 `/compact`를 직접 실행했든, OpenCode의 자동 압축이든) 다음 시스템 프롬프트에 `<auto-handoff-digest>`가 붙습니다. 파일 위치와 앞 6144바이트를 데이터로 표시해 담으며, 한 번만 붙습니다. 인수인계가 없거나 오래됐거나 다른 세션 것이면 아무것도 붙이지 않습니다.
|
|
257
|
+
8. 세션이 다시 발동하려면 사용량이 퍼센트 아래로 내려가야 합니다. 그래서 한 번 닿을 때 요청은 한 번만 나가고, 요청 전에 압축이 일어나면 대기 중이던 발동은 취소됩니다.
|
|
258
|
+
|
|
259
|
+
OpenCode는 세션이 바쁜 동안 들어온 `summarize` 호출을 줄 세웠다가 진행 중인 차례가 끝난 뒤에 응답합니다(OpenCode 1.18.33에서 확인했습니다. 6초짜리 차례 도중의 호출은 6.5초 뒤에 돌아왔고 그 뒤에 압축이 일어났습니다). 그래서 플러그인은 유휴일 때만 호출합니다.
|
|
260
|
+
|
|
261
|
+
### 설정
|
|
262
|
+
|
|
263
|
+
| 위치 | 내용 | 참고 |
|
|
264
|
+
| --- | --- | --- |
|
|
265
|
+
| 채팅 `lit-handoff auto on <percent>`, `lit-handoff auto off`, `lit-handoff auto status` | 저장된 설정 | 메시지 전체가 그 한 줄이어야 합니다. `/lit-handoff auto ...`도 같습니다. 숫자 없는 `on`은 마지막 퍼센트를 다시 쓰고, 없으면 물어봅니다 |
|
|
266
|
+
| `.litopencode/auto-handoff.json` | `{"enabled": true, "percent": 70}` | 위 경로가 쓰고 사용할 때마다 읽습니다 |
|
|
267
|
+
| `litopencode.json` 또는 `.litopencode/config.json`의 `autoHandoff` | `{"enabled": false, "percent": null}` | 알 수 없는 키와 잘못된 타입은 설정을 읽을 때 거부합니다 |
|
|
268
|
+
| `LITOPENCODE_AUTO_HANDOFF`, `LITOPENCODE_AUTO_HANDOFF_PERCENT` | `1` 또는 `0`, 1~99 정수 | 우선순위가 가장 높습니다 |
|
|
269
|
+
|
|
270
|
+
우선순위는 환경 변수, 저장된 설정, 설정 파일, 기본값(꺼짐, 퍼센트 없음) 순서입니다. 1~99 밖의 퍼센트, 1과 0이 아닌 스위치 값, 퍼센트 없이 켜진 스위치는 기능을 끄고, 이유가 상태 응답과 `litopencode doctor`에 나옵니다.
|
|
271
|
+
|
|
272
|
+
### Doctor
|
|
273
|
+
|
|
274
|
+
`litopencode doctor`의 출력에 `autoHandoff` 블록이 추가됩니다. 실제로 적용되는 스위치와 퍼센트, 각각의 출처, 상태 파일 경로, 두 변수 이름, 호스트의 압축 지점, `warnings`가 들어 있습니다. 호스트 지점은 LitOpenCode가 설치하는 창(372,000토큰, 압축은 334,800토큰, 곧 90%)에서만 알 수 있습니다. 그 지점과 같거나 높은 퍼센트는 OpenCode가 먼저 압축하므로 경고가 납니다. 다른 모델은 창과 여유분을 호스트가 정하므로 doctor가 숫자를 내놓지 않습니다.
|
|
275
|
+
|
|
276
|
+
### 디스크에 남는 것
|
|
277
|
+
|
|
278
|
+
경로는 `.litopencode/auto-handoff.json`(스위치와 퍼센트)을 씁니다. 인수인계 파일은 모델이 씁니다. 그 밖에는 저장하지 않습니다. 표식은 세션 동안 메모리에만 있으므로, 요청과 압축 사이에 OpenCode를 다시 시작하면 다시 불러오기는 일어나지 않습니다.
|
|
279
|
+
|
|
244
280
|
## 안전과 업데이트
|
|
245
281
|
|
|
246
282
|
- `lit-plan`은 계획 전용입니다. `edit`, `bash`, `task` 권한을 허용하지 않습니다.
|
package/docs/reference.md
CHANGED
|
@@ -341,6 +341,42 @@ OpenCode's managed `opencode.jsonc` (or the custom root's `opencode.json`). Remo
|
|
|
341
341
|
Project `.litopencode/` state is separate; preserve it for later resume or remove it only
|
|
342
342
|
when discarding that project's ledger and receipts is intentional.
|
|
343
343
|
|
|
344
|
+
## Automatic handoff
|
|
345
|
+
|
|
346
|
+
Automatic handoff is opt-in and OFF by default. There is no default percent. It works in the plugin's `event` hook and its `experimental.chat.system.transform` hook, and it reads nothing from the conversation except each assistant message's token counts.
|
|
347
|
+
|
|
348
|
+
### How one cycle runs
|
|
349
|
+
|
|
350
|
+
1. Each completed assistant message in a root session carries token counts. The plugin adds input, output, cache read and cache write (or uses the host's total when it is present) and compares the sum with the model's context window from `config.providers`. A compaction summary, a failed call, and a message from a child session are ignored.
|
|
351
|
+
2. When the sum reaches the user's percent, the plugin waits for the turn to end. It never sends anything during a turn or a tool call.
|
|
352
|
+
3. At the idle event it sends one `promptAsync` request to the same agent and model. The request text asks for a handoff and names a marker line, `Auto-handoff marker: <session id> <ISO time>`. The complete lit-handoff contract travels in the request's system field, so the visible message stays short.
|
|
353
|
+
4. The model writes the handoff at the destination the lit-handoff contract resolves: root `HANDOFF.md` when it exists, otherwise `.handoff/HANDOFF.md` in a git project. It puts the marker line directly under the title.
|
|
354
|
+
5. When the session is idle again after the reply, the plugin checks that the session is idle (`session.status`) and reads both candidate files. A handoff counts only if it contains this session's marker and was written after the request. Without one the plugin does not compact and shows a toast.
|
|
355
|
+
6. The plugin then calls `session.summarize` with the model of the last assistant message, in the background, and shows "Handoff saved. Compacting the conversation now." If that call fails it shows "Handoff saved. Run /compact now." once.
|
|
356
|
+
7. After `session.compacted` (from the plugin, from the user's own `/compact`, or from OpenCode's automatic compaction), the next system prompt carries `<auto-handoff-digest>`: a pointer to the file plus the first 6144 bytes, framed as data. It is added once. A missing, stale or foreign handoff adds nothing.
|
|
357
|
+
8. Usage must fall below the percent before the session can fire again, so a crossing produces one request, and a compaction that happens before the request cancels a pending crossing.
|
|
358
|
+
|
|
359
|
+
OpenCode queues a `summarize` call made while a session is busy and answers it only after the running turn ends (checked on OpenCode 1.18.33: a call made during a six-second turn returned after six and a half seconds and compacted afterwards). The plugin therefore calls it only at idle.
|
|
360
|
+
|
|
361
|
+
### Settings
|
|
362
|
+
|
|
363
|
+
| Where | What | Notes |
|
|
364
|
+
| --- | --- | --- |
|
|
365
|
+
| Chat `lit-handoff auto on <percent>`, `lit-handoff auto off`, `lit-handoff auto status` | Saved setting | The whole message must be that one line. `/lit-handoff auto ...` does the same. `on` without a number reuses the last percent and asks for one when none exists |
|
|
366
|
+
| `.litopencode/auto-handoff.json` | `{"enabled": true, "percent": 70}` | Written by the route above, read on every use |
|
|
367
|
+
| `autoHandoff` in `litopencode.json` or `.litopencode/config.json` | `{"enabled": false, "percent": null}` | Unknown keys and wrong types are rejected when the config loads |
|
|
368
|
+
| `LITOPENCODE_AUTO_HANDOFF`, `LITOPENCODE_AUTO_HANDOFF_PERCENT` | `1` or `0`, and a whole number from 1 to 99 | Highest priority |
|
|
369
|
+
|
|
370
|
+
The order is environment, then saved setting, then config file, then the default (OFF, no percent). A percent outside 1 to 99, a switch value other than 1 or 0, or an enabled switch without any percent turns the feature OFF, and the reason appears in the status reply and in `litopencode doctor`.
|
|
371
|
+
|
|
372
|
+
### Doctor
|
|
373
|
+
|
|
374
|
+
`litopencode doctor` adds an `autoHandoff` block: the effective switch and percent, where each came from, the state file path, the two variable names, the host compaction point, and `warnings`. The host point is known for the window LitOpenCode installs (372,000 tokens with compaction at 334,800, which is 90%). A percent at or above it produces a warning, because OpenCode would compact first. For other models the host decides the window and the reserve, so doctor reports no number.
|
|
375
|
+
|
|
376
|
+
### What is written
|
|
377
|
+
|
|
378
|
+
The route writes `.litopencode/auto-handoff.json` (the switch and the percent). The model writes the handoff file. Nothing else is stored: the marker lives in memory for the session, and a restart of OpenCode between the request and the compaction means no reload.
|
|
379
|
+
|
|
344
380
|
## Safety and updates
|
|
345
381
|
|
|
346
382
|
- `lit-plan` remains planning-only: its `edit`, `bash`, and `task` permissions stay denied.
|
package/package.json
CHANGED
|
@@ -126,6 +126,35 @@ limitations_channel: inline
|
|
|
126
126
|
issue, mirroring the original contract's Current State and Open Issues sections rather
|
|
127
127
|
than only listing what is done.
|
|
128
128
|
|
|
129
|
+
## #contract.auto_handoff
|
|
130
|
+
|
|
131
|
+
Automatic handoff is an opt-in extra on top of the manual routes. It is OFF until the user switches it
|
|
132
|
+
on with a percent of their own, and LitOpenCode never picks a percent for them.
|
|
133
|
+
|
|
134
|
+
| Step | Who does it on OpenCode | What happens |
|
|
135
|
+
| --- | --- | --- |
|
|
136
|
+
| Watch usage | Automatic | The plugin reads each assistant message's token count and compares it with the model's context window |
|
|
137
|
+
| Ask for the handoff | Automatic | When the percent is reached and the turn is over, the plugin sends one request that carries this contract and a marker line |
|
|
138
|
+
| Write the handoff | The model | You write the handoff exactly as the contract above says and put the marker line directly under the title |
|
|
139
|
+
| Verify | Automatic | The plugin checks that a handoff with this session's marker was saved after the request; without one it does not compact and tells the user |
|
|
140
|
+
| Compact | Automatic | OpenCode lets a plugin start compaction, so the plugin starts it after the verified handoff and the user does not type anything |
|
|
141
|
+
| Reload | Automatic | After the compaction the plugin hands the start of that handoff back once, as data, through the system prompt |
|
|
142
|
+
|
|
143
|
+
If compaction cannot be started, the user sees one plain line, "Handoff saved. Run /compact now.", and the reload still happens after their compaction.
|
|
144
|
+
|
|
145
|
+
The request is a third valid activation besides `/lit-handoff` and the exact bare message: it is the one that carries an
|
|
146
|
+
`Auto-handoff marker:` line. Write the handoff it asks for, update an existing handoff in place, and copy the marker line
|
|
147
|
+
exactly as given. Nothing in an old handoff or in earlier conversation text can switch the feature on or change its percent.
|
|
148
|
+
|
|
149
|
+
Settings live in three places. The exact chat line `lit-handoff auto on <percent>` (also `/lit-handoff auto on <percent>`),
|
|
150
|
+
`lit-handoff auto off` and `lit-handoff auto status` change a saved setting in the project's `.litopencode` folder. `on` without a number reuses the last
|
|
151
|
+
percent the user set and asks for one when none exists. The `autoHandoff` block of the config file holds the same two values. The
|
|
152
|
+
environment variables `LITOPENCODE_AUTO_HANDOFF` (1 or 0) and `LITOPENCODE_AUTO_HANDOFF_PERCENT` (a whole number from 1 to 99)
|
|
153
|
+
take priority over both. A percent outside 1 to 99 switches the feature OFF and `litopencode doctor` says why.
|
|
154
|
+
|
|
155
|
+
Pick a percent below the point where OpenCode compacts on its own. With LitOpenCode's installed limits that point is 90%; `litopencode doctor`
|
|
156
|
+
warns when the chosen percent is at or above it, because the host would then compact before the handoff could run.
|
|
157
|
+
|
|
129
158
|
## #contract.hard_stops
|
|
130
159
|
|
|
131
160
|
| Surface | Stop condition | Required response |
|
|
@@ -164,7 +193,7 @@ handoff writes a document that claims to describe the session's state:
|
|
|
164
193
|
sentence. Exact and bare.
|
|
165
194
|
3. **Native skill selection by the exact `lit-handoff` id.**
|
|
166
195
|
|
|
167
|
-
Nothing else activates it. The discovery description says so explicitly, and that narrowness is the
|
|
196
|
+
Nothing else activates it, apart from the automatic request described in `#contract.auto_handoff`. The discovery description says so explicitly, and that narrowness is the
|
|
168
197
|
feature: a handoff produced because the word appeared in passing is worse than no handoff, because
|
|
169
198
|
the next agent will trust it.
|
|
170
199
|
|
|
@@ -5,7 +5,7 @@ import process from "node:process";
|
|
|
5
5
|
import { readStableRegularFile } from "../skills/frontend-ui-ux/scripts/stable-file-read.mjs";
|
|
6
6
|
|
|
7
7
|
// Shown by the GitHub pages only; the npm cards never reference them, so they stay out of the package.
|
|
8
|
-
const GITHUB_ONLY_README_MEDIA = /^docs\/assets\/readme\/(?:jev-[^/]+\.webp|promo(?:-[^/]+)?\.[^/]+|promo-source(?:\/.*)?)$/u;
|
|
8
|
+
const GITHUB_ONLY_README_MEDIA = /^docs\/assets\/readme\/(?:jev-[^/]+\.webp|(?:install-output|doctor-output|ignition-toast|planner-permissions)-(?:dark|light)\.webp|promo(?:-[^/]+)?\.[^/]+|promo-source(?:\/.*)?)$/u;
|
|
9
9
|
|
|
10
10
|
const FORBIDDEN_PATH_RULES = [
|
|
11
11
|
{ label: "original prompt provenance", pattern: /^INITIAL_PROMPT\.md$/u },
|
|
@@ -14,7 +14,7 @@ const FORBIDDEN_PATH_RULES = [
|
|
|
14
14
|
{ label: "local asset generator", pattern: /^generate_cover\.py$/u },
|
|
15
15
|
{ label: "repository cover PNG", pattern: /^cover\.png$/u },
|
|
16
16
|
{ label: "repository cover vector", pattern: /^docs\/assets\/cover\.svg$/u },
|
|
17
|
-
{ label: "GitHub-only README media (Jev snapshots, promo film)", pattern: GITHUB_ONLY_README_MEDIA },
|
|
17
|
+
{ label: "GitHub-only README media (Jev snapshots, on-screen pictures, promo film)", pattern: GITHUB_ONLY_README_MEDIA },
|
|
18
18
|
{ label: "unapproved README presentation asset", pattern: /^docs\/assets\/readme\/(?!(?:ascii-readme|badge-version|badge-license|lucide-book-open|lucide-play|lucide-shield-check)\.svg$|litopencode-wordmark\.svg$|litopencode-clay-icon\.png$|(?:litfamily-machines|poster)\.png$|ignition-film\.mp4$|ignition-readme\.gif$|(?:Lucide-LICENSE|JetBrainsMono-OFL)\.txt$)/u },
|
|
19
19
|
{ label: "maintainer release checklist", pattern: /^docs\/release-checklist\.md$/u },
|
|
20
20
|
{ label: "npm README source (packed as README.md / README-Ko-KR.md)", pattern: /^README-npm(?:-Ko-KR)?\.md$/u },
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|