@litfamily/litopencode 1.0.18 → 1.0.20
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 +14 -0
- package/README-Ko-KR.md +56 -86
- package/README.md +57 -86
- package/dist/activation-routing.js +3 -1
- package/dist/cli/args.js +5 -1
- package/dist/cli/auto-update.js +1 -1
- package/dist/cli/doctor.js +7 -5
- package/dist/cli/host-limits.js +2 -5
- package/dist/cli/install-config.d.ts +4 -0
- package/dist/cli/install-config.js +27 -1
- package/dist/cli/install-report.js +4 -1
- package/dist/cli/install.js +89 -28
- package/dist/cli/json.d.ts +1 -0
- package/dist/cli/json.js +10 -4
- package/dist/cli/jsonc.d.ts +17 -0
- package/dist/cli/jsonc.js +174 -0
- package/dist/cli/loop.d.ts +1 -1
- package/dist/cli/loop.js +81 -1
- package/dist/cli/motion-runtime.d.ts +13 -1
- package/dist/cli/motion-runtime.js +89 -2
- package/dist/cli/plugin-mutation.js +11 -6
- package/dist/cli/tui-config.d.ts +52 -0
- package/dist/cli/tui-config.js +198 -0
- package/dist/cli/types.d.ts +4 -0
- package/dist/cli.js +8 -3
- package/dist/deliverable-hedge-guard.js +2 -2
- package/dist/tui/mission-band.d.ts +47 -0
- package/dist/tui/mission-band.js +290 -0
- package/dist/tui/mission-model.d.ts +139 -0
- package/dist/tui/mission-model.js +318 -0
- package/dist/tui/mission-motion.d.ts +66 -0
- package/dist/tui/mission-motion.js +147 -0
- package/dist/tui/mission-skills.d.ts +38 -0
- package/dist/tui/mission-skills.js +81 -0
- package/dist/tui/mission-source.d.ts +68 -0
- package/dist/tui/mission-source.js +112 -0
- package/dist/tui/mission-text.d.ts +106 -0
- package/dist/tui/mission-text.js +613 -0
- package/dist/tui.d.ts +6 -0
- package/dist/tui.js +342 -0
- package/docs/assets/readme/badge-version.svg +1 -1
- package/docs/reference-Ko-KR.md +91 -1
- package/docs/reference.md +100 -1
- package/package.json +21 -2
- package/skills/lit-pptx/scripts/lib/template-registry.js +1 -1
- package/skills/lit-pptx/templates/tonalities/atlas/pack.yaml +0 -6
- package/skills/lit-pptx/templates/tonalities/chalk/pack.yaml +0 -6
- package/skills/lit-pptx/templates/tonalities/gazette/pack.yaml +0 -6
- package/skills/lit-pptx/templates/tonalities/ledger/pack.yaml +0 -6
- package/skills/lit-pptx/templates/tonalities/night/pack.yaml +0 -6
- package/skills/lit-pptx/templates/tonalities/paper/pack.yaml +0 -6
- package/skills/lit-pptx/templates/tonalities/signal/pack.yaml +0 -6
- package/skills/lit-pptx/templates/tonalities/studio/pack.yaml +0 -6
- package/skills/managed-skill-manifest.json +9 -9
- package/tools/check-pack-payload.mjs +20 -5
- package/tools/version-manifests.json +18 -6
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,20 @@ are tracked separately from this product history.
|
|
|
5
5
|
|
|
6
6
|
## Unreleased
|
|
7
7
|
|
|
8
|
+
## 1.0.20 - 2026-10-12
|
|
9
|
+
|
|
10
|
+
- The band along the bottom of OpenCode's main screen is now a small card that stays on screen for the whole session. The top edge shows LIT, the current workflow and its phase. The first row shows PLAN ━ WORK ━ REVIEW with the goal and the next task. The second row shows a chip for each LitOpenCode skill that ran: skills used by the current request are bright and get a short shine as they appear, then dim into a recent list when the answer is done, and extra chips fold into `+N`. The bottom edge shows context use, elapsed time and the git branch. Before you use lit in a session, the card shows the project's last goal. `band: false` still hides it and `band: { card: true }` still adds the detail card.
|
|
11
|
+
|
|
12
|
+
## 1.0.19 - 2026-10-11
|
|
13
|
+
|
|
14
|
+
- The README is shorter for first-time readers. It says what LitOpenCode does, how to install it and what to type first, and the detail now lives in docs pages (guide, skills, screens and brand) in English and Korean. The GitHub page also plays a short film of a real session.
|
|
15
|
+
- A lit mission now shows in OpenCode's TUI. A pill chip sits by the prompt, a rounded sidebar panel carries the phase and a smooth progress bar, a band runs along the bottom of the main screen, the home screen shows a line for the last mission, and a finished mission gets a short completion moment. In the plugin's `tui.json` options, `band: false` turns the band off and `band: { card: true }` adds a card under it with the warnings, the next task and the goal.
|
|
16
|
+
- Install adds the TUI plugin to `tui.json` or `tui.jsonc` and backs the file up first, and `litopencode tui remove` takes it out again. Auto-update backs up these files with the rest of the install and puts them back when an update fails.
|
|
17
|
+
- Install and doctor read a commented `opencode.jsonc` safely. They accept comments, trailing commas, a BOM and CRLF line endings, and an edit keeps every comment. When a comment sits inside an entry that has to change, install stops before writing anything and prints the entry to add by hand. A second install from a local checkout no longer adds a duplicate plugin entry.
|
|
18
|
+
- A prompt such as "lit turn notes.md into a 10-slide deck" now loads the office skills: lit-pptx for a deck and lit-docx for a Word report. The dot in a file name no longer breaks the match.
|
|
19
|
+
- The prose check that runs before a write now skips YAML, JSON and CSV files, so a line such as `source:` in a config file no longer blocks the write.
|
|
20
|
+
- `--dry-run` writes nothing. Loop commands that change the ledger list the files they would touch, and `motion-runtime` refuses an unknown option before it downloads anything.
|
|
21
|
+
|
|
8
22
|
## 1.0.18 - 2026-10-09
|
|
9
23
|
|
|
10
24
|
- The prose check that runs before a file is written now works inside OpenCode. It used to start under OpenCode's own program instead of Node and to look for the new text in the wrong place, so it never saw a write. It now stops an added line such as an unrequested source label before the file is saved, adds a short note after the write when the wording only needs a second look, and checks the text of the Word, PowerPoint and PDF files a session creates.
|
package/README-Ko-KR.md
CHANGED
|
@@ -1,120 +1,90 @@
|
|
|
1
|
-
<p align="center"><picture><source media="(prefers-reduced-motion: reduce)" srcset="https://cdn.jsdelivr.net/npm/@litfamily/litopencode@1.0.
|
|
2
|
-
|
|
3
|
-
<p align="center"><img src="https://cdn.jsdelivr.net/npm/@litfamily/litopencode@1.0.18/docs/assets/readme/ascii-readme.svg" width="480" alt="LIT ASCII B 마크" /></p>
|
|
4
|
-
|
|
5
|
-
<details>
|
|
6
|
-
<summary>ASCII 로고 복사</summary>
|
|
7
|
-
|
|
8
|
-
```text
|
|
9
|
-
▄▄▄▄
|
|
10
|
-
▗███▌ ▗██████▖
|
|
11
|
-
▗▄▄▄▄▄ ▗▟████▌ ▝██████▘
|
|
12
|
-
▐█████ ▗▟██████▌ ▝▀▜█▀▘
|
|
13
|
-
▐█████ ▗▟███████▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
|
|
14
|
-
▐█████ ▗▟█████████████████████████ ▐█▀
|
|
15
|
-
▐█████ ████████████████████████████▀
|
|
16
|
-
▐█████ ██▛▘ ▄ ▄▄▄▄▖▄▄▄▄▄▄▄▄▄▄▄▄▄▖
|
|
17
|
-
▐█████ ▀ ▄██ ████▌█████████████▌
|
|
18
|
-
▐█████ ▄████ ████▌█████████████▌
|
|
19
|
-
▐█████ ▄█████▛ litopencode
|
|
20
|
-
▐█████ ▗▟█████▀▘ ▄▄▄▄▄ ▗▖
|
|
21
|
-
▐█████ ▐█████▀ █████ ▐▛▀
|
|
22
|
-
▐█████ ▐███▀ █████
|
|
23
|
-
▐█████ ▐█▀ █████
|
|
24
|
-
▐█████ ▝ █████
|
|
25
|
-
▐█████▄▄▄▄▄▄▄▖ █████
|
|
26
|
-
▐███████████▛ █████
|
|
27
|
-
▐██████████▀ █████
|
|
28
|
-
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
</details>
|
|
1
|
+
<p align="center"><picture><source media="(prefers-reduced-motion: reduce)" srcset="https://cdn.jsdelivr.net/npm/@litfamily/litopencode@1.0.20/docs/assets/cover-motion-still.webp" /><img src="https://cdn.jsdelivr.net/npm/@litfamily/litopencode@1.0.20/docs/assets/cover-motion.webp" width="100%" alt="LitFamily 모션 커버: 다섯 로봇 패널이 차례로 켜지고, LitOpenCode 로봇의 눈과 테두리가 빛난 뒤 LITFAMILY와 KEEP THE WORK LIT. 문구가 밝아지는 영상" /></picture></p>
|
|
32
2
|
|
|
33
3
|
# LitOpenCode
|
|
34
4
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
> **불씨를 건네받았다.**<br>
|
|
38
|
-
> **이제, 당신의 작업에 옮길 차례다.**
|
|
5
|
+
**LitOpenCode는 OpenCode용 워크플로 플러그인입니다. 프롬프트에 `lit`만 붙이면 계획하고, 만들고, 확인하고, 기록까지 남겨서 다음 세션이 어디서 멈췄는지 바로 압니다.**
|
|
39
6
|
|
|
40
7
|
<p align="center">
|
|
41
|
-
<a href="
|
|
42
|
-
<a href="https://
|
|
8
|
+
<a href="https://www.npmjs.com/package/@litfamily/litopencode"><img src="https://cdn.jsdelivr.net/npm/@litfamily/litopencode@1.0.20/docs/assets/readme/badge-version.svg" alt="1.0.20" /></a>
|
|
9
|
+
<a href="https://www.npmjs.com/package/@litfamily/litopencode"><img src="https://img.shields.io/npm/dm/@litfamily/litopencode?label=downloads&color=D7F75B" alt="월간 npm 다운로드 수" /></a>
|
|
10
|
+
<a href="https://cdn.jsdelivr.net/npm/@litfamily/litopencode@1.0.20/LICENSE"><img src="https://cdn.jsdelivr.net/npm/@litfamily/litopencode@1.0.20/docs/assets/readme/badge-license.svg" alt="MIT 라이선스" /></a>
|
|
11
|
+
<a href="https://github.com/wjgoarxiv/litopencode"><img src="https://img.shields.io/github/stars/wjgoarxiv/litopencode?style=social" alt="GitHub 스타" /></a>
|
|
43
12
|
</p>
|
|
44
13
|
|
|
45
|
-
LitOpenCode는
|
|
46
|
-
|
|
47
|
-
프롬프트에 `lit`을 붙이면 계획하고, 만들고, 확인한 뒤 다음 할 일을 프로젝트에 적어 둡니다. 그래서 다음 세션이 멈춘 자리에서 바로 이어 갈 수 있습니다. 모델을 돌리고 권한을 묻는 일은 지금처럼 OpenCode가 합니다.
|
|
14
|
+
LitOpenCode는 목표와 계획, 확인한 내용, 다음 할 일을 프로젝트 안의 `.litopencode/litgoal/`에 남겨 두기 때문에, 긴 작업도 다음 날 멈춘 자리에서 이어 갈 수 있습니다.
|
|
48
15
|
|
|
49
|
-
**[전체
|
|
50
|
-
|
|
51
|
-
## 설치
|
|
52
|
-
|
|
53
|
-
Node.js와 npm, 그리고 OpenCode가 있으면 됩니다.
|
|
54
|
-
|
|
55
|
-
```sh
|
|
56
|
-
LIT_PACKAGE='@litfamily/litopencode@latest'
|
|
57
|
-
npm exec --package "$LIT_PACKAGE" -- litopencode install
|
|
58
|
-
```
|
|
16
|
+
**[전체 안내, 화면, 스킬 갤러리는 GitHub에서 →](https://github.com/wjgoarxiv/litopencode/blob/main/README-Ko-KR.md)**
|
|
59
17
|
|
|
60
|
-
|
|
18
|
+
## 빠르게 시작하기
|
|
61
19
|
|
|
62
|
-
|
|
20
|
+
Node.js와 npm, 그리고 모델 제공자를 설정해 둔 OpenCode가 있으면 됩니다.
|
|
63
21
|
|
|
64
22
|
```sh
|
|
65
|
-
npm exec --package @litfamily/litopencode@latest -- litopencode install
|
|
66
|
-
npm exec --package @litfamily/litopencode@latest -- litopencode install --yes # 기본값 사용, 저장된 선택 유지
|
|
23
|
+
npm exec --package @litfamily/litopencode@latest -- litopencode install
|
|
67
24
|
```
|
|
68
25
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
빈 폴더를 OpenCode에서 열고 `lit-loop`를 고른 다음 이렇게 보내 보세요.
|
|
26
|
+
기본값으로 바로 설치하려면 `--yes`를, 아무것도 쓰지 않고 무엇이 바뀔지만 보려면 `--dry-run`을 붙이세요. OpenCode를 다시 시작하고 **Tab** 키로 **lit-loop**를 고른 뒤, 빈 폴더를 열고 이렇게 보냅니다.
|
|
72
27
|
|
|
73
28
|
```text
|
|
74
29
|
lit 외부 의존성 없이 index.html 하나로 할 일 목록을 만들고, 추가와 완료 표시를 확인한 뒤 다음 할 일을 남겨줘.
|
|
75
30
|
```
|
|
76
31
|
|
|
77
|
-
`index.html`이
|
|
32
|
+
직접 열어 볼 수 있는 `index.html`이 생기고, 다음에 돌아오면 `/lit-recap`이 어디까지 했는지 알려 줍니다.
|
|
78
33
|
|
|
79
|
-
##
|
|
34
|
+
## 할 수 있는 일
|
|
80
35
|
|
|
81
36
|
| 입력 | 하는 일 |
|
|
82
37
|
| --- | --- |
|
|
83
|
-
| `lit` 또는 `/lit` |
|
|
84
|
-
| `lit-plan` → `/start-work` → `/review-work` |
|
|
85
|
-
| `handoff`
|
|
86
|
-
| `/
|
|
87
|
-
|
|
|
88
|
-
|
|
89
|
-
이 밖에도 디버깅, 리팩터링, 코드 검토, 조사 스킬이 있고, 만들기 전에 디자인 방향을 골라 알려 주는 워드 보고서(`lit-docx`)와 파워포인트 발표자료(`lit-pptx`), 다이어그램, 과학 그림, 화면 구현, README, 글 다듬기(`/lit-humanizer`) 스킬도 함께 설치됩니다. 스킬마다 무엇을 만드는지는 그림과 함께 [GitHub 스킬 갤러리](https://github.com/wjgoarxiv/litopencode/blob/master/README-Ko-KR.md#스킬-한눈에-보기)에 있습니다.
|
|
90
|
-
|
|
91
|
-
## 설치하면 바뀌는 것
|
|
92
|
-
|
|
93
|
-
많지 않습니다. OpenCode 설정에 플러그인을 등록하고, LitOpenCode의 명령과 스킬 파일을 OpenCode 설정 폴더에 복사합니다. 어떤 일에 어떤 모델을 쓸지 정한 route는 `~/.config/opencode/litopencode.json`에 저장됩니다. `XDG_CONFIG_HOME`을 지정하면 설정 폴더가 그쪽으로 옮겨 가고, 이미 손봐 둔 route는 건드리지 않습니다. 작업 기록은 프로젝트마다 `.litopencode/litgoal/`에 쌓이고, 다음 세션은 이 기록을 읽고 이어 갑니다.
|
|
38
|
+
| `lit` 또는 `/lit` | 일을 정리하고, 계획하고, 만들고, 확인하고, 요약하며 단계마다 기록을 남깁니다. |
|
|
39
|
+
| `lit-plan` → `/start-work` → `/review-work` | 계획하고, 승인하고, 실행하고, 검토합니다. 계획 에이전트는 파일을 고치거나 셸 명령을 실행할 수 없습니다. |
|
|
40
|
+
| `handoff` · `/lit-recap` | 다음 세션이 이어 갈 인수인계 파일을 남기고, 끝낸 일과 다음 할 일을 다시 읽어 줍니다. |
|
|
41
|
+
| `/litresearch` | 여러 차례 조사하며 주장마다 출처를 남깁니다. |
|
|
42
|
+
| `lit` + 보고서·발표자료 | 마크다운 원고와 함께 편집할 수 있는 워드 보고서나 파워포인트 덱을 만듭니다. |
|
|
43
|
+
| `/lit-humanizer` | 딱딱한 영어나 한국어 문장을 사실은 그대로 두고 다시 씁니다. |
|
|
94
44
|
|
|
95
|
-
|
|
45
|
+
스킬마다 만들어 내는 결과의 그림은 [GitHub의 스킬 갤러리](https://github.com/wjgoarxiv/litopencode/blob/main/docs/skills-Ko-KR.md)에서 볼 수 있습니다.
|
|
96
46
|
|
|
97
|
-
##
|
|
47
|
+
## 업데이트와 제거
|
|
98
48
|
|
|
99
|
-
|
|
100
|
-
- LitOpenCode는 대화형으로 시작할 때와 install이나 doctor가 성공한 뒤에 스스로 업데이트할 수 있습니다. 끄려면 `--no-auto-update`를 붙이거나 `LITOPENCODE_NO_AUTO_UPDATE=1`을 설정하세요.
|
|
101
|
-
- 스킬 학습 기능은 제거되었습니다. 이전 릴리스가 프로젝트의 `.litopencode` 폴더에 남긴 학습 기록은 더 이상 쓰이지 않으니, 남겨 두든 지우든 편한 대로 하면 됩니다.
|
|
102
|
-
- Jev 스킬 힌트는 선택 기능이고 기본값은 꺼짐입니다. 켜면 조건에 맞는 프롬프트가 TypeSafe로 전송되니, 먼저 [Jev 스킬 힌트 참조 문서](https://cdn.jsdelivr.net/npm/@litfamily/litopencode@1.0.18/docs/reference-Ko-KR.md#jev-스킬-힌트-선택)를 읽어 보세요. 알림과 doctor 줄이 어떻게 보이는지는 [GitHub 페이지](https://github.com/wjgoarxiv/litopencode/blob/master/README-Ko-KR.md#화면에서-보이는-것)에서 볼 수 있습니다.
|
|
103
|
-
- 뭔가 이상하면 `npm exec --package @litfamily/litopencode@latest -- litopencode doctor`로 패키지와 설정 상태를 확인하세요.
|
|
49
|
+
LitOpenCode는 대화형으로 시작할 때와 install·doctor가 성공한 뒤 새 버전을 확인합니다. 끄려면 `--no-auto-update`를 붙이거나 `LITOPENCODE_NO_AUTO_UPDATE=1`을 설정하세요. `npm exec --package @litfamily/litopencode@latest -- litopencode doctor`는 설치 상태를 확인할 뿐 아무것도 바꾸지 않습니다.
|
|
104
50
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
별도의 제거 명령은 없습니다. OpenCode의 `opencode.jsonc`(custom root라면 `opencode.json`)에서 `plugin` 배열의 `@litfamily/litopencode` 항목을 지우고 OpenCode를 다시 시작하세요. 전역으로 설치했다면 다음도 실행합니다.
|
|
51
|
+
제거하려면 OpenCode의 `opencode.jsonc`에서 `plugin` 배열의 `@litfamily/litopencode` 항목을 지우고 OpenCode를 다시 시작하세요. 전역으로 설치했다면 다음 명령도 실행합니다.
|
|
108
52
|
|
|
109
53
|
```sh
|
|
110
54
|
npm uninstall -g @litfamily/litopencode
|
|
111
55
|
```
|
|
112
56
|
|
|
113
|
-
남겨 둘 만한 설치 파일과 기록은 [제거 상세 안내](https://cdn.jsdelivr.net/npm/@litfamily/litopencode@1.0.18/docs/reference-Ko-KR.md#제거)에 정리되어 있습니다.
|
|
114
|
-
|
|
115
57
|
## 더 보기
|
|
116
58
|
|
|
117
|
-
- [GitHub
|
|
118
|
-
- [워크플로 상세 안내](https://cdn.jsdelivr.net/npm/@litfamily/litopencode@1.0.
|
|
119
|
-
- [마이그레이션 안내](https://cdn.jsdelivr.net/npm/@litfamily/litopencode@1.0.
|
|
120
|
-
- [MIT 라이선스](https://cdn.jsdelivr.net/npm/@litfamily/litopencode@1.0.
|
|
59
|
+
- [GitHub의 사용 안내](https://github.com/wjgoarxiv/litopencode/blob/main/docs/guide-Ko-KR.md): 설치 옵션, 자동 인수인계, 문제 해결, 제거
|
|
60
|
+
- [워크플로 상세 안내](https://cdn.jsdelivr.net/npm/@litfamily/litopencode@1.0.20/docs/reference-Ko-KR.md) · [English reference](https://cdn.jsdelivr.net/npm/@litfamily/litopencode@1.0.20/docs/reference.md)
|
|
61
|
+
- [마이그레이션 안내](https://cdn.jsdelivr.net/npm/@litfamily/litopencode@1.0.20/docs/migration.md) · [Changelog](https://cdn.jsdelivr.net/npm/@litfamily/litopencode@1.0.20/CHANGELOG.md) · [개인정보와 네트워크 동작](https://cdn.jsdelivr.net/npm/@litfamily/litopencode@1.0.20/docs/privacy.md)
|
|
62
|
+
- [LitFamily 허브](https://github.com/wjgoarxiv/litfamily) · [MIT 라이선스](https://cdn.jsdelivr.net/npm/@litfamily/litopencode@1.0.20/LICENSE) · [ASCII 글꼴 라이선스](https://cdn.jsdelivr.net/npm/@litfamily/litopencode@1.0.20/docs/assets/readme/JetBrainsMono-OFL.txt)
|
|
63
|
+
|
|
64
|
+
<details>
|
|
65
|
+
<summary>ASCII 로고 복사</summary>
|
|
66
|
+
|
|
67
|
+
```text
|
|
68
|
+
▄▄▄▄
|
|
69
|
+
▗███▌ ▗██████▖
|
|
70
|
+
▗▄▄▄▄▄ ▗▟████▌ ▝██████▘
|
|
71
|
+
▐█████ ▗▟██████▌ ▝▀▜█▀▘
|
|
72
|
+
▐█████ ▗▟███████▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
|
|
73
|
+
▐█████ ▗▟█████████████████████████ ▐█▀
|
|
74
|
+
▐█████ ████████████████████████████▀
|
|
75
|
+
▐█████ ██▛▘ ▄ ▄▄▄▄▖▄▄▄▄▄▄▄▄▄▄▄▄▄▖
|
|
76
|
+
▐█████ ▀ ▄██ ████▌█████████████▌
|
|
77
|
+
▐█████ ▄████ ████▌█████████████▌
|
|
78
|
+
▐█████ ▄█████▛ litopencode
|
|
79
|
+
▐█████ ▗▟█████▀▘ ▄▄▄▄▄ ▗▖
|
|
80
|
+
▐█████ ▐█████▀ █████ ▐▛▀
|
|
81
|
+
▐█████ ▐███▀ █████
|
|
82
|
+
▐█████ ▐█▀ █████
|
|
83
|
+
▐█████ ▝ █████
|
|
84
|
+
▐█████▄▄▄▄▄▄▄▖ █████
|
|
85
|
+
▐███████████▛ █████
|
|
86
|
+
▐██████████▀ █████
|
|
87
|
+
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
</details>
|
package/README.md
CHANGED
|
@@ -1,119 +1,90 @@
|
|
|
1
|
-
<p align="center"><picture><source media="(prefers-reduced-motion: reduce)" srcset="https://cdn.jsdelivr.net/npm/@litfamily/litopencode@1.0.
|
|
2
|
-
|
|
3
|
-
<p align="center"><img src="https://cdn.jsdelivr.net/npm/@litfamily/litopencode@1.0.18/docs/assets/readme/ascii-readme.svg" width="480" alt="LIT ASCII B mark" /></p>
|
|
4
|
-
|
|
5
|
-
<details>
|
|
6
|
-
<summary>Copy ASCII logo</summary>
|
|
7
|
-
|
|
8
|
-
```text
|
|
9
|
-
▄▄▄▄
|
|
10
|
-
▗███▌ ▗██████▖
|
|
11
|
-
▗▄▄▄▄▄ ▗▟████▌ ▝██████▘
|
|
12
|
-
▐█████ ▗▟██████▌ ▝▀▜█▀▘
|
|
13
|
-
▐█████ ▗▟███████▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
|
|
14
|
-
▐█████ ▗▟█████████████████████████ ▐█▀
|
|
15
|
-
▐█████ ████████████████████████████▀
|
|
16
|
-
▐█████ ██▛▘ ▄ ▄▄▄▄▖▄▄▄▄▄▄▄▄▄▄▄▄▄▖
|
|
17
|
-
▐█████ ▀ ▄██ ████▌█████████████▌
|
|
18
|
-
▐█████ ▄████ ████▌█████████████▌
|
|
19
|
-
▐█████ ▄█████▛ litopencode
|
|
20
|
-
▐█████ ▗▟█████▀▘ ▄▄▄▄▄ ▗▖
|
|
21
|
-
▐█████ ▐█████▀ █████ ▐▛▀
|
|
22
|
-
▐█████ ▐███▀ █████
|
|
23
|
-
▐█████ ▐█▀ █████
|
|
24
|
-
▐█████ ▝ █████
|
|
25
|
-
▐█████▄▄▄▄▄▄▄▖ █████
|
|
26
|
-
▐███████████▛ █████
|
|
27
|
-
▐██████████▀ █████
|
|
28
|
-
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
</details>
|
|
1
|
+
<p align="center"><picture><source media="(prefers-reduced-motion: reduce)" srcset="https://cdn.jsdelivr.net/npm/@litfamily/litopencode@1.0.20/docs/assets/cover-motion-still.webp" /><img src="https://cdn.jsdelivr.net/npm/@litfamily/litopencode@1.0.20/docs/assets/cover-motion.webp" width="100%" alt="LitFamily motion cover: five armored robots power on one by one, the LitOpenCode robot wakes with glowing eyes and a lit frame, then LITFAMILY and KEEP THE WORK LIT. light up." /></picture></p>
|
|
32
2
|
|
|
33
3
|
# LitOpenCode
|
|
34
4
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
**Keep the work lit.**
|
|
5
|
+
**LitOpenCode is a workflow plugin for OpenCode. Add `lit` to a prompt and the work gets planned, built, checked and written down, so the next session knows where you stopped.**
|
|
38
6
|
|
|
39
7
|
<p align="center">
|
|
40
|
-
<a href="
|
|
41
|
-
<a href="https://
|
|
8
|
+
<a href="https://www.npmjs.com/package/@litfamily/litopencode"><img src="https://cdn.jsdelivr.net/npm/@litfamily/litopencode@1.0.20/docs/assets/readme/badge-version.svg" alt="1.0.20" /></a>
|
|
9
|
+
<a href="https://www.npmjs.com/package/@litfamily/litopencode"><img src="https://img.shields.io/npm/dm/@litfamily/litopencode?label=downloads&color=D7F75B" alt="npm downloads per month" /></a>
|
|
10
|
+
<a href="https://cdn.jsdelivr.net/npm/@litfamily/litopencode@1.0.20/LICENSE"><img src="https://cdn.jsdelivr.net/npm/@litfamily/litopencode@1.0.20/docs/assets/readme/badge-license.svg" alt="MIT license" /></a>
|
|
11
|
+
<a href="https://github.com/wjgoarxiv/litopencode"><img src="https://img.shields.io/github/stars/wjgoarxiv/litopencode?style=social" alt="GitHub stars" /></a>
|
|
42
12
|
</p>
|
|
43
13
|
|
|
44
|
-
LitOpenCode
|
|
45
|
-
|
|
46
|
-
Add `lit` to a prompt and it plans, builds, checks, and writes down the next step in your project, so a later session can pick up where this one stopped. OpenCode still runs the model and asks for permission the way it always has.
|
|
14
|
+
LitOpenCode keeps the goal, the plan, what was checked and the next step in `.litopencode/litgoal/` inside your project, so a long task picks up the next day where it stopped.
|
|
47
15
|
|
|
48
|
-
**[Full guide and skills gallery on GitHub →](https://github.com/wjgoarxiv/litopencode#readme)**
|
|
49
|
-
|
|
50
|
-
## Install
|
|
51
|
-
|
|
52
|
-
You need Node.js with npm, and OpenCode.
|
|
53
|
-
|
|
54
|
-
```sh
|
|
55
|
-
LIT_PACKAGE='@litfamily/litopencode@latest'
|
|
56
|
-
npm exec --package "$LIT_PACKAGE" -- litopencode install
|
|
57
|
-
```
|
|
16
|
+
**[Full guide, screens and skills gallery on GitHub →](https://github.com/wjgoarxiv/litopencode#readme)**
|
|
58
17
|
|
|
59
|
-
|
|
18
|
+
## Quick start
|
|
60
19
|
|
|
61
|
-
|
|
20
|
+
You need Node.js with npm, and OpenCode with a model provider set up.
|
|
62
21
|
|
|
63
22
|
```sh
|
|
64
|
-
npm exec --package @litfamily/litopencode@latest -- litopencode install
|
|
65
|
-
npm exec --package @litfamily/litopencode@latest -- litopencode install --yes # use defaults; preserve saved choices
|
|
23
|
+
npm exec --package @litfamily/litopencode@latest -- litopencode install
|
|
66
24
|
```
|
|
67
25
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
Open an empty folder in OpenCode, pick `lit-loop`, and send:
|
|
26
|
+
Add `--yes` to take the defaults, or `--dry-run` to preview without writing anything. Restart OpenCode, press **Tab**, pick **lit-loop**, open an empty folder and send:
|
|
71
27
|
|
|
72
28
|
```text
|
|
73
29
|
lit Build a to-do list in one index.html with no dependencies; check adding and completing items, then leave results and next steps.
|
|
74
30
|
```
|
|
75
31
|
|
|
76
|
-
You get an `index.html` to
|
|
32
|
+
You get an `index.html` to try, and next time `/lit-recap` shows where you left off.
|
|
77
33
|
|
|
78
|
-
##
|
|
34
|
+
## What you get
|
|
79
35
|
|
|
80
|
-
|
|
|
36
|
+
| You enter | What happens |
|
|
81
37
|
| --- | --- |
|
|
82
|
-
| `lit` or `/lit` |
|
|
83
|
-
| `lit-plan` → `/start-work` → `/review-work` | Plan, approve,
|
|
84
|
-
| `handoff`
|
|
85
|
-
| `/
|
|
86
|
-
|
|
|
87
|
-
|
|
88
|
-
Beyond these, the package installs skills for debugging, refactoring, code review, research, Word reports (`lit-docx`) and PowerPoint decks (`lit-pptx`) that pick and name a design direction before building, diagrams, scientific figures, interfaces, READMEs, and prose editing (`/lit-humanizer`). Each one, with a picture of what it produces, is in the [skills gallery on GitHub](https://github.com/wjgoarxiv/litopencode#skills-at-a-glance).
|
|
89
|
-
|
|
90
|
-
## What install changes
|
|
91
|
-
|
|
92
|
-
Not much. Install adds the plugin to OpenCode's config and copies LitOpenCode's commands and skills into your OpenCode config folder. Your routes, which say which model handles each kind of work, are kept in `~/.config/opencode/litopencode.json`. Setting `XDG_CONFIG_HOME` moves that folder, and routes you've already customized are left as they are. Each project keeps its work record in `.litopencode/litgoal/`, and that record is what a later session reads to carry on.
|
|
38
|
+
| `lit` or `/lit` | Plan, build, verify and recap a task, with a note at each step. |
|
|
39
|
+
| `lit-plan` → `/start-work` → `/review-work` | Plan, approve, build and review. The planner cannot edit files. |
|
|
40
|
+
| `handoff` · `/lit-recap` | Leave a continuation file for the next session, and read back what is done and what is next. |
|
|
41
|
+
| `/litresearch` | Research in rounds with a source for each claim. |
|
|
42
|
+
| `lit` + report or slides | An editable Word report or PowerPoint deck with its Markdown source. |
|
|
43
|
+
| `/lit-humanizer` | Rewrite stiff English or Korean prose and keep the facts. |
|
|
93
44
|
|
|
94
|
-
|
|
45
|
+
Each skill is pictured in the [skills gallery on GitHub](https://github.com/wjgoarxiv/litopencode/blob/main/docs/skills.md).
|
|
95
46
|
|
|
96
|
-
##
|
|
47
|
+
## Updates and removal
|
|
97
48
|
|
|
98
|
-
|
|
99
|
-
- LitOpenCode can update itself when it starts interactively and after an install or doctor run succeeds. To turn that off, pass `--no-auto-update` or set `LITOPENCODE_NO_AUTO_UPDATE=1`.
|
|
100
|
-
- Skill learning has been removed. Learning records an earlier release left in a project's `.litopencode` folder are no longer used; keep or delete them as you like.
|
|
101
|
-
- The Jev skill hint is optional and off by default. Turning it on sends eligible prompts to TypeSafe, so read the [Jev skill hint reference](https://cdn.jsdelivr.net/npm/@litfamily/litopencode@1.0.18/docs/reference.md#jev-skill-hint-optional) first. The GitHub page shows [what the toast and the doctor line look like](https://github.com/wjgoarxiv/litopencode#what-you-will-see).
|
|
102
|
-
- If something seems off, `npm exec --package @litfamily/litopencode@latest -- litopencode doctor` checks the package and your configuration.
|
|
49
|
+
LitOpenCode checks for updates on interactive start and after a successful install or doctor run. To turn that off, pass `--no-auto-update` or set `LITOPENCODE_NO_AUTO_UPDATE=1`. `npm exec --package @litfamily/litopencode@latest -- litopencode doctor` checks the setup and changes nothing.
|
|
103
50
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
There's no uninstall command. Remove the `@litfamily/litopencode` entry from the `plugin` array in OpenCode's `opencode.jsonc` (or a custom root's `opencode.json`), then restart OpenCode. If you installed it globally:
|
|
51
|
+
To remove it, delete the `@litfamily/litopencode` entry from the `plugin` array in OpenCode's `opencode.jsonc` and restart OpenCode. If you installed it globally:
|
|
107
52
|
|
|
108
53
|
```sh
|
|
109
54
|
npm uninstall -g @litfamily/litopencode
|
|
110
55
|
```
|
|
111
56
|
|
|
112
|
-
The [removal reference](https://cdn.jsdelivr.net/npm/@litfamily/litopencode@1.0.18/docs/reference.md#remove) covers the installed files and records you may want to keep.
|
|
113
|
-
|
|
114
57
|
## More
|
|
115
58
|
|
|
116
|
-
- [
|
|
117
|
-
- [Workflow reference](https://cdn.jsdelivr.net/npm/@litfamily/litopencode@1.0.
|
|
118
|
-
- [Migration notes](https://cdn.jsdelivr.net/npm/@litfamily/litopencode@1.0.
|
|
119
|
-
- [MIT license](https://cdn.jsdelivr.net/npm/@litfamily/litopencode@1.0.
|
|
59
|
+
- [Guide on GitHub](https://github.com/wjgoarxiv/litopencode/blob/main/docs/guide.md): install options, automatic handoff, troubleshooting and removal.
|
|
60
|
+
- [Workflow reference](https://cdn.jsdelivr.net/npm/@litfamily/litopencode@1.0.20/docs/reference.md)
|
|
61
|
+
- [Migration notes](https://cdn.jsdelivr.net/npm/@litfamily/litopencode@1.0.20/docs/migration.md) · [Changelog](https://cdn.jsdelivr.net/npm/@litfamily/litopencode@1.0.20/CHANGELOG.md) · [Privacy and network behavior](https://cdn.jsdelivr.net/npm/@litfamily/litopencode@1.0.20/docs/privacy.md)
|
|
62
|
+
- [LitFamily hub](https://github.com/wjgoarxiv/litfamily) · [MIT license](https://cdn.jsdelivr.net/npm/@litfamily/litopencode@1.0.20/LICENSE) · [ASCII font license](https://cdn.jsdelivr.net/npm/@litfamily/litopencode@1.0.20/docs/assets/readme/JetBrainsMono-OFL.txt)
|
|
63
|
+
|
|
64
|
+
<details>
|
|
65
|
+
<summary>Copy ASCII logo</summary>
|
|
66
|
+
|
|
67
|
+
```text
|
|
68
|
+
▄▄▄▄
|
|
69
|
+
▗███▌ ▗██████▖
|
|
70
|
+
▗▄▄▄▄▄ ▗▟████▌ ▝██████▘
|
|
71
|
+
▐█████ ▗▟██████▌ ▝▀▜█▀▘
|
|
72
|
+
▐█████ ▗▟███████▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
|
|
73
|
+
▐█████ ▗▟█████████████████████████ ▐█▀
|
|
74
|
+
▐█████ ████████████████████████████▀
|
|
75
|
+
▐█████ ██▛▘ ▄ ▄▄▄▄▖▄▄▄▄▄▄▄▄▄▄▄▄▄▖
|
|
76
|
+
▐█████ ▀ ▄██ ████▌█████████████▌
|
|
77
|
+
▐█████ ▄████ ████▌█████████████▌
|
|
78
|
+
▐█████ ▄█████▛ litopencode
|
|
79
|
+
▐█████ ▗▟█████▀▘ ▄▄▄▄▄ ▗▖
|
|
80
|
+
▐█████ ▐█████▀ █████ ▐▛▀
|
|
81
|
+
▐█████ ▐███▀ █████
|
|
82
|
+
▐█████ ▐█▀ █████
|
|
83
|
+
▐█████ ▝ █████
|
|
84
|
+
▐█████▄▄▄▄▄▄▄▖ █████
|
|
85
|
+
▐███████████▛ █████
|
|
86
|
+
▐██████████▀ █████
|
|
87
|
+
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
</details>
|
|
@@ -62,7 +62,9 @@ const uiHardenCue = /\b(?:harden|stress.test|hold up under|robust to)\b|튼튼
|
|
|
62
62
|
const uiReadOnlyCue = /\b(?:read.only|don't (?:touch|change|fix)|just (?:check|tell))\b|수정은 하지|건드리지 말|고치지는 말|목록만/u;
|
|
63
63
|
const uiBuildCue = /\b(?:redesign|new layout|brand.new|add|implement|build|create|make|wire up)\b|새로|추가|구현|다시 짜|재구성/u;
|
|
64
64
|
const diagramCreationIntent = /^\s*(?:lit[,:]?\s+)?(?:please\s+)?(?:create|draw|make|design|render|build)\b[^.!?\n]*\b(?:diagrams?|flowcharts?|architecture maps?)\b|^\s*(?:lit\s+)?[^.!?\n]*(?:다이어그램|흐름도|구성도|구조도)[^.!?\n]*(?:그려|만들어|제작해)/mu;
|
|
65
|
-
|
|
65
|
+
// "turn X into a deck/report" also authors an Office file. Within the clause, a dot followed by a
|
|
66
|
+
// non-space (notes.md, q3.v2.csv) is part of a file name and does not end the sentence.
|
|
67
|
+
const officeAuthoringVerb = /(?<![a-z])(?:make|create|write|draft|prepare|produce|generate|convert|edit|build)(?![a-z])|(?<![a-z])turn(?=(?:[^.!?\n]|\.(?=\S))*?(?<![a-z])into(?![a-z])(?:[^.!?\n]|\.(?=\S))*?(?<![a-z])(?:slides?|decks?|presentations?|pptx?|reports?|documents?|docx|word)(?![a-z]))|만들|작성|써줘|제작|변환|편집/u;
|
|
66
68
|
const reportNoun = /(?<![a-z])(?:reports?|documents?|docx|word)(?![a-z])|보고서|리포트|기획서|제안서|문서|워드/u;
|
|
67
69
|
const slidesNoun = /(?<![a-z])(?:slides?|decks?|presentations?|pptx?)(?![a-z])|발표자료|발표|슬라이드|피피티|덱/u;
|
|
68
70
|
// lit-typographic-motion (MO-C-18..24). The trigger is a creation verb plus a compound motion-video
|
package/dist/cli/args.js
CHANGED
|
@@ -66,7 +66,10 @@ export function parseArgs(argv) {
|
|
|
66
66
|
throw new Error(`${arg} requires a value`);
|
|
67
67
|
return cleaned;
|
|
68
68
|
};
|
|
69
|
-
const
|
|
69
|
+
const tuiAction = command === "tui" ? argv[1] : undefined;
|
|
70
|
+
if (command === "tui" && tuiAction !== "remove")
|
|
71
|
+
throw new Error("tui requires an action: remove");
|
|
72
|
+
const firstOptionIndex = command === "fetch-public" || command === "tui" ? 2 : 1;
|
|
70
73
|
if (command === "fetch-public") {
|
|
71
74
|
fetchPublicUrl = cleanOption(argv[1], "fetch-public URL");
|
|
72
75
|
if (!fetchPublicUrl)
|
|
@@ -298,6 +301,7 @@ export function parseArgs(argv) {
|
|
|
298
301
|
modelSelection: resolveModelSelection(provider, model, effort, subagentModel, subagentEffort),
|
|
299
302
|
modelPrompt: yes ? "never" : modelPrompt,
|
|
300
303
|
outputStylePrompt: yes ? "never" : "auto",
|
|
304
|
+
...(tuiAction === undefined ? {} : { tuiAction }),
|
|
301
305
|
loop: {
|
|
302
306
|
projectRoot,
|
|
303
307
|
json: loopJson,
|
package/dist/cli/auto-update.js
CHANGED
|
@@ -255,7 +255,7 @@ async function captureSnapshot(configRoot, homeDir) {
|
|
|
255
255
|
const snapshotPath = path.join(stateRoot(homeDir), `.auto-update-backup-${randomUUID()}`);
|
|
256
256
|
await fs.mkdir(snapshotPath, { recursive: true, mode: 0o700 });
|
|
257
257
|
const entries = [];
|
|
258
|
-
for (const relativePath of ["opencode.json", "opencode.jsonc", "litopencode.json", "command", "skills"]) {
|
|
258
|
+
for (const relativePath of ["opencode.json", "opencode.jsonc", "tui.json", "tui.jsonc", "litopencode.json", "command", "skills"]) {
|
|
259
259
|
const source = path.join(configRoot, relativePath);
|
|
260
260
|
const kind = await lstatKind(source);
|
|
261
261
|
if (kind === undefined) {
|
package/dist/cli/doctor.js
CHANGED
|
@@ -5,6 +5,7 @@ import { defaultGlobalConfigFile, loadConfig, mergeConfigs, readLitOpenCodeConfi
|
|
|
5
5
|
import { diagnoseModelRoutes, effectiveAuthoredAgentRoutes, projectModelRoutesForDiagnostics } from "../model-route-policy.js";
|
|
6
6
|
import { litOpenCodeConfigFileForOpenCodeRoot } from "../state.js";
|
|
7
7
|
import { isRecord, readJsonObjectIfPresent, readPackageMetadata } from "./json.js";
|
|
8
|
+
import { parseJsonc } from "./jsonc.js";
|
|
8
9
|
import { inspectCommandAliases } from "./command-aliases.js";
|
|
9
10
|
import { inspectNativeSkills } from "./native-skills.js";
|
|
10
11
|
import { openCodeHostCapabilities } from "./host-capabilities.js";
|
|
@@ -13,6 +14,7 @@ import { autoHandoffEnvEnabled, autoHandoffEnvPercent, createAutoHandoffSettings
|
|
|
13
14
|
import { inspectLspCapability } from "./lsp-capability.js";
|
|
14
15
|
import { probeMotionRuntime } from "./motion-runtime.js";
|
|
15
16
|
import { isLitOpenCodeEntry } from "./plugin-mutation.js";
|
|
17
|
+
import { inspectTuiPlugin } from "./tui-config.js";
|
|
16
18
|
import { jevSkillHintDoctorLine } from "../jev-skill-hint.js";
|
|
17
19
|
import { autoUpdateInstallLockPath, autoUpdateJournalPath, autoUpdateReceiptPath, isAutoUpdateDisabled, readAutoUpdateReceipt } from "./auto-update.js";
|
|
18
20
|
function pluginSpec(metadata) {
|
|
@@ -25,9 +27,6 @@ function pluginEntryId(value) {
|
|
|
25
27
|
return value[0];
|
|
26
28
|
return "";
|
|
27
29
|
}
|
|
28
|
-
function stripJsonComments(value) {
|
|
29
|
-
return value.replace(/\/\*[\s\S]*?\*\//g, "").replace(/^\s*\/\/.*$/gm, "");
|
|
30
|
-
}
|
|
31
30
|
async function readOpenCodeConfig(root) {
|
|
32
31
|
const resolvedRoot = path.resolve(root);
|
|
33
32
|
const candidates = [path.join(resolvedRoot, "opencode.json"), path.join(resolvedRoot, "opencode.jsonc")];
|
|
@@ -42,7 +41,7 @@ async function readOpenCodeConfig(root) {
|
|
|
42
41
|
throw error;
|
|
43
42
|
}
|
|
44
43
|
try {
|
|
45
|
-
const parsed =
|
|
44
|
+
const parsed = parseJsonc(raw);
|
|
46
45
|
return { path: candidate, config: isRecord(parsed) ? parsed : null, ...(isRecord(parsed) ? {} : { error: "expected object" }) };
|
|
47
46
|
}
|
|
48
47
|
catch (error) {
|
|
@@ -114,6 +113,8 @@ export async function doctor(root) {
|
|
|
114
113
|
const installPlugin = await inspectPlugin(root, metadata);
|
|
115
114
|
const commandAliases = await inspectCommandAliases(root);
|
|
116
115
|
const nativeSkills = await inspectNativeSkills(root, metadata);
|
|
116
|
+
// The TUI panel is optional, so a missing entry is reported here without failing install.ok.
|
|
117
|
+
const tui = await inspectTuiPlugin(root, installPlugin.present && installPlugin.configured !== null ? installPlugin.configured : installPlugin.expected);
|
|
117
118
|
const hostConfig = await readOpenCodeConfig(root);
|
|
118
119
|
const motion = probeMotionRuntime(metadata.packageRoot);
|
|
119
120
|
const autoHandoff = await createAutoHandoffSettings({
|
|
@@ -193,7 +194,8 @@ export async function doctor(root) {
|
|
|
193
194
|
ok: installPlugin.ok && commandAliases.ok && nativeSkills.ok,
|
|
194
195
|
plugin: installPlugin,
|
|
195
196
|
commandAliases,
|
|
196
|
-
nativeSkills
|
|
197
|
+
nativeSkills,
|
|
198
|
+
tui
|
|
197
199
|
}
|
|
198
200
|
}, null, 2)
|
|
199
201
|
};
|
package/dist/cli/host-limits.js
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import { isRecord } from "./json.js";
|
|
2
|
-
import {
|
|
2
|
+
import { writeOpenCodeConfig } from "./install-config.js";
|
|
3
3
|
import { hostLimitModelIds } from "./model-catalog.js";
|
|
4
|
-
import fs from "node:fs/promises";
|
|
5
|
-
import path from "node:path";
|
|
6
4
|
export const contextCeilingTokens = 372000;
|
|
7
5
|
export const compactionTriggerTokens = 334800;
|
|
8
6
|
export const compactionReserveTokens = contextCeilingTokens - compactionTriggerTokens;
|
|
@@ -91,6 +89,5 @@ export async function ensureHostLimits(configPath, config, reconfigure) {
|
|
|
91
89
|
const next = applyHostLimits(config);
|
|
92
90
|
if (JSON.stringify(config) === JSON.stringify(next))
|
|
93
91
|
return;
|
|
94
|
-
await
|
|
95
|
-
await writeTextAtomically(configPath, JSON.stringify(next, null, 2) + "\n");
|
|
92
|
+
await writeOpenCodeConfig(configPath, next);
|
|
96
93
|
}
|
|
@@ -3,6 +3,10 @@ type AtomicWriteOverrides = {
|
|
|
3
3
|
readonly rename?: (from: string, to: string) => Promise<void>;
|
|
4
4
|
};
|
|
5
5
|
export declare function writeTextAtomically(filePath: string, text: string, overrides?: AtomicWriteOverrides): Promise<void>;
|
|
6
|
+
export declare class OpenCodeConfigCommentError extends Error {
|
|
7
|
+
}
|
|
8
|
+
export declare function renderOpenCodeConfig(filePath: string, currentText: string | null, next: Record<string, unknown>): string;
|
|
9
|
+
export declare function writeOpenCodeConfig(filePath: string, next: Record<string, unknown>): Promise<void>;
|
|
6
10
|
export declare function readInstallModelClassification(root: string): Promise<ModelConfigClassification>;
|
|
7
11
|
export declare function readInstallModelSelection(root: string): Promise<InstallModelSelection | undefined>;
|
|
8
12
|
export declare function assertExistingModelRoutesSafe(root: string): Promise<void>;
|
|
@@ -5,7 +5,8 @@ import { litOpenCodeAgents, registerLitOpenCodeAgents } from "../agents.js";
|
|
|
5
5
|
import { defaultGlobalConfigFile, defaultGlobalConfigJson, mergeConfigs, readLitOpenCodeConfigFile } from "../config.js";
|
|
6
6
|
import { diagnoseModelRoutes, effectiveAuthoredAgentRoutes, UnsafeModelRouteError } from "../model-route-policy.js";
|
|
7
7
|
import { litOpenCodeConfigFileForOpenCodeRoot } from "../state.js";
|
|
8
|
-
import { isRecord, readJsonObjectIfPresent } from "./json.js";
|
|
8
|
+
import { isRecord, readJsonObjectIfPresent, readTextIfPresent } from "./json.js";
|
|
9
|
+
import { editJsoncObject, formatJsoncMember, hasJsoncComments, lineEnding } from "./jsonc.js";
|
|
9
10
|
import { installModelEfforts, isModelProvider, modelMenuRows, stripFastSuffix } from "./model-catalog.js";
|
|
10
11
|
import { classifyModelConfig, selectedLitConfig } from "./model-policy.js";
|
|
11
12
|
export async function writeTextAtomically(filePath, text, overrides = {}) {
|
|
@@ -19,6 +20,31 @@ export async function writeTextAtomically(filePath, text, overrides = {}) {
|
|
|
19
20
|
throw error;
|
|
20
21
|
}
|
|
21
22
|
}
|
|
23
|
+
export class OpenCodeConfigCommentError extends Error {
|
|
24
|
+
}
|
|
25
|
+
// A commented OpenCode config is edited in place; when an edit would delete a comment, the user is
|
|
26
|
+
// shown the exact entry to write instead.
|
|
27
|
+
export function renderOpenCodeConfig(filePath, currentText, next) {
|
|
28
|
+
if (currentText === null)
|
|
29
|
+
return JSON.stringify(next, null, 2) + "\n";
|
|
30
|
+
if (!hasJsoncComments(currentText)) {
|
|
31
|
+
const eol = lineEnding(currentText);
|
|
32
|
+
return (currentText.startsWith("\uFEFF") ? "\uFEFF" : "") + (JSON.stringify(next, null, 2) + "\n").replace(/\n/gu, eol);
|
|
33
|
+
}
|
|
34
|
+
const edit = editJsoncObject(currentText, next);
|
|
35
|
+
if (edit.ok)
|
|
36
|
+
return edit.text;
|
|
37
|
+
const action = edit.key in next
|
|
38
|
+
? `set this entry yourself:\n${formatJsoncMember(edit.key, next[edit.key])}`
|
|
39
|
+
: `remove the "${edit.key}" entry yourself`;
|
|
40
|
+
throw new OpenCodeConfigCommentError(`Refusing to rewrite ${filePath}: changing its "${edit.key}" entry would delete a comment in it. ` +
|
|
41
|
+
`Nothing was written. To continue, ${action}\nthen run the command again.`);
|
|
42
|
+
}
|
|
43
|
+
export async function writeOpenCodeConfig(filePath, next) {
|
|
44
|
+
const text = renderOpenCodeConfig(filePath, await readTextIfPresent(filePath), next);
|
|
45
|
+
await fs.mkdir(path.dirname(filePath), { recursive: true });
|
|
46
|
+
await writeTextAtomically(filePath, text);
|
|
47
|
+
}
|
|
22
48
|
async function readValidatedConfig(root) {
|
|
23
49
|
const filePath = litOpenCodeConfigFileForOpenCodeRoot(root);
|
|
24
50
|
if ((await readLitOpenCodeConfigFile(filePath)) === undefined)
|
|
@@ -125,7 +125,8 @@ function actionLines(report) {
|
|
|
125
125
|
: "OpenCode context and compaction limits already ready"
|
|
126
126
|
: "OpenCode context and compaction limits preserved; select LUNA to reconfigure",
|
|
127
127
|
report.commandAliases.changed ? "command aliases written" : "command aliases preserved",
|
|
128
|
-
report.nativeSkills.changed ? "native skills written" : "native skills preserved"
|
|
128
|
+
report.nativeSkills.changed ? "native skills written" : "native skills preserved",
|
|
129
|
+
report.tui.changed ? "TUI mission panel registered" : "TUI mission panel already ready"
|
|
129
130
|
];
|
|
130
131
|
}
|
|
131
132
|
function progressLine(label) {
|
|
@@ -166,6 +167,7 @@ export function renderInstallReport(report) {
|
|
|
166
167
|
line("", actions[2]),
|
|
167
168
|
line("", actions[3]),
|
|
168
169
|
line("", actions[4]),
|
|
170
|
+
line("", actions[5]),
|
|
169
171
|
...section("Routes"),
|
|
170
172
|
line("Model", modelRoute(report)),
|
|
171
173
|
line("Effort", report.litopencodeConfig.model.effort ?? "preserve existing"),
|
|
@@ -189,6 +191,7 @@ export function renderInstallReport(report) {
|
|
|
189
191
|
line("Native skills", report.nativeSkills.write.length + " managed / " + report.nativeSkills.preserve.length + " preserved"),
|
|
190
192
|
...nativeSkillsLinkLines(report),
|
|
191
193
|
line("Plugin entries", report.plugin.currentCount + " -> " + report.plugin.resultCount),
|
|
194
|
+
line("TUI config", report.tui.path),
|
|
192
195
|
...section("Progress"),
|
|
193
196
|
progressLine("Resolve package"),
|
|
194
197
|
progressLine("Read OpenCode config"),
|