afucontext 0.1.19 → 0.1.21

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 CHANGED
@@ -16,17 +16,17 @@ In a long session, the same tool output can travel with every model request. AFU
16
16
 
17
17
  ## Quick start
18
18
 
19
- Install and sign in to your host first. You need npm, Node.js **22.19+ (22.x) or 24+** and Python **3.11+** on `PATH`. Pick one row, run the install command in your terminal, then use the launch command.
19
+ Install and sign in to your host first. You need npm, Node.js **22.19+ (22.x) or 24+** and Python **3.11+** on `PATH`. Pick one row, run the install command in your terminal (the first npx run asks once to install the package; press Enter), then use the launch command. After that, add hosts, upgrade and remove with `afuctx`; see [Commands](#commands).
20
20
 
21
21
  | Host | System | Install | Launch after installation | Tested version |
22
22
  | --- | --- | --- | --- | --- |
23
- | <a id="afu-claude"></a>Claude Code | macOS / Linux | `npx --yes --registry=https://registry.npmjs.org afucontext@0.1.19 install claude` | `claude` | 2.1.293 |
24
- | <a id="afu-codex"></a>Codex CLI | macOS / Linux | `npx --yes --registry=https://registry.npmjs.org afucontext@0.1.19 install codex` | `codex` | 0.153.4 |
25
- | <a id="afu-pi"></a>Pi | macOS / Linux | `npx --yes --registry=https://registry.npmjs.org afucontext@0.1.19 install pi` | `pi` | 0.84.4, 1.5.0 |
26
- | <a id="afu-dsh"></a>DSH | macOS / Linux | `npx --yes --registry=https://registry.npmjs.org afucontext@0.1.19 install dsh --profile YOUR_PROFILE` | `dsh --profile YOUR_PROFILE` | 0.2.2-rc.1 |
27
- | Codex CLI | Windows 10/11¹ | `npx.cmd --yes --registry=https://registry.npmjs.org "afucontext@0.1.19" install codex` | `codex` | preview, not yet tested; official in the next release |
28
- | Pi | Windows 10/11¹ | `npx.cmd --yes --registry=https://registry.npmjs.org "afucontext@0.1.19" install pi` | `pi` | preview, not yet tested; official in the next release |
29
- | DSH | Windows 10/11¹ | `npx.cmd --yes --registry=https://registry.npmjs.org "afucontext@0.1.19" install dsh --profile YOUR_PROFILE` | `dsh --profile YOUR_PROFILE` | preview, not yet tested; official in the next release |
23
+ | <a id="afu-claude"></a>Claude Code | macOS / Linux | `npx afucontext@latest install claude` | `claude` | 2.1.293 |
24
+ | <a id="afu-codex"></a>Codex CLI | macOS / Linux | `npx afucontext@latest install codex` | `codex` | 0.153.4 |
25
+ | <a id="afu-pi"></a>Pi | macOS / Linux | `npx afucontext@latest install pi` | `pi` | 0.84.4, 1.5.0 |
26
+ | <a id="afu-dsh"></a>DSH | macOS / Linux | `npx afucontext@latest install dsh --profile YOUR_PROFILE` | `dsh --profile YOUR_PROFILE` | 0.2.2-rc.1 |
27
+ | Codex CLI | Windows 10/11¹ | `npx.cmd "afucontext@latest" install codex` | `codex` | preview, not yet tested; official in the next release |
28
+ | Pi | Windows 10/11¹ | `npx.cmd "afucontext@latest" install pi` | `pi` | preview, not yet tested; official in the next release |
29
+ | DSH | Windows 10/11¹ | `npx.cmd "afucontext@latest" install dsh --profile YOUR_PROFILE` | `dsh --profile YOUR_PROFILE` | preview, not yet tested; official in the next release |
30
30
 
31
31
  Supported on macOS (Apple Silicon) and Linux x64. Start a new session after installing.
32
32
 
@@ -36,22 +36,34 @@ Supported on macOS (Apple Silicon) and Linux x64. Start a new session after inst
36
36
 
37
37
  <a id="results"></a>
38
38
 
39
+ <a id="commands"></a>
40
+
39
41
  ## Commands
40
42
 
41
- The terminal commands (`afuctx …`) are placed in `~/.local/bin` by the first install of any host (the folder is created when missing). If that folder is not on `PATH`, the installer says so: add `export PATH="$HOME/.local/bin:$PATH"` to `~/.bashrc` or `~/.zshrc`, or use `npx --yes --registry=https://registry.npmjs.org afucontext@latest` in place of `afuctx`. Install, upgrade and remove replace the runtime itself, so they always run through npx.
43
+ After installing, use `afuctx` in a terminal. The first install of any host places it in `~/.local/bin` (creating the folder when missing). Shell startup files are never edited (when the folder is not on `PATH` the installer prints the line to add, `export PATH="$HOME/.local/bin:$PATH"`, for `~/.bashrc` or `~/.zshrc`), an existing command of the same name is kept, and it is removed with the last host. Without `afuctx` (on Windows, or with `~/.local/bin` not on `PATH`), use `npx afucontext@latest` in its place; in Windows PowerShell use `npx.cmd "afucontext@latest"`.
44
+
45
+ HOST below is `claude`, `codex`, `pi` or `dsh`; for DSH always add `--profile NAME`.
46
+
47
+ ### Install, upgrade and remove
42
48
 
43
49
  | Command | What it does |
44
50
  | --- | --- |
45
- | `npx --yes --registry=https://registry.npmjs.org afucontext@latest install claude\|codex\|pi\|dsh` | Install for a host; for DSH add `--profile NAME` |
46
- | `npx --yes --registry=https://registry.npmjs.org afucontext@latest install dsh --runtime-only` | Prepare only the runtime, for use with `dsh plugin --profile NAME add afucontext-dsh-plugin` |
47
- | `npx --yes --registry=https://registry.npmjs.org afucontext@latest update` | Upgrade every host installed on this machine to this version |
48
- | `npx --yes --registry=https://registry.npmjs.org afucontext@latest remove HOST` | Remove; host settings return to their state before installation. For DSH, `--profile NAME` removes one profile |
49
- | `afuctx status` | Whether each host is connected, how far the context is from the trigger, compactions applied; `--json` for the full record |
51
+ | `npx afucontext@latest install HOST` | First install |
52
+ | `afuctx install HOST` | Add another host |
53
+ | `afuctx install dsh --runtime-only` | Prepare only the runtime, for use with `dsh plugin --profile NAME add afucontext-dsh-plugin` |
54
+ | `afuctx update` | Upgrade every installed host to the latest release, one by one with the settings it was installed with, printing each version change |
55
+ | `afuctx upgrade HOST` | Upgrade one host |
56
+ | `afuctx remove HOST` | Remove; the host's settings return to how they were before install. For DSH, `--profile` removes one profile, without it all of them |
57
+
58
+ `afuctx install`, `update`, `upgrade` and `remove` fetch the latest release from npm and run it. After upgrading Claude Code or Codex, start a new session to use the new version; after removing, restart the host.
59
+
60
+ ### Status and dashboard
61
+
62
+ | Command | What it does |
63
+ | --- | --- |
64
+ | `afuctx` | Short status of recent sessions |
65
+ | `afuctx status [HOST]` | Whether AFU is connected, the current context against the trigger, compactions so far; `--brief` for a summary (with each host's installed version), `--json` for everything |
50
66
  | `afuctx dashboard` | Open the local dashboard (same as `afuctx-admin`); `--prices FILE` estimates costs with your prices |
51
- | `afuctx doctor` | Checks host → AFU → model end to end, fixes what AFU can and gives exact steps for the rest; add a host name to check one |
52
- | `afuctx off` / `afuctx on` | Pause / resume: while paused the hosts talk to their models directly; the installation, logs and summaries stay. Add a host name for one host |
53
- | `afuctx repair codex --network` | Find and verify the proxy route to the model again (`repair claude` for Claude Code) |
54
- | `afuctx gc --dry-run` | List old runtimes and logs that can be removed; without `--dry-run` it removes them |
55
67
  | `afuctx --version` / `afuctx --help` | Version / help |
56
68
 
57
69
  Inside a host session:
@@ -62,6 +74,26 @@ Inside a host session:
62
74
  | Codex | `$afuctx-status` | `$afuctx-dashboard` |
63
75
  | Pi / DSH | `/afuctx-status` | `/afuctx-dashboard` |
64
76
 
77
+ ### When to compact
78
+
79
+ | Command | What it does |
80
+ | --- | --- |
81
+ | `afuctx install HOST --ratio 0.3` | Compact earlier or later (between 0 and 1) |
82
+ | `afuctx install HOST --context-window 200000` | Set the model window |
83
+ | `afuctx install HOST --context-window auto --ratio auto` | Back to automatic |
84
+
85
+ The two options combine: `--context-window 200000 --ratio 0.3` triggers at 60,000 tokens. Start a new session for the change to apply.
86
+
87
+ ### Troubleshooting and maintenance
88
+
89
+ | Command | What it does |
90
+ | --- | --- |
91
+ | `afuctx doctor [HOST]` | Check host → AFU → model end to end; fixes what AFU can and gives concrete steps for the rest |
92
+ | `afuctx off [HOST]` | Pause: the host talks to its model directly; AFU's installation, logs and summaries are kept |
93
+ | `afuctx on [HOST]` | Resume |
94
+ | `afuctx repair codex --network` | Find and verify the proxy route to the model service again (`repair claude` for Claude Code) |
95
+ | `afuctx gc --dry-run` | List old runtimes and logs that can be cleaned; without `--dry-run` it cleans them |
96
+
65
97
  ## When something goes wrong
66
98
 
67
99
  | What you see | Do first |
@@ -69,6 +101,9 @@ Inside a host session:
69
101
  | After installing, the host cannot connect or keeps reconnecting | `afuctx off`: the host talks to its model directly right away. Then `afuctx doctor` to find the cause, and `afuctx on` once fixed |
70
102
  | Status says the model service is unreachable | `afuctx doctor` (or, for the network only, `afuctx repair codex --network`) |
71
103
  | A proxy app keeps the host from reaching AFU on this machine | Add `127.0.0.1` and `localhost` to the proxy app's bypass/exception list (for example AntFamily); `afuctx doctor` checks this |
104
+ | Install reports `UPSTREAM_UNREACHABLE` | AFU could not reach the model service and changed nothing; install again from a terminal with your proxy set (`HTTPS_PROXY`) |
105
+ | `HOST_CONFIG_INVALID` | Codex itself cannot read `~/.codex/config.toml` (for example a duplicate key) and AFU left it unchanged; fix it in an editor and retry |
106
+ | `CONFIGURATION_CONFLICT` | Codex or you were changing the settings at the same time and AFU did not overwrite them; retry shortly |
72
107
  | Settings or hooks were damaged | Run the install command again |
73
108
  | No compaction after a reboot | Open a host session once (its hook starts AFU) |
74
109
  | You no longer want AFU | `remove`: the host's settings return to how they were before install |
@@ -95,27 +130,14 @@ In a LongBench V2 replay of 39 history questions (20 agent histories and 19 dial
95
130
 
96
131
  ### Open the dashboard
97
132
 
98
- | Where | Type |
99
- | --- | --- |
100
- | In a Claude Code session | `/afuctx:dashboard` |
101
- | In a Codex session | `$afuctx-dashboard` |
102
- | In a Pi or DSH session | `/afuctx-dashboard` |
103
- | In a terminal | `afuctx dashboard` |
133
+ Open it from a host session or a terminal; see [Commands · Status and dashboard](#commands).
104
134
 
105
135
  - The dashboard runs in the background and does not occupy a terminal; opening it again reuses the same one, and it exits after 30 minutes without an open page.
106
136
  - It opens in the dark theme; switch to light, follow-system or English/Chinese in the top-right corner.
107
- - The terminal commands are placed in `~/.local/bin` by the installer for every host, creating the folder when needed. Shell startup files are never edited (the installer prints the line to add when the folder is not on `PATH`) and an existing command of the same name is kept (the installer says so). They are removed with the last integration, whichever host that is.
108
137
 
109
138
  ### Check the current session
110
139
 
111
- Type `/afuctx:status` in Claude Code, `$afuctx-status` in Codex, `/afuctx-status` in Pi or DSH, or run `afuctx status` in a terminal. It shows whether AFU is connected, the current context against the compaction threshold, and how many compactions have been applied.
112
-
113
- Without the terminal commands (for example when `~/.local/bin` is not on `PATH`), use the full npx commands. For Codex; for another host replace `codex` with `claude`, `pi` or `dsh`:
114
-
115
- ```sh
116
- npx --yes --registry=https://registry.npmjs.org afucontext@0.1.19 status codex --brief
117
- npx --yes --registry=https://registry.npmjs.org afucontext@0.1.19 ui
118
- ```
140
+ Run `afuctx status`, or the status command inside a host session (see [Commands](#commands)). It shows whether AFU is connected, the current context against the compaction threshold, and how many compactions have been applied.
119
141
 
120
142
  ### What the dashboard shows
121
143
 
@@ -150,49 +172,4 @@ If a window is still unknown, chat continues and `/afuctx:status` or `$afuctx-st
150
172
 
151
173
  ### Set the window or ratio manually
152
174
 
153
- Run the same install command with options, then start a new session. For Codex; for another host replace `codex` with `claude`, `pi` or `dsh`.
154
-
155
- | To | Option |
156
- | --- | --- |
157
- | Compact earlier or later | `--ratio 0.3` (between 0 and 1) |
158
- | Set the model window | `--context-window 200000` |
159
- | Restore automatic settings | `--context-window auto --ratio auto` |
160
-
161
- ```sh
162
- # Trigger at 30% of a manually set 200,000-token window (60,000 tokens)
163
- npx --yes --registry=https://registry.npmjs.org afucontext@0.1.19 install codex --context-window 200000 --ratio 0.3
164
- # Restore automatic settings
165
- npx --yes --registry=https://registry.npmjs.org afucontext@0.1.19 install codex --context-window auto --ratio auto
166
- ```
167
-
168
- For frequent use, run `npm install -g --registry=https://registry.npmjs.org afucontext@0.1.19` and use `afuctx` in place of the full `npx` invocation. For example, `afuctx dashboard --prices ./afu-prices.json` opens the dashboard with your price file to estimate costs.
169
-
170
- ## Upgrade and remove
171
-
172
- After upgrading a Claude Code or Codex integration, start a new session to use the new gateway. To uninstall, remove the host integration first, then restart the host. Use the appropriate command below.
173
-
174
- To move every installed integration (Claude Code, Codex, Pi and each DSH profile) to the latest release in one step, run `update` with `@latest`. It upgrades them one by one with the settings they were installed with and prints the version change for each:
175
-
176
- ```sh
177
- npx --yes --registry=https://registry.npmjs.org afucontext@latest update
178
- ```
179
-
180
- To check which version you have, run `--version` (the launcher), or `status --brief`, which shows the installed version of each host:
181
-
182
- ```sh
183
- npx --yes --registry=https://registry.npmjs.org afucontext@latest --version
184
- npx --yes --registry=https://registry.npmjs.org afucontext@latest status --brief
185
- ```
186
-
187
- To upgrade or remove one host:
188
-
189
- ```sh
190
- npx --yes --registry=https://registry.npmjs.org afucontext@0.1.19 upgrade codex
191
- npx --yes --registry=https://registry.npmjs.org afucontext@0.1.19 remove codex
192
- ```
193
-
194
- Use `remove pi` or `remove dsh` for those integrations. In Windows PowerShell, use `npx.cmd` and double-quote the package name.
195
-
196
- The dashboard listens on loopback. Logs record usage and receipts, and Pi/DSH also persist summaries in local session state. Generating summaries uses model tokens. Savings depend on subsequent reuse and actual cache hits.
197
-
198
- [Apache-2.0](LICENSE)
175
+ To compact earlier or later, or to set the model window, run `afuctx install` with options; see [Commands · When to compact](#commands).
package/README.zh-CN.md CHANGED
@@ -16,17 +16,17 @@
16
16
 
17
17
  ## 快速开始
18
18
 
19
- 先安装并登录要使用的宿主,准备 npm、Node.js **22.19+(22.x)或 24+** 和 Python **3.11+**(需在 `PATH` 中)。选一行,在终端执行安装命令,然后用最后一列的命令启动。
19
+ 先安装并登录要使用的宿主,准备 npm、Node.js **22.19+(22.x)或 24+** 和 Python **3.11+**(需在 `PATH` 中)。选一行,在终端执行安装命令(第一次 npx 会问一次是否安装,回车确认即可),然后用最后一列的命令启动。装好后,再加别的宿主、升级、卸载都用 `afuctx`,见[命令](#commands)。
20
20
 
21
21
  | 宿主 | 系统 | 一键安装 | 安装后启动 | 实测版本 |
22
22
  | --- | --- | --- | --- | --- |
23
- | <a id="afu-claude"></a>Claude Code | macOS / Linux | `npx --yes --registry=https://registry.npmjs.org afucontext@0.1.19 install claude` | `claude` | 2.1.293 |
24
- | <a id="afu-codex"></a>Codex CLI | macOS / Linux | `npx --yes --registry=https://registry.npmjs.org afucontext@0.1.19 install codex` | `codex` | 0.153.4 |
25
- | <a id="afu-pi"></a>Pi | macOS / Linux | `npx --yes --registry=https://registry.npmjs.org afucontext@0.1.19 install pi` | `pi` | 0.84.4、1.5.0 |
26
- | <a id="afu-dsh"></a>DSH | macOS / Linux | `npx --yes --registry=https://registry.npmjs.org afucontext@0.1.19 install dsh --profile YOUR_PROFILE` | `dsh --profile YOUR_PROFILE` | 0.2.2-rc.1 |
27
- | Codex CLI | Windows 10/11¹ | `npx.cmd --yes --registry=https://registry.npmjs.org "afucontext@0.1.19" install codex` | `codex` | 预览,未实测,下一版本正式提供 |
28
- | Pi | Windows 10/11¹ | `npx.cmd --yes --registry=https://registry.npmjs.org "afucontext@0.1.19" install pi` | `pi` | 预览,未实测,下一版本正式提供 |
29
- | DSH | Windows 10/11¹ | `npx.cmd --yes --registry=https://registry.npmjs.org "afucontext@0.1.19" install dsh --profile YOUR_PROFILE` | `dsh --profile YOUR_PROFILE` | 预览,未实测,下一版本正式提供 |
23
+ | <a id="afu-claude"></a>Claude Code | macOS / Linux | `npx afucontext@latest install claude` | `claude` | 2.1.293 |
24
+ | <a id="afu-codex"></a>Codex CLI | macOS / Linux | `npx afucontext@latest install codex` | `codex` | 0.153.4 |
25
+ | <a id="afu-pi"></a>Pi | macOS / Linux | `npx afucontext@latest install pi` | `pi` | 0.84.4、1.5.0 |
26
+ | <a id="afu-dsh"></a>DSH | macOS / Linux | `npx afucontext@latest install dsh --profile YOUR_PROFILE` | `dsh --profile YOUR_PROFILE` | 0.2.2-rc.1 |
27
+ | Codex CLI | Windows 10/11¹ | `npx.cmd "afucontext@latest" install codex` | `codex` | 预览,未实测,下一版本正式提供 |
28
+ | Pi | Windows 10/11¹ | `npx.cmd "afucontext@latest" install pi` | `pi` | 预览,未实测,下一版本正式提供 |
29
+ | DSH | Windows 10/11¹ | `npx.cmd "afucontext@latest" install dsh --profile YOUR_PROFILE` | `dsh --profile YOUR_PROFILE` | 预览,未实测,下一版本正式提供 |
30
30
 
31
31
  支持 macOS(Apple Silicon)和 x64 Linux;安装后新开会话即可。
32
32
 
@@ -36,25 +36,37 @@
36
36
 
37
37
  <a id="results"></a>
38
38
 
39
- ## 命令一览
39
+ <a id="commands"></a>
40
40
 
41
- 终端命令(`afuctx …`)在首次安装任一宿主后放到 `~/.local/bin`,目录不存在时会自动创建。该目录不在 `PATH` 时,安装程序会提示:把 `export PATH="$HOME/.local/bin:$PATH"` 加到 `~/.bashrc` 或 `~/.zshrc`,或者把 `afuctx` 换成 `npx --yes --registry=https://registry.npmjs.org afucontext@latest`。安装、升级、移除这类会替换运行时本身的命令,始终用 npx 执行。
41
+ ## 命令
42
+
43
+ 装好后在终端用 `afuctx`。它在首次安装任一宿主后放到 `~/.local/bin`,目录不存在时自动创建;不改 shell 配置(目录不在 `PATH` 时,安装程序会提示把 `export PATH="$HOME/.local/bin:$PATH"` 加到 `~/.bashrc` 或 `~/.zshrc`),不覆盖你已有的同名命令,移除最后一个宿主时一并删除。没有 `afuctx` 时(Windows,或 `~/.local/bin` 不在 `PATH` 中),把 `afuctx` 换成 `npx afucontext@latest`;Windows PowerShell 用 `npx.cmd "afucontext@latest"`。
44
+
45
+ 下面的"宿主"是 `claude`、`codex`、`pi` 或 `dsh`;DSH 都要加 `--profile 名称`。
46
+
47
+ ### 安装、升级、卸载
48
+
49
+ | 命令 | 作用 |
50
+ | --- | --- |
51
+ | `npx afucontext@latest install 宿主` | 第一次安装 |
52
+ | `afuctx install 宿主` | 再加一个宿主 |
53
+ | `afuctx install dsh --runtime-only` | 只准备运行时,配合 `dsh plugin --profile 名称 add afucontext-dsh-plugin` 使用 |
54
+ | `afuctx update` | 把已装的所有宿主一次升级到最新版,按安装时的设置逐个升级,并打印每个的版本变化 |
55
+ | `afuctx upgrade 宿主` | 只升级一个宿主 |
56
+ | `afuctx remove 宿主` | 卸载,宿主配置恢复成安装前的样子;DSH 加 `--profile` 只移除一个 profile,省略则移除全部 |
57
+
58
+ `afuctx install`、`update`、`upgrade`、`remove` 会自动从 npm 取最新版执行。升级 Claude Code 或 Codex 后新开会话即用上新版;卸载后重启宿主。
59
+
60
+ ### 查看状态和面板
42
61
 
43
62
  | 命令 | 作用 |
44
63
  | --- | --- |
45
- | `npx --yes --registry=https://registry.npmjs.org afucontext@latest install claude\|codex\|pi\|dsh` | 安装到指定宿主;DSH 加 `--profile 名称` |
46
- | `npx --yes --registry=https://registry.npmjs.org afucontext@latest install dsh --runtime-only` | 只准备运行时,配合 `dsh plugin --profile 名称 add afucontext-dsh-plugin` 使用 |
47
- | `npx --yes --registry=https://registry.npmjs.org afucontext@latest update` | 把本机已装的所有宿主一次升级到这个版本 |
48
- | `npx --yes --registry=https://registry.npmjs.org afucontext@latest remove 宿主` | 移除,宿主配置恢复成安装前的样子;DSH 可加 `--profile 名称` 只移除一个 profile |
49
- | `afuctx status` | 各宿主是否接入、当前上下文离触发线多远、已压缩几次;加 `--json` 输出完整信息 |
64
+ | `afuctx` | 最近几个会话的简要状态 |
65
+ | `afuctx status [宿主]` | 是否接入、当前上下文离触发线多远、已压缩几次;`--brief` 简要(含各宿主装的版本),`--json` 完整信息 |
50
66
  | `afuctx dashboard` | 打开本地面板(同 `afuctx-admin`);`--prices 文件` 用自己的单价估算费用 |
51
- | `afuctx doctor` | 检查"宿主 → AFU → 模型"整条链路,能修的直接修,修不了的给出具体步骤;加宿主名只查一个 |
52
- | `afuctx off` / `afuctx on` | 暂停 / 恢复:暂停时宿主直连模型,AFU 的安装、日志、摘要都保留;加宿主名只作用于一个 |
53
- | `afuctx repair codex --network` | 重新查找并验证连到模型服务的代理(Claude Code 用 `repair claude`) |
54
- | `afuctx gc --dry-run` | 查看可清理的旧版本运行时和日志;去掉 `--dry-run` 才会真正清理 |
55
67
  | `afuctx --version` / `afuctx --help` | 版本号 / 帮助 |
56
68
 
57
- 宿主会话里也可以直接用:
69
+ 宿主会话里:
58
70
 
59
71
  | 宿主 | 查看状态 | 打开面板 |
60
72
  | --- | --- | --- |
@@ -62,6 +74,26 @@
62
74
  | Codex | `$afuctx-status` | `$afuctx-dashboard` |
63
75
  | Pi / DSH | `/afuctx-status` | `/afuctx-dashboard` |
64
76
 
77
+ ### 调整压缩时机
78
+
79
+ | 命令 | 作用 |
80
+ | --- | --- |
81
+ | `afuctx install 宿主 --ratio 0.3` | 提前或推迟压缩,取值 0 到 1 之间 |
82
+ | `afuctx install 宿主 --context-window 200000` | 手动指定模型窗口 |
83
+ | `afuctx install 宿主 --context-window auto --ratio auto` | 恢复自动 |
84
+
85
+ 两个参数可以一起用,例如 `--context-window 200000 --ratio 0.3` 即在 60,000 tokens 触发。改完后新开会话生效。
86
+
87
+ ### 排查和维护
88
+
89
+ | 命令 | 作用 |
90
+ | --- | --- |
91
+ | `afuctx doctor [宿主]` | 检查"宿主 → AFU → 模型"整条链路,能修的直接修,修不了的给出具体步骤 |
92
+ | `afuctx off [宿主]` | 暂停:宿主直连模型,AFU 的安装、日志、摘要都保留 |
93
+ | `afuctx on [宿主]` | 恢复 |
94
+ | `afuctx repair codex --network` | 重新查找并验证连到模型服务的代理(Claude Code 用 `repair claude`) |
95
+ | `afuctx gc --dry-run` | 查看可清理的旧版本运行时和日志;去掉 `--dry-run` 才会真正清理 |
96
+
65
97
  ## 出问题时怎么办
66
98
 
67
99
  | 现象 | 先做 |
@@ -69,6 +101,9 @@
69
101
  | 装了以后宿主连不上、一直重连 | `afuctx off`,宿主立即恢复直连模型;之后运行 `afuctx doctor` 查原因,修好后 `afuctx on` |
70
102
  | 状态提示连不上模型服务 | `afuctx doctor`(只查网络也可以 `afuctx repair codex --network`) |
71
103
  | 代理软件导致连不上本机 AFU | 在代理软件(如 AntFamily)的例外 / 绕过列表里加入 `127.0.0.1` 和 `localhost`;`afuctx doctor` 会检查 |
104
+ | 安装报 `UPSTREAM_UNREACHABLE` | AFU 连不上模型服务,什么都没改;在设置了代理(`HTTPS_PROXY`)的终端里重新安装 |
105
+ | 报 `HOST_CONFIG_INVALID` | Codex 自己读不了 `~/.codex/config.toml`(比如有重复的键),AFU 没有改动它;用编辑器修好后重试 |
106
+ | 报 `CONFIGURATION_CONFLICT` | 执行期间 Codex 或你正在改配置,AFU 没有覆盖;稍后重试 |
72
107
  | 配置或 hook 被改坏 | 重新执行安装命令 |
73
108
  | 重启后不压缩 | 开一次宿主会话(hook 会拉起 AFU) |
74
109
  | 彻底不用 | `remove`,宿主配置恢复成安装前的样子 |
@@ -95,27 +130,14 @@ AFU 连续几次连不上模型服务时,会自动重新查找并验证一条
95
130
 
96
131
  ### 打开面板
97
132
 
98
- | 在哪里 | 输入 |
99
- | --- | --- |
100
- | Claude Code 会话里 | `/afuctx:dashboard` |
101
- | Codex 会话里 | `$afuctx-dashboard` |
102
- | Pi / DSH 会话里 | `/afuctx-dashboard` |
103
- | 终端里 | `afuctx dashboard` |
133
+ 在宿主会话里或终端里打开,命令见[命令 · 查看状态和面板](#commands)。
104
134
 
105
135
  - 面板在后台运行,不占用终端;再次打开会复用同一个面板,30 分钟没有页面打开时自动退出。
106
136
  - 默认暗色主题,右上角可切换亮色、跟随系统和中英文。
107
- - 终端命令由安装程序放在 `~/.local/bin`,四个宿主都会放,目录不存在时自动创建。不改 shell 配置(目录不在 `PATH` 时会提示要加的那一行),不覆盖你已有的同名命令(会提示未覆盖)。移除最后一个接入时一并删除,不论是哪个宿主。
108
137
 
109
138
  ### 查看当前会话
110
139
 
111
- Claude Code 输入 `/afuctx:status`,Codex 输入 `$afuctx-status`,Pi 和 DSH 输入 `/afuctx-status`,终端里运行 `afuctx status`。会显示 AFU 是否已接入、当前上下文距离压缩触发线还有多少,以及已经生效的压缩次数。
112
-
113
- 没有上面的终端命令时(例如 `~/.local/bin` 不在 `PATH` 中),可以用完整的 npx 命令。以 Codex 为例,其它宿主将 `codex` 换成 `claude`、`pi` 或 `dsh`:
114
-
115
- ```sh
116
- npx --yes --registry=https://registry.npmjs.org afucontext@0.1.19 status codex --brief
117
- npx --yes --registry=https://registry.npmjs.org afucontext@0.1.19 ui
118
- ```
140
+ 用 `afuctx status` 或宿主会话里的状态命令(见[命令](#commands))。会显示 AFU 是否已接入、当前上下文距离压缩触发线还有多少,以及已经生效的压缩次数。
119
141
 
120
142
  ### 面板内容
121
143
 
@@ -150,49 +172,4 @@ npx --yes --registry=https://registry.npmjs.org afucontext@0.1.19 ui
150
172
 
151
173
  ### 手动指定窗口和调整比例
152
174
 
153
- 用同一条安装命令加参数即可,改完后新开会话生效。下面以 Codex 为例,其它宿主将 `codex` 换成 `claude`、`pi` 或 `dsh`。
154
-
155
- | 想做的事 | 参数 |
156
- | --- | --- |
157
- | 提前或推迟压缩 | `--ratio 0.3`(取值 0 到 1 之间) |
158
- | 手动指定模型窗口 | `--context-window 200000` |
159
- | 恢复自动 | `--context-window auto --ratio auto` |
160
-
161
- ```sh
162
- # 在 30% 触发,并手动指定 200,000 的窗口(即 60,000 触发)
163
- npx --yes --registry=https://registry.npmjs.org afucontext@0.1.19 install codex --context-window 200000 --ratio 0.3
164
- # 恢复自动设置
165
- npx --yes --registry=https://registry.npmjs.org afucontext@0.1.19 install codex --context-window auto --ratio auto
166
- ```
167
-
168
- 如果经常使用 AFU,可运行 `npm install -g --registry=https://registry.npmjs.org afucontext@0.1.19`,以后用 `afuctx` 代替完整的 `npx` 命令。例如,`afuctx dashboard --prices ./afu-prices.json` 用自己的单价文件打开面板估算费用。
169
-
170
- ## 升级与移除
171
-
172
- 升级 Claude Code 或 Codex 接入后,新开会话即可使用新版网关。需要移除时,先撤销对应宿主的接入,再重启宿主。以下两条命令分别用于升级和移除。
173
-
174
- 想把已装的所有接入(Claude Code、Codex、Pi 和每个 DSH profile)一次升级到最新版,用 `@latest` 执行 `update`。它会按安装时的设置逐个升级,并打印每个接入从哪个版本升到哪个版本:
175
-
176
- ```sh
177
- npx --yes --registry=https://registry.npmjs.org afucontext@latest update
178
- ```
179
-
180
- 查看版本:`--version` 显示启动器版本,`status --brief` 显示每个宿主当前装的版本:
181
-
182
- ```sh
183
- npx --yes --registry=https://registry.npmjs.org afucontext@latest --version
184
- npx --yes --registry=https://registry.npmjs.org afucontext@latest status --brief
185
- ```
186
-
187
- 只升级或移除某一个宿主:
188
-
189
- ```sh
190
- npx --yes --registry=https://registry.npmjs.org afucontext@0.1.19 upgrade codex
191
- npx --yes --registry=https://registry.npmjs.org afucontext@0.1.19 remove codex
192
- ```
193
-
194
- Pi 和 DSH 可分别用 `remove pi` 或 `remove dsh` 撤销。Windows PowerShell 请使用 `npx.cmd` 并将包名放在双引号中。
195
-
196
- 本地面板只监听回环地址。日志记录用量和回执,Pi/DSH 的本地会话状态还会保存摘要。生成摘要本身会调用模型,节省多少取决于后续复用和实际缓存命中。
197
-
198
- [Apache-2.0](LICENSE)
175
+ 提前或推迟压缩、手动指定模型窗口,用 `afuctx install` 加参数,见[命令 · 调整压缩时机](#commands)。
package/bin/afu.mjs CHANGED
@@ -13,6 +13,12 @@ const root=resolve(dirname(fileURLToPath(import.meta.url)),'..');
13
13
  const manifest=JSON.parse(readFileSync(join(root,'release.json'),'utf8'));
14
14
  const env={...process.env,AFU_INSTALL_ROOT:root};
15
15
  let args=process.argv.slice(2);
16
+ // State lives in the user's home directory; files written as root through
17
+ // sudo become unreadable for that user. Root's own login is fine.
18
+ if(process.platform!=='win32'&&process.getuid?.()===0&&process.env.SUDO_USER&&!['--version','-v','version','--help','-h','help'].includes(args[0]??'--help')){
19
+ console.error('afucontext: do not run AFU under sudo. AFU keeps its state in your home directory, and files written as root become unreadable for you. Run the same command again without sudo.');
20
+ process.exit(2);
21
+ }
16
22
  if(['install','upgrade','status','remove','gc','native','repair','off','on','doctor'].includes(args[0])){
17
23
  const at=args.indexOf('--state');if(at>=0&&args[at+1])env.AFU_STATE_DIR=resolve(args[at+1]);
18
24
  const inline=args.find(a=>a.startsWith('--state='));if(inline&&inline.length>8)env.AFU_STATE_DIR=resolve(inline.slice(8));
@@ -77,8 +83,8 @@ try{
77
83
  // Only the bare launcher prints its own banner; "afu ui --help" and
78
84
  // "afu claude --help" belong to the subcommand or the host.
79
85
  if(!args.length || (['--help','-h'].includes(args[0]))){
80
- const pkg=manifest.name||'afucontext',npx=`npx --yes --registry=https://registry.npmjs.org ${pkg}@latest`;
81
- console.log(`afuctx ${manifest.version}: AFU Context, local context compression for coding agents\n\n ${npx} install [claude|codex|pi|dsh]\n ${npx} update upgrade every installed host\n ${npx} remove HOST\n ${npx} status [HOST]\n ${npx} dashboard open the local dashboard\n ${npx} gc --dry-run\n ${npx} --version\n\nAfter installing, the same commands are on PATH as afuctx (status, dashboard, --help, --version) and afuctx-admin (dashboard). Host login remains managed by the host.`);
86
+ const pkg=manifest.name||'afucontext',npx=`npx ${pkg}@latest`;
87
+ console.log(`afuctx ${manifest.version}: AFU Context, local context compression for coding agents\n\n ${npx} install [claude|codex|pi|dsh]\n ${npx} update upgrade every installed host\n ${npx} remove HOST\n ${npx} status [HOST]\n ${npx} dashboard open the local dashboard\n ${npx} gc --dry-run\n ${npx} --version\n\nAfter installing, the same commands are on PATH as afuctx (status, dashboard, --help, --version) and afuctx-admin (dashboard); afuctx install, update and remove run this package from npm. Host login remains managed by the host.`);
82
88
  process.exit(0);
83
89
  }
84
90
  if(['--version','-v','version'].includes(args[0])){console.log(manifest.version);process.exit(0);}
@@ -401,6 +401,10 @@ def remove_record(host, record):
401
401
 
402
402
 
403
403
  def main():
404
+ from afu_context.local_cli import SUDO_REFUSAL, under_sudo
405
+ if under_sudo():
406
+ print(SUDO_REFUSAL, file=sys.stderr)
407
+ raise SystemExit(2)
404
408
  p = argparse.ArgumentParser()
405
409
  p.add_argument("action", choices=["install", "upgrade", "remove", "status"])
406
410
  p.add_argument("host", choices=["pi", "dsh"], nargs="?")
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "afucontext",
3
- "version": "0.1.19",
3
+ "version": "0.1.21",
4
4
  "type": "module",
5
5
  "license": "Apache-2.0",
6
6
  "description": "Local asynchronous context compression and diagnostics",
package/release.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
- "version": "0.1.19",
2
+ "version": "0.1.21",
3
3
  "name": "afucontext",
4
- "build": "62194a699342a041d610236ff46479044e6b87083142681a5c44094355291435",
5
- "wheel": "afu_context_local-0.1.19-py3-none-any.whl",
4
+ "build": "ac2723431caf1b88720c948ddd41fd3cf9e4f5079e6c4bb5af426bc52693d59c",
5
+ "wheel": "afu_context_local-0.1.21-py3-none-any.whl",
6
6
  "prebuilt": false
7
7
  }
@@ -1,5 +1,5 @@
1
1
  /** Compose a disposable overlay using DSH's own YAML and patch semantics. */
2
- import {readFileSync, writeFileSync, realpathSync} from 'node:fs';
2
+ import {readFileSync, writeFileSync, realpathSync, existsSync} from 'node:fs';
3
3
  import {createRequire} from 'node:module';
4
4
  import {join,isAbsolute,dirname} from 'node:path';
5
5
  import {pathToFileURL} from 'node:url';
@@ -86,8 +86,9 @@ if(process.argv[1] && import.meta.url===pathToFileURL(process.argv[1]).href) {
86
86
  writeFileSync(presetModule, `import Native from ${JSON.stringify(pathToFileURL(native).href)};\nimport {presetAdapter} from ${JSON.stringify(new URL('./dsh-presets.mjs',import.meta.url).href)};\nexport default presetAdapter(Native, ${JSON.stringify(moduleReference(process.argv[2]))}, ${JSON.stringify(process.argv[3])});\n`, {mode:0o600});
87
87
  } catch (error) { if(error.code!=='MODULE_NOT_FOUND') throw error; }
88
88
  }
89
- // The commands module sits beside the provider module (commands.mjs).
90
- const commands=process.argv[2] ? moduleReference(join(dirname(process.argv[2]),'commands.mjs')) : undefined;
89
+ // The commands module sits beside the provider module: commands.mjs in an
90
+ // installed bundle (host-autoload), commands.js in a source checkout.
91
+ const commands=process.argv[2] ? moduleReference(['commands.mjs','commands.js'].map(n=>join(dirname(process.argv[2]),n)).find(p=>existsSync(p)) ?? join(dirname(process.argv[2]),'commands.mjs')) : undefined;
91
92
  const patches=overlay(tree,moduleReference(process.argv[2]),presetModule && moduleReference(presetModule),commands);
92
93
  if (process.argv[5]==='web-compat') {
93
94
  const picker=tree.find(row=>!row.disabled && row.name==='@deepseek-ai/dsh-host-directory-picker-auto');
@@ -135,10 +135,23 @@ export class CompactDshEngine extends BasicCompactionEngine {
135
135
  if (!this.bindings.has(binding.key) && this.bindings.size >= 16)
136
136
  throw new Error("DSH binding limit reached");
137
137
  this.bindings.set(binding.key, binding);
138
- const request = dshMessagesToRequest(messages, binding.key, mode);
138
+ const request = dshMessagesToRequest(messages, binding.key, mode, binding.contextWindow);
139
139
  const tokens = dshContextTokens(this.ctx, agent);
140
+ if (tokens === undefined && !dshHasMeter(this.ctx))
141
+ this.noteUnmeasured(agent);
140
142
  return tokens === undefined ? request : { ...request, metadata: { ...request.metadata, host_context_tokens: tokens } };
141
143
  }
144
+ /** Sessions already reported as running without DSH's token meter. */
145
+ unmeasured = new Set();
146
+ noteUnmeasured(agent) {
147
+ if (this.unmeasured.has(agent.session.id))
148
+ return;
149
+ this.unmeasured.add(agent.session.id);
150
+ if (this.unmeasured.size > 256)
151
+ this.unmeasured.delete(this.unmeasured.values().next().value);
152
+ // The trigger then follows AFU's own count of the text (see compression.py).
153
+ this.log("host_measure_unavailable", { session: sessionHash(agent.session.id) });
154
+ }
142
155
  async compactIfNeeded(agent, trigger, signal) {
143
156
  // afuctx off: DSH's own compaction, unchanged.
144
157
  if (afuPaused("dsh"))
@@ -354,6 +367,15 @@ function dshRemovedTokens(result) {
354
367
  const text = result.summary.map(b => b.type === "text" ? b.text : "").join("");
355
368
  return Math.max(0, shadowed - Math.ceil(text.length / 4));
356
369
  }
370
+ /** Whether this DSH mounts a token meter at all (it reads 0 before a session's first request). */
371
+ function dshHasMeter(ctx) {
372
+ try {
373
+ return typeof ctx.tokenMeter?.measure === "function";
374
+ }
375
+ catch {
376
+ return false;
377
+ }
378
+ }
357
379
  /** DSH's own token meter (the measure its native compaction uses), if available. */
358
380
  function dshContextTokens(ctx, agent) {
359
381
  try {
@@ -365,7 +387,7 @@ function dshContextTokens(ctx, agent) {
365
387
  return undefined;
366
388
  }
367
389
  }
368
- export function dshMessagesToRequest(messages, sessionId, mode = "active") {
390
+ export function dshMessagesToRequest(messages, sessionId, mode = "active", contextWindow) {
369
391
  const groups = toolCallGroups(messages);
370
392
  const items = messages.map((message) => {
371
393
  const content = normalizeContent(message.content);
@@ -391,7 +413,9 @@ export function dshMessagesToRequest(messages, sessionId, mode = "active") {
391
413
  return {
392
414
  schema_version: "1",
393
415
  session_id: sessionId,
394
- token_budget: Math.max(20_000, estimatedTokens),
416
+ // The model's window when known: the trigger is min(budget, window *
417
+ // ratio), so a budget equal to the estimate would make it the trigger.
418
+ token_budget: Number.isSafeInteger(contextWindow) && contextWindow > 0 ? contextWindow : Math.max(20_000, estimatedTokens),
395
419
  items,
396
420
  query: "",
397
421
  mode,