charness 3.3.2 → 3.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +639 -0
- package/DEVELOPMENT.md +76 -0
- package/README.md +78 -7
- package/SETUP.md +65 -19
- package/dist/adapters/claudeCliAdapter.js +2 -2
- package/dist/adapters/claudeCliAdapter.js.map +1 -1
- package/dist/adapters/claudeConfigDir.d.ts +18 -0
- package/dist/adapters/claudeConfigDir.d.ts.map +1 -1
- package/dist/adapters/claudeJsonStreamAdapter.d.ts +8 -1
- package/dist/adapters/claudeJsonStreamAdapter.d.ts.map +1 -1
- package/dist/adapters/claudeJsonStreamAdapter.js +24 -6
- package/dist/adapters/claudeJsonStreamAdapter.js.map +1 -1
- package/dist/adapters/createAdapter.d.ts +2 -1
- package/dist/adapters/createAdapter.d.ts.map +1 -1
- package/dist/adapters/createAdapter.js +16 -0
- package/dist/adapters/createAdapter.js.map +1 -1
- package/dist/adapters/openCodeAdapter.d.ts +11 -0
- package/dist/adapters/openCodeAdapter.d.ts.map +1 -1
- package/dist/adapters/openCodeAdapter.js +24 -9
- package/dist/adapters/openCodeAdapter.js.map +1 -1
- package/dist/agentLogin/agentLogin.d.ts +19 -1
- package/dist/agentLogin/agentLogin.d.ts.map +1 -1
- package/dist/agentLogin/agentLogin.js +64 -18
- package/dist/agentLogin/agentLogin.js.map +1 -1
- package/dist/apiErrorRetry.d.ts +3 -1
- package/dist/apiErrorRetry.d.ts.map +1 -1
- package/dist/apiErrorRetry.js +11 -1
- package/dist/apiErrorRetry.js.map +1 -1
- package/dist/bot.d.ts +0 -3
- package/dist/bot.d.ts.map +1 -1
- package/dist/bot.js +487 -182
- package/dist/bot.js.map +1 -1
- package/dist/changelogEntries.d.ts +25 -0
- package/dist/changelogEntries.d.ts.map +1 -0
- package/dist/changelogEntries.js +66 -0
- package/dist/changelogEntries.js.map +1 -0
- package/dist/cli/bot.d.ts +6 -2
- package/dist/cli/bot.d.ts.map +1 -1
- package/dist/cli/bot.js +34 -2
- package/dist/cli/bot.js.map +1 -1
- package/dist/cli/claudeProfiles.d.ts +1 -1
- package/dist/cli/claudeProfiles.d.ts.map +1 -1
- package/dist/cli/claudeProfiles.js +11 -6
- package/dist/cli/claudeProfiles.js.map +1 -1
- package/dist/cli/hot.d.ts +7 -0
- package/dist/cli/hot.d.ts.map +1 -1
- package/dist/cli/hot.js +53 -3
- package/dist/cli/hot.js.map +1 -1
- package/dist/cli.d.ts +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +8 -0
- package/dist/cli.js.map +1 -1
- package/dist/connectors/telegram/bindPicker.d.ts +64 -0
- package/dist/connectors/telegram/bindPicker.d.ts.map +1 -0
- package/dist/connectors/telegram/bindPicker.js +97 -0
- package/dist/connectors/telegram/bindPicker.js.map +1 -0
- package/dist/connectors/telegram/commands/claudeAccounts.d.ts +6 -2
- package/dist/connectors/telegram/commands/claudeAccounts.d.ts.map +1 -1
- package/dist/connectors/telegram/commands/claudeAccounts.js +127 -28
- package/dist/connectors/telegram/commands/claudeAccounts.js.map +1 -1
- package/dist/connectors/telegram/commands/fallbackChain.d.ts.map +1 -1
- package/dist/connectors/telegram/commands/fallbackChain.js +6 -2
- package/dist/connectors/telegram/commands/fallbackChain.js.map +1 -1
- package/dist/connectors/telegram/commands/selfUpdate.d.ts +16 -0
- package/dist/connectors/telegram/commands/selfUpdate.d.ts.map +1 -0
- package/dist/connectors/telegram/commands/selfUpdate.js +210 -0
- package/dist/connectors/telegram/commands/selfUpdate.js.map +1 -0
- package/dist/connectors/telegram/commands/stt.d.ts +1 -0
- package/dist/connectors/telegram/commands/stt.d.ts.map +1 -1
- package/dist/connectors/telegram/commands/stt.js +5 -0
- package/dist/connectors/telegram/commands/stt.js.map +1 -1
- package/dist/connectors/telegram/commands/topicCommand.d.ts +75 -0
- package/dist/connectors/telegram/commands/topicCommand.d.ts.map +1 -0
- package/dist/connectors/telegram/commands/topicCommand.js +391 -0
- package/dist/connectors/telegram/commands/topicCommand.js.map +1 -0
- package/dist/i18n/de.d.ts.map +1 -1
- package/dist/i18n/de.js +136 -3
- package/dist/i18n/de.js.map +1 -1
- package/dist/i18n/en.d.ts.map +1 -1
- package/dist/i18n/en.js +136 -3
- package/dist/i18n/en.js.map +1 -1
- package/dist/i18n/es.d.ts.map +1 -1
- package/dist/i18n/es.js +136 -3
- package/dist/i18n/es.js.map +1 -1
- package/dist/i18n/fr.d.ts.map +1 -1
- package/dist/i18n/fr.js +136 -3
- package/dist/i18n/fr.js.map +1 -1
- package/dist/i18n/hi.d.ts.map +1 -1
- package/dist/i18n/hi.js +136 -3
- package/dist/i18n/hi.js.map +1 -1
- package/dist/i18n/ja.d.ts.map +1 -1
- package/dist/i18n/ja.js +136 -3
- package/dist/i18n/ja.js.map +1 -1
- package/dist/i18n/ka.d.ts.map +1 -1
- package/dist/i18n/ka.js +136 -3
- package/dist/i18n/ka.js.map +1 -1
- package/dist/i18n/pt.d.ts.map +1 -1
- package/dist/i18n/pt.js +136 -3
- package/dist/i18n/pt.js.map +1 -1
- package/dist/i18n/ru.d.ts.map +1 -1
- package/dist/i18n/ru.js +136 -3
- package/dist/i18n/ru.js.map +1 -1
- package/dist/i18n/uk.d.ts.map +1 -1
- package/dist/i18n/uk.js +136 -3
- package/dist/i18n/uk.js.map +1 -1
- package/dist/i18n/uz.d.ts.map +1 -1
- package/dist/i18n/uz.js +136 -3
- package/dist/i18n/uz.js.map +1 -1
- package/dist/i18n/zh.d.ts.map +1 -1
- package/dist/i18n/zh.js +136 -3
- package/dist/i18n/zh.js.map +1 -1
- package/dist/instanceSettings.d.ts +12 -1
- package/dist/instanceSettings.d.ts.map +1 -1
- package/dist/instanceSettings.js +40 -4
- package/dist/instanceSettings.js.map +1 -1
- package/dist/scheduler/mcpSurface.d.ts.map +1 -1
- package/dist/scheduler/mcpSurface.js +4 -2
- package/dist/scheduler/mcpSurface.js.map +1 -1
- package/dist/selfUpdate/bootRollback.d.ts +22 -0
- package/dist/selfUpdate/bootRollback.d.ts.map +1 -0
- package/dist/selfUpdate/bootRollback.js +79 -0
- package/dist/selfUpdate/bootRollback.js.map +1 -0
- package/dist/selfUpdate/commandRunner.d.ts +21 -0
- package/dist/selfUpdate/commandRunner.d.ts.map +1 -0
- package/dist/selfUpdate/commandRunner.js +32 -0
- package/dist/selfUpdate/commandRunner.js.map +1 -0
- package/dist/selfUpdate/constants.d.ts +26 -0
- package/dist/selfUpdate/constants.d.ts.map +1 -0
- package/dist/selfUpdate/constants.js +31 -0
- package/dist/selfUpdate/constants.js.map +1 -0
- package/dist/selfUpdate/gitSource.d.ts +58 -0
- package/dist/selfUpdate/gitSource.d.ts.map +1 -0
- package/dist/selfUpdate/gitSource.js +183 -0
- package/dist/selfUpdate/gitSource.js.map +1 -0
- package/dist/selfUpdate/hostLock.d.ts +16 -0
- package/dist/selfUpdate/hostLock.d.ts.map +1 -0
- package/dist/selfUpdate/hostLock.js +101 -0
- package/dist/selfUpdate/hostLock.js.map +1 -0
- package/dist/selfUpdate/hotSupervisor.d.ts +47 -0
- package/dist/selfUpdate/hotSupervisor.d.ts.map +1 -0
- package/dist/selfUpdate/hotSupervisor.js +125 -0
- package/dist/selfUpdate/hotSupervisor.js.map +1 -0
- package/dist/selfUpdate/installKind.d.ts +45 -0
- package/dist/selfUpdate/installKind.d.ts.map +1 -0
- package/dist/selfUpdate/installKind.js +99 -0
- package/dist/selfUpdate/installKind.js.map +1 -0
- package/dist/selfUpdate/launchEnvironment.d.ts +3 -0
- package/dist/selfUpdate/launchEnvironment.d.ts.map +1 -0
- package/dist/selfUpdate/launchEnvironment.js +16 -0
- package/dist/selfUpdate/launchEnvironment.js.map +1 -0
- package/dist/selfUpdate/npmSource.d.ts +34 -0
- package/dist/selfUpdate/npmSource.d.ts.map +1 -0
- package/dist/selfUpdate/npmSource.js +107 -0
- package/dist/selfUpdate/npmSource.js.map +1 -0
- package/dist/selfUpdate/releaseNotes.d.ts +33 -0
- package/dist/selfUpdate/releaseNotes.d.ts.map +1 -0
- package/dist/selfUpdate/releaseNotes.js +115 -0
- package/dist/selfUpdate/releaseNotes.js.map +1 -0
- package/dist/selfUpdate/restart.d.ts +33 -0
- package/dist/selfUpdate/restart.d.ts.map +1 -0
- package/dist/selfUpdate/restart.js +94 -0
- package/dist/selfUpdate/restart.js.map +1 -0
- package/dist/selfUpdate/selfCheck.d.ts +20 -0
- package/dist/selfUpdate/selfCheck.d.ts.map +1 -0
- package/dist/selfUpdate/selfCheck.js +126 -0
- package/dist/selfUpdate/selfCheck.js.map +1 -0
- package/dist/selfUpdate/semver.d.ts +24 -0
- package/dist/selfUpdate/semver.d.ts.map +1 -0
- package/dist/selfUpdate/semver.js +165 -0
- package/dist/selfUpdate/semver.js.map +1 -0
- package/dist/selfUpdate/types.d.ts +51 -0
- package/dist/selfUpdate/types.d.ts.map +1 -0
- package/dist/selfUpdate/types.js +3 -0
- package/dist/selfUpdate/types.js.map +1 -0
- package/dist/selfUpdate/updateEngine.d.ts +110 -0
- package/dist/selfUpdate/updateEngine.d.ts.map +1 -0
- package/dist/selfUpdate/updateEngine.js +727 -0
- package/dist/selfUpdate/updateEngine.js.map +1 -0
- package/dist/selfUpdate/updateMessages.d.ts +84 -0
- package/dist/selfUpdate/updateMessages.d.ts.map +1 -0
- package/dist/selfUpdate/updateMessages.js +115 -0
- package/dist/selfUpdate/updateMessages.js.map +1 -0
- package/dist/selfUpdate/updateModes.d.ts +17 -0
- package/dist/selfUpdate/updateModes.d.ts.map +1 -0
- package/dist/selfUpdate/updateModes.js +14 -0
- package/dist/selfUpdate/updateModes.js.map +1 -0
- package/dist/selfUpdate/updatePending.d.ts +76 -0
- package/dist/selfUpdate/updatePending.d.ts.map +1 -0
- package/dist/selfUpdate/updatePending.js +131 -0
- package/dist/selfUpdate/updatePending.js.map +1 -0
- package/dist/selfUpdate/updatePolicy.d.ts +115 -0
- package/dist/selfUpdate/updatePolicy.d.ts.map +1 -0
- package/dist/selfUpdate/updatePolicy.js +83 -0
- package/dist/selfUpdate/updatePolicy.js.map +1 -0
- package/dist/selfUpdate/updateRuntime.d.ts +22 -0
- package/dist/selfUpdate/updateRuntime.d.ts.map +1 -0
- package/dist/selfUpdate/updateRuntime.js +148 -0
- package/dist/selfUpdate/updateRuntime.js.map +1 -0
- package/dist/startupPromptBuffer.d.ts +2 -0
- package/dist/startupPromptBuffer.d.ts.map +1 -1
- package/dist/startupPromptBuffer.js +4 -0
- package/dist/startupPromptBuffer.js.map +1 -1
- package/dist/state.d.ts +43 -0
- package/dist/state.d.ts.map +1 -1
- package/dist/state.js +54 -0
- package/dist/state.js.map +1 -1
- package/dist/types.d.ts +10 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/anthropicApiKeyCheck.d.ts +19 -0
- package/dist/utils/anthropicApiKeyCheck.d.ts.map +1 -0
- package/dist/utils/anthropicApiKeyCheck.js +41 -0
- package/dist/utils/anthropicApiKeyCheck.js.map +1 -0
- package/dist/utils/claudeAccountPickerPlan.d.ts +6 -1
- package/dist/utils/claudeAccountPickerPlan.d.ts.map +1 -1
- package/dist/utils/claudeAccountPickerPlan.js +5 -1
- package/dist/utils/claudeAccountPickerPlan.js.map +1 -1
- package/dist/utils/claudeApiKeyHelper.d.ts +19 -0
- package/dist/utils/claudeApiKeyHelper.d.ts.map +1 -0
- package/dist/utils/claudeApiKeyHelper.js +32 -0
- package/dist/utils/claudeApiKeyHelper.js.map +1 -0
- package/dist/utils/claudeApiSpend.d.ts +73 -0
- package/dist/utils/claudeApiSpend.d.ts.map +1 -0
- package/dist/utils/claudeApiSpend.js +82 -0
- package/dist/utils/claudeApiSpend.js.map +1 -0
- package/dist/utils/claudeCompactHook.d.ts +11 -6
- package/dist/utils/claudeCompactHook.d.ts.map +1 -1
- package/dist/utils/claudeCompactHook.js +28 -11
- package/dist/utils/claudeCompactHook.js.map +1 -1
- package/dist/utils/claudeLimitSwitch.d.ts +2 -1
- package/dist/utils/claudeLimitSwitch.d.ts.map +1 -1
- package/dist/utils/claudeLimitSwitch.js +3 -2
- package/dist/utils/claudeLimitSwitch.js.map +1 -1
- package/dist/utils/claudeProfileUsageLines.d.ts +18 -3
- package/dist/utils/claudeProfileUsageLines.d.ts.map +1 -1
- package/dist/utils/claudeProfileUsageLines.js +23 -2
- package/dist/utils/claudeProfileUsageLines.js.map +1 -1
- package/dist/utils/claudeProfiles.d.ts +57 -2
- package/dist/utils/claudeProfiles.d.ts.map +1 -1
- package/dist/utils/claudeProfiles.js +96 -3
- package/dist/utils/claudeProfiles.js.map +1 -1
- package/dist/utils/claudeStreamJson.d.ts +4 -1
- package/dist/utils/claudeStreamJson.d.ts.map +1 -1
- package/dist/utils/claudeStreamJson.js +6 -0
- package/dist/utils/claudeStreamJson.js.map +1 -1
- package/dist/utils/claudeTranscriptContent.d.ts +8 -0
- package/dist/utils/claudeTranscriptContent.d.ts.map +1 -1
- package/dist/utils/claudeTranscriptContent.js +44 -0
- package/dist/utils/claudeTranscriptContent.js.map +1 -1
- package/dist/utils/claudeUsage.d.ts +22 -6
- package/dist/utils/claudeUsage.d.ts.map +1 -1
- package/dist/utils/claudeUsage.js +12 -5
- package/dist/utils/claudeUsage.js.map +1 -1
- package/dist/utils/claudeUsageRefresher.d.ts +6 -0
- package/dist/utils/claudeUsageRefresher.d.ts.map +1 -1
- package/dist/utils/claudeUsageRefresher.js +2 -2
- package/dist/utils/claudeUsageRefresher.js.map +1 -1
- package/dist/utils/fallbackChain.d.ts +15 -8
- package/dist/utils/fallbackChain.d.ts.map +1 -1
- package/dist/utils/fallbackChain.js +30 -13
- package/dist/utils/fallbackChain.js.map +1 -1
- package/dist/utils/limitsBoardPlan.d.ts +4 -2
- package/dist/utils/limitsBoardPlan.d.ts.map +1 -1
- package/dist/utils/limitsBoardPlan.js +12 -5
- package/dist/utils/limitsBoardPlan.js.map +1 -1
- package/dist/utils/recvPreviewRedaction.d.ts +7 -2
- package/dist/utils/recvPreviewRedaction.d.ts.map +1 -1
- package/dist/utils/recvPreviewRedaction.js +10 -4
- package/dist/utils/recvPreviewRedaction.js.map +1 -1
- package/dist/utils/threadStatusReport.d.ts +12 -1
- package/dist/utils/threadStatusReport.d.ts.map +1 -1
- package/dist/utils/threadStatusReport.js +13 -4
- package/dist/utils/threadStatusReport.js.map +1 -1
- package/dist/utils/updateScreenPlan.d.ts +38 -0
- package/dist/utils/updateScreenPlan.d.ts.map +1 -0
- package/dist/utils/updateScreenPlan.js +143 -0
- package/dist/utils/updateScreenPlan.js.map +1 -0
- package/package.json +3 -1
package/DEVELOPMENT.md
CHANGED
|
@@ -89,6 +89,30 @@ owner = the `charness hot` supervisor (a worker reload keeps the sidecar) or the
|
|
|
89
89
|
the sidecar polls its owner and exits within ~2 s of its death, even after a SIGKILL.
|
|
90
90
|
```
|
|
91
91
|
|
|
92
|
+
### Self-update (the bot updates itself)
|
|
93
|
+
|
|
94
|
+
`src/selfUpdate/` (its README has the contracts) is an engine over ports: `updatePolicy.ts` decides, `updateEngine.ts` runs
|
|
95
|
+
the hourly check, the idle loop and the boot step against fakes in tests, `updateRuntime.ts` binds it to this process
|
|
96
|
+
(install kind, npm / git sources, host lock), `bot.ts` supplies the settings, the idle verdict and General. Three facts to
|
|
97
|
+
keep when touching the restart path:
|
|
98
|
+
|
|
99
|
+
- **A restart in place is `process.execve`** (the same pid) of `node <packageRoot>/dist/cli.js <original arguments>` with
|
|
100
|
+
the environment as it was at launch — `cli.ts`'s FIRST import snapshots it, so an edited `.env` is read afresh. Nothing
|
|
101
|
+
may be imported before `launchEnvironment`.
|
|
102
|
+
- **The hot supervisor re-executes itself** when a file it loaded changed: at start it writes `DATA_DIR/hot-supervisor.json`
|
|
103
|
+
(pid, start token, hash of every loaded `dist/` module); a new worker compares it with `dist/` and, at its idle point,
|
|
104
|
+
sends `SIGUSR2` — only when pid and start token match. The supervisor stops `tsc -w` and nodemon, leaves the OpenCode
|
|
105
|
+
server and the speech sidecar alone and `execve`s `cli.js hot`. A supervisor that predates this has no record and is
|
|
106
|
+
never signalled (an unhandled `SIGUSR2` kills a process).
|
|
107
|
+
- **`update-pending.json` is written BEFORE the switch**; every boot counts itself in (`cli/bot.ts`, once the instance lock is held and before the bot
|
|
108
|
+
module is imported), the boot after two unconfirmed ones rolls back, the running bot confirms 60 s after launch.
|
|
109
|
+
|
|
110
|
+
The flows run it for real: `selfUpdateNpmE2e` (a loopback registry — `e2e/fakeNpmRegistry.ts` — and a real global install into
|
|
111
|
+
a temp prefix), `selfUpdateCheckoutE2e` (a checkout copy, a bare remote and a second clone — `e2e/checkoutFixture.ts`),
|
|
112
|
+
`selfUpdateHotE2e` (the real `charness hot`), `selfUpdateEntrypointE2e` (the image's own `docker/entrypoint.sh` and
|
|
113
|
+
`restart-bot.sh` with their paths pointed into a temp folder — the one thing it cannot run is the container itself). The
|
|
114
|
+
harness writes `settings.json` with `autoUpdate: off` for every instance, so no flow updates the checkout it runs from.
|
|
115
|
+
|
|
92
116
|
## Local development
|
|
93
117
|
|
|
94
118
|
```bash
|
|
@@ -129,3 +153,55 @@ docker compose down charness && docker compose up -d charness # examples/docke
|
|
|
129
153
|
docker compose logs -f charness # tail logs
|
|
130
154
|
docker exec charness-main charness-restart-bot # restart only the bot; agents keep running
|
|
131
155
|
```
|
|
156
|
+
|
|
157
|
+
## Releases
|
|
158
|
+
|
|
159
|
+
Two workflows. **`.github/workflows/test.yml` (`Tests`)** runs typecheck, build and the FULL `yarn test` on every push to
|
|
160
|
+
`main`. **`.github/workflows/publish.yml`** releases charness to npm without anyone doing anything: every day at 09:17
|
|
161
|
+
(Asia/Tbilisi) it decides by itself: nothing shipped changed → a green run, no tag, no publish; otherwise it checks the tests
|
|
162
|
+
of the commit it would release (below), checks the package, commits `chore(release): X.Y.Z`, tags `vX.Y.Z`, publishes to the
|
|
163
|
+
`latest` dist-tag with provenance (npm trusted publishing from the `release` environment, no npm token anywhere) and creates
|
|
164
|
+
the GitHub Release from the CHANGELOG section. Red anywhere → no tag, no publish, the run is red; the next day's run tries
|
|
165
|
+
again by itself. The logic is in `src/release/` (pure `releasePlan.ts` and `testGate.ts` + the `cli.ts` wrapper, run by
|
|
166
|
+
`tsx`, never built into `dist/`).
|
|
167
|
+
|
|
168
|
+
- **Tests gate:** the release does not run the suite again when the exact commit already passed. It asks GitHub for the
|
|
169
|
+
`Tests` workflow's runs of that commit's SHA (the newest run of the commit decides): **passed** → go on; **no run at all**
|
|
170
|
+
(a manual dispatch before CI ran) → the release runs the suite itself; **failed or still running** → the daily run
|
|
171
|
+
releases nothing that day and ends green with the reason (a red head is not skipped over to an older green commit), a
|
|
172
|
+
manual dispatch or a hand-pushed tag fails with it. The release commit may differ from the tested one ONLY in
|
|
173
|
+
`package.json`'s `"version"` line and `CHANGELOG.md`: `verify-delta` checks the diff before the tag and again in the publish
|
|
174
|
+
job (the tag against the tested SHA) and refuses otherwise. A hand-pushed tag (`npm version`, then push `main` with the tag) is gated through its
|
|
175
|
+
PARENT: when the commit before the tag has a green `Tests` run and the tag differs from it only in the version and the CHANGELOG,
|
|
176
|
+
that run is the gate — the tag's own run, started by the same push, is not waited for. When the parent is not green or the tag
|
|
177
|
+
carries more than the bump, the tagged commit's own run decides (still running → refused: re-run the release once it is green).
|
|
178
|
+
- **Version** (Conventional Commits since the last `v*` tag): a `feat` that changes shipped code → minor; any other
|
|
179
|
+
shipped change (`fix`, `perf`, `refactor`, `revert`, `chore`, …) → patch; `chore(release)` commits never count. A `!`
|
|
180
|
+
after the type or a `BREAKING CHANGE:` footer in ANY commit makes the automatic run **fail**, naming the commits: a
|
|
181
|
+
major is released only by dispatching the workflow with `bump=major`.
|
|
182
|
+
- **Nothing to release** (green, nothing tagged): no commits since the last tag, `HEAD` already tagged, or no shipped
|
|
183
|
+
path in the net diff from the tag — `src/**/*.ts` outside `src/__tests__` and `src/release`, `stt/gigaam_sidecar.py`,
|
|
184
|
+
and `package.json` only when `dependencies`, `bin`, `engines`, `files` or `main` differ. A docs-only or tests-only
|
|
185
|
+
day, or a change and its revert, publishes nothing; README / SETUP changes reach the npm page with the next code
|
|
186
|
+
release.
|
|
187
|
+
- **Manual run** (Actions → Release to npm → Run workflow): `bump` `auto|patch|minor|major`; `force` releases even when
|
|
188
|
+
the skip rules say skip (never past the breaking-change guard of `auto`); `dryRun` does everything but the push, the
|
|
189
|
+
publish and the GitHub Release and prints the plan, the CHANGELOG diff, the notes and the package check.
|
|
190
|
+
- **By hand:** `npm version minor` locally (its `preversion` runs typecheck, build and the tests, its
|
|
191
|
+
`version` script moves the CHANGELOG heading, `.npmrc` gives the commit npm's message `chore(release): X.Y.Z`), then
|
|
192
|
+
push `main` with the tag; the workflow gates that tag on its commit's `Tests` run (above) and publishes it.
|
|
193
|
+
- **CHANGELOG:** `## Unreleased` becomes `## X.Y.Z — YYYY-MM-DD` (Tbilisi date) with a fresh empty `## Unreleased`
|
|
194
|
+
above; that section is the GitHub Release text and ships inside the package. Every entry of it — a top-level
|
|
195
|
+
paragraph or `- ` bullet, in any `###` subsection — starts with a bold first sentence (`**…**`); the run fails,
|
|
196
|
+
quoting the line, otherwise (`changelogFormat.test.ts` fails first on a commit that breaks it). An empty
|
|
197
|
+
`## Unreleased` is filled with the `feat` / `fix` subjects.
|
|
198
|
+
- **Package check** before any tag: the tarball holds `dist/cli.js`, `stt/gigaam_sidecar.py`, `CHANGELOG.md`,
|
|
199
|
+
`README.md`, `LICENSE` and no `src/` or tests, and `charness --version` of it, installed into a temp prefix, prints
|
|
200
|
+
the new version (`yarn tsx src/release/cli.ts check-pack`, after `yarn build`). `bin` paths are written
|
|
201
|
+
`dist/cli.js`, never `./dist/cli.js`: npm >= 11.10 silently drops a "./" entry from the manifest it publishes (3.3.0
|
|
202
|
+
reached the registry without its commands), so `check-pack` and `packageManifest.test.ts` refuse one, and
|
|
203
|
+
`check-publish` (`npm publish --dry-run`, run before the tag and again right before the publish) refuses a package.json
|
|
204
|
+
that npm reports it would drop or rewrite anything from.
|
|
205
|
+
- **After a release** the clone is one commit behind `main`: `git pull --rebase` before pushing. A new CHANGELOG entry
|
|
206
|
+
goes under `## Unreleased` (a push that races the release can conflict there; the run then fails with nothing
|
|
207
|
+
published).
|
package/README.md
CHANGED
|
@@ -27,6 +27,7 @@ These hold whichever surface you drive it from — the same core serves all of t
|
|
|
27
27
|
- **Sleeping agents** — a Claude json-stream topic's process is stopped when idle (or after every turn in per-turn mode) and the next message resumes the same conversation by itself, prompt cache still warm
|
|
28
28
|
- **Several Claude accounts** — keep more than one Claude subscription signed in side by side and choose per topic which one a session runs on (`/accounts`); every account's usage windows are shown next to it, and `/limits` is a one-tap switch board over all of them and over the OpenCode providers. See [Several accounts](#several-accounts-accounts)
|
|
29
29
|
- **Waits out usage limits** — when the agent hits a usage / session limit the bot reads the reset time out of the error (honouring the timezone the provider quotes; a mere warning such as `Approaching session limit · resets …` or the switch onto extra usage is not a limit), waits, then tells the agent to continue by itself and pins the "work resumed" message so a muted topic still notifies you; `/limits_autoswitch` turns waiting off per topic and `/limits` skips a single resume. With a **fallback chain** (`/limits_autoswitch`: other Claude accounts, OpenCode providers and models, in your order of preference) the limit notice offers «🔁 Switch to …» buttons to move the topic to the next entry with room and continue at once — or the bot does it by itself when you turn switching on; across backends the new agent gets a context bridge with the previous one's last turns
|
|
30
|
+
- **Updates itself** — checks for a new version hourly, installs it when no agent is working, restarts in place (same process, agents keep running) and says in General what changed; npm installs and git checkouts, hot mode and Docker included. Off with `/update` in General. See [Updating](SETUP.md#updating)
|
|
30
31
|
- **Restart-safe** — agents run as external processes (tmux, `opencode serve`) that the bot re-adopts after a restart instead of killing them; a prompt sent while a session boots is buffered and replayed. See [Restart behaviour](#restart-behaviour)
|
|
31
32
|
|
|
32
33
|
### Telegram
|
|
@@ -94,7 +95,7 @@ actually start an agent or terminal in the folder.
|
|
|
94
95
|
| `/terminal` | Open a raw `$SHELL` in the bound folder — see [Raw terminal](#raw-terminal-terminal-telegram) |
|
|
95
96
|
| `/claude_mode` | Switch this topic's Claude backend (json-stream ⇄ per-turn ⇄ tmux-scrape); bare shows a picker — see [Claude Code backends](#claude-code-backends-claude_mode) |
|
|
96
97
|
| `/model` | Switch model through a two-level picker: providers, then that provider's models (10 per page). On OpenCode the first row is 🕘 Recently used — a flat list of the models picked before, across providers (bot-wide, most recent first, up to 10), one tap to switch; it appears once something has been picked. Each provider row has a 🙈 to hide it from the picker (bot-wide, persisted; 👁 brings it back) — `/model <provider/model>` still reaches a hidden provider. If OpenCode is waiting on an old provider's retry, the next prompt interrupts that wait and starts with the selected model instead of sitting queued behind it |
|
|
97
|
-
| `/accounts` | Every account the bot works with, on one screen. **Claude accounts** (when you keep several subscriptions signed in): each profile with its email, plan (personal Pro/Max or corporate Team/Enterprise), how many topics use it and its usage windows, ✓ on the active one; tap a profile to switch this topic (a running session is restarted under it, same conversation — at the end of its turn if it is working; on a topic that runs OpenCode the tap switches the topic to Claude on that account, after a confirmation when there is a conversation to hand over); in **General** the pick becomes the default for all topics. The title says where the topic really runs (`Claude «work»`, `OpenCode openai/gpt-5`) and the ✓ sits on that row — on no account while OpenCode runs. Per profile: 🔑 signs it in again, 🗑 removes it (after a confirmation; for `default`, which IS `~/.claude`, «remove» signs it out — see below). The usage lines give each window's percentage USED and when it resets as a time from now (`5h 5% 🔄 in 4h · week 20% 🔄 in 5d 8h · Fable 4% 🔄 in 5d 8h`; «🔄 in 2h», «🔄 in 2d 1h», «🔄 in 30m»; Fable only on a plan that has its own weekly window); when the 5h window's reset is unknown the weekly one is shown in its place, and with no reset at all only the percentage. The hint paragraph under the account list says the percentages are used. «➕ Claude account» asks for a name and runs the sign-in. **OpenCode providers**: the connected ones are listed with how each is signed in (`ChatGPT subscription` with its ~5 h / ~7 d usage windows like an account's, `API key`). In a topic a provider row is `[provider] [🔑] [🔌]`: a tap switches the topic to the provider through its model page (✓ on the model it runs, ⛔ on a limited one; a provider with one model is picked at once), 🔑 connects it again, 🔌 disconnects it (it asks, then removes the stored credentials; a provider OpenCode enables from an environment variable, e.g. `OPENROUTER_API_KEY`, stays active — the reply says so and points at hiding it in `/model`); in **General** a provider row is «🔌 Disconnect <provider>» and 🔑 only; «➕ OpenCode provider» asks for the provider id and continues with the connect flow (OAuth methods when available, otherwise an API key whose message is deleted from Telegram). What happens when an account hits a usage limit is set in `/limits_autoswitch`. Text forms: `/accounts add <name>`, `/accounts use <name>`, `/accounts use <provider>/<model>` (an OpenCode model, in a topic), `/accounts login <name>`, `/accounts remove <name>`, `/accounts autoswitch on\|off`. `/account`, `/connect [provider [key]]` and `/disconnect [provider]` still work as hidden aliases (the menu lists only `/accounts`). See [Several accounts](#several-accounts-accounts) |
|
|
98
|
+
| `/accounts` | Every account the bot works with, on one screen. **Claude accounts** (when you keep several subscriptions signed in): each profile with its email, plan (personal Pro/Max or corporate Team/Enterprise), how many topics use it and its usage windows, ✓ on the active one; tap a profile to switch this topic (a running session is restarted under it, same conversation — at the end of its turn if it is working; on a topic that runs OpenCode the tap switches the topic to Claude on that account, after a confirmation when there is a conversation to hand over); in **General** the pick becomes the default for all topics. The title says where the topic really runs (`Claude «work»`, `OpenCode openai/gpt-5`) and the ✓ sits on that row — on no account while OpenCode runs. Per profile: 🔑 signs it in again, 🗑 removes it (after a confirmation; for `default`, which IS `~/.claude`, «remove» signs it out — see below). The usage lines give each window's percentage USED and when it resets as a time from now (`5h 5% 🔄 in 4h · week 20% 🔄 in 5d 8h · Fable 4% 🔄 in 5d 8h`; «🔄 in 2h», «🔄 in 2d 1h», «🔄 in 30m»; Fable only on a plan that has its own weekly window); when the 5h window's reset is unknown the weekly one is shown in its place, and with no reset at all only the percentage. The hint paragraph under the account list says the percentages are used. «➕ Claude account» asks for a name and runs the sign-in; «➕ Claude API account (Console credits)» adds an account billed to a Claude Console organization's API credits (`💳`, see [An account billed to API credits](#an-account-billed-to-api-credits-claude-console)). **OpenCode providers**: the connected ones are listed with how each is signed in (`ChatGPT subscription` with its ~5 h / ~7 d usage windows like an account's, `API key`). In a topic a provider row is `[provider] [🔑] [🔌]`: a tap switches the topic to the provider through its model page (✓ on the model it runs, ⛔ on a limited one; a provider with one model is picked at once), 🔑 connects it again, 🔌 disconnects it (it asks, then removes the stored credentials; a provider OpenCode enables from an environment variable, e.g. `OPENROUTER_API_KEY`, stays active — the reply says so and points at hiding it in `/model`); in **General** a provider row is «🔌 Disconnect <provider>» and 🔑 only; «➕ OpenCode provider» asks for the provider id and continues with the connect flow (OAuth methods when available, otherwise an API key whose message is deleted from Telegram). What happens when an account hits a usage limit is set in `/limits_autoswitch`. Text forms: `/accounts add <name>`, `/accounts add <name> api`, `/accounts use <name>`, `/accounts use <provider>/<model>` (an OpenCode model, in a topic), `/accounts login <name>`, `/accounts remove <name>`, `/accounts autoswitch on\|off`. `/account`, `/connect [provider [key]]` and `/disconnect [provider]` still work as hidden aliases (the menu lists only `/accounts`). See [Several accounts](#several-accounts-accounts) |
|
|
98
99
|
| `/effort` | Reasoning effort. **In a topic:** shows the level its session runs and where the next start's level comes from («medium — as in General» / «high — set for this topic»; a running session keeps the level it started with when General moves on: «xhigh (medium from the next start) — as in General») with a button per level — Claude: the native `/effort` levels (`low…ultracode`); OpenCode: the current model's variants, applied per-prompt; General's `ultracode` is the model's highest variant and `auto` sends no variant — and «As in General (medium)», named with the level the topic will really get (OpenCode: rounded to the model's variants), which drops the topic's own pick (a live session is brought to the default at once). **In General:** the default effort for every topic that has no effort of its own (✓ on the current one; `medium` until you pick), saved to `settings.json` and applied from each topic's next session start or wake-up — running sessions are not restarted. No env configuration — see [Instance settings](SETUP.md#instance-settings-settingsjson) |
|
|
99
100
|
| `/verbosity` | Output-verbosity macro (`minimal\|short\|full`): sets the thinking, tool-results and sub-agent display prefs at once; `/thinking`, `/tool_results`, `/subagent` point-override afterwards. Mixed prefs show as "custom" in the picker. The picker's second row (or `/verbosity stream\|stream_answers\|answers`) sets what the topic SHOWS — "Stream only" (default), "Stream + answers" (the stream plus the agent's pinned answers) or "Answers only" (the pinned answers, no stream; an agent that keeps writing after its final answer is reminded once to send what matters); the answers are written like for a manager or QA — brief and to the point; a switch applies from the next message, and `/status` names the view |
|
|
100
101
|
| `/thinking` | Chain-of-thought display: `full` keeps the reasoning, `short` collapses to "💭 thought for Ns", `minimal` keeps only the live working cue |
|
|
@@ -104,11 +105,11 @@ actually start an agent or terminal in the folder.
|
|
|
104
105
|
| `/rename_session` | Rename the current live session (OpenCode; Claude transcripts have no title) |
|
|
105
106
|
| `/quit`, `/q` | End the session — Claude: graceful double Ctrl+C; OpenCode/terminal: `stopSession`. Releases the persisted session id, so a bot restart won't auto-reattach it (resume later via `/sessions`). A topic whose agent process is gone but whose session is kept (it "sleeps": the next message, file, voice note, `/compact`, `/model` or `/effort` resumes it by itself) is released the same way |
|
|
106
107
|
| `/new`, `/clear_session` | End the current session and start a fresh one (same adapter) |
|
|
107
|
-
| `/status` | This thread's status: agent, bound folder, the Claude account it runs on and the resolved workdir; a live session also shows the model it is actually running, the effort it runs (when the default moved on under it: «xhigh (medium from the next start)»), start time, runtime version and context use (anything the backend cannot report renders as unknown). On a Claude topic the account is its profile (name · email as in `/accounts`, marked ⛔ while it is at its limit, with a second row for a switch still pending); an OpenCode topic's model already names its provider |
|
|
108
|
+
| `/status` | This thread's status: agent, bound folder, the Claude account it runs on and the resolved workdir; a live session also shows the model it is actually running, the effort it runs (when the default moved on under it: «xhigh (medium from the next start)»), start time, runtime version and context use (anything the backend cannot report renders as unknown). On a Claude topic the account is its profile (name · email as in `/accounts`, `· 💳 API` for an account billed to API credits — with a line of what it spent through the bot — marked ⛔ while it is at its limit, with a second row for a switch still pending); an OpenCode topic's model already names its provider |
|
|
108
109
|
| `/output` | Last 500 lines of agent output (sent as at most 5 chunks; the overflow is reported as omitted) |
|
|
109
110
|
| `/c`, `/y`, `/n` | Ctrl+C / "y" / "n" |
|
|
110
111
|
| `/enter`, `/up`, `/down`, `/tab` | tmux key passthrough |
|
|
111
|
-
| `/esc`, `/escape` |
|
|
112
|
+
| `/interrupt`, `/esc`, `/escape` | Interrupt the running turn — Claude gets a raw Escape (which also dismisses a selector), OpenCode aborts the generation; the conversation stays and your next message steers the agent. A question the agent is waiting on is closed first (rejected on OpenCode, declined on the Claude stream-json backends) and its buttons are retired. A pending sign-in, account-name prompt or `/topic` wizard is cancelled first instead (the agent is not interrupted). Not supported in a `/terminal` topic |
|
|
112
113
|
| `/schedule` | Schedule a prompt in free text — the agent parses the time and owns the job; see [Scheduler](#scheduler-schedule-telegram) |
|
|
113
114
|
| `/stt` | Voice recognition, from any topic (General included); instance-wide, applied to the next voice note — no restart. The main screen holds only what applies to recognition as a whole: the ordered list of **engines** (the first that works answers; when one fails the next takes over) — one full-width button each (`1. GigaAM (local) · running · 10s+25% · ✓` — name, the local engine's short state, timeout `base s + % of the voice`, ✓ usable / ✗ disabled or skipped) — then «➕ Add engine», «🌐 Language» (auto or `ru en uk de fr es`) and «✖️ Close». A tap on an engine opens its **card**: ⬆️ Up / ⬇️ Down, ✅ Use / 🚫 Don't use, ⏱ Timeout (presets), then what the kind adds — 🔑 key for **Groq**, **OpenAI** or a **custom** OpenAI-compatible server (its address, a base like `http://host:8000` is completed; then «does it need a key?»), and 🗑 Remove. A pasted key is deleted from the topic the moment it is accepted, never shown again and kept out of the logs; an address with a login in it is refused. **GigaAM (local)** (Russian only, runs on this machine) is added through «➕ Add engine» like the others: installed, it joins the list at once; not installed, a confirmation (≈ 400 MB on disk; ≈ 0.5 GB RAM while it runs, up to ≈ 0.9 GB on a long voice, nothing while stopped) leads to the install with a live progress message, and the message becomes its card. Its card holds everything local: the status line (ready · running / stopped / paused after failed starts / installing / not installed), «⏱ Exit after idle» (5 / 15 / 30 / 60 min or never), «⚙️ Workers» (1 / 2 / 4 / 8), «🔄 Try again now» (while paused), «Remove from list» (the files stay) and «🗑 Remove model files». Everything lives in one file, `stt.json` — see [Voice input](SETUP.md#voice-input). `/voice` and `/speech` are hidden aliases |
|
|
114
115
|
| `/reminders` | Reminders set with buttons only — the bot posts and pins them itself, with no agent involved; works in any topic, bound or not. See [Reminders](#reminders-reminders-telegram) |
|
|
@@ -117,9 +118,10 @@ actually start an agent or terminal in the folder.
|
|
|
117
118
|
| `/compact` | Compact the agent's context — a real, confirmed compaction on OpenCode and on the default (stream) Claude backend; the tmux Claude backend has the literal command forwarded (its TUI compacts); terminal: not supported |
|
|
118
119
|
| `/compact_on_idle` | Toggle auto-compaction after ~55 min idle (Enable/Disable picker; `AGENT_IDLE_MINUTES` sets the window). Per topic; run it in **General** to set the default for all topics. On by default. Each idle compaction posts one short notice; the picker's «Show summary» / «Hide summary» row (the `/compact_summary` switch) adds the agent's full summary after it. Fires at most once per active period (until you write again); if a question was pending it is re-asked with tappable buttons after the compaction. On the json-stream backends the idle mark also STOPS the agent process, compaction or not — the topic sleeps and your next message resumes it (`/status` says so) |
|
|
119
120
|
| `/compact_summary` | Toggle posting the agent's full summary after a compaction — `/compact`, the idle compaction and the agent's own `compact_conversation` (Enable/Disable picker). Per topic; run it in **General** to set the default for all topics. Off by default: a compaction ends in a short line. On OpenCode it also hides the summary OpenCode streams itself |
|
|
120
|
-
| `/limits` | The **switch board**: every signed-in Claude account and every connected OpenCode provider on one screen. The **message** carries the figures — `Usage (% used)` and a line per account in the same wording `/accounts` uses (`default — ⏱ 5h 14% 🔄 in 3h · week 3% 🔄 in 6d`; `⛔ at its limit until …` while the account is limited; `(stale)` when the last poll could not refresh), a provider signed in through a ChatGPT subscription after them (`openai (ChatGPT) — ⏱ 5h 12% 🔄 in 3h · week 40% 🔄 in 4d`), the two automatic-switching settings' state with a link to `/limits_autoswitch`, and the caption «Choose the active model:». The **buttons** are one full-width name each — `✓ Claude · work`, `Claude · default`, `OpenCode · openai` — with no figure on them (the figures do not fit a phone's button); ✓ marks where the topic runs; a signed-out account is not listed. **A tap switches this topic**: another Claude account (the running session restarts under it, same conversation — at the end of its turn when it is working), an OpenCode provider (opens its model page, 10 models per page with ⛔ on a limited one; a provider with one model switches at once), the ✓ row (the model page of where the topic runs: change the model). Across backends with a conversation to hand over the bot asks first (✅ Continue / ✖️ Cancel); while a usage-limit wait is armed the tap is the limit move — the wait ends and the work continues, no question — and «⏭ Skip once» is offered. An unbound topic is told to bind a folder first. In **General** a Claude row sets the default account for all topics (the caption reads «Choose the default Claude account:»), and an OpenCode row only says that a model is picked inside a topic. The limit notice names this command. The old text forms `/limits rebuild`, `/limits clear`, `/limits switch …`, `/limits wait …` still work (they are `/limits_autoswitch`'s verbs). See [Usage limits and the fallback models](#usage-limits-and-the-fallback-models-limits-and-limits_autoswitch) |
|
|
121
|
-
| `/limits_autoswitch` | The setup of automatic switching on a usage limit, with a short text: a title, what the topic runs on and where its two settings come from. **Fallback models** — an ordered list of Claude accounts (with an optional model) and OpenCode providers with a model, top = preferred, where a topic continues when its agent hits a limit. One full-width button per entry (`✓ 1. Claude · work · opus`, `2. Claude · default ⛔ 14:00`, `3. OpenCode · openai · gpt-5 🚫` — ✓ where the topic runs, ⛔ limited until, 🔒 not signed in, ❓ no longer offered, 🚫 left out of automatic switching); a tap opens that entry in the same message with ⬆️ Up / ⬇️ Down, 🚫 Don't use / ✅ Use (a left-out entry stays usable by hand through `/model` and `/accounts`), 🗑 Remove and ⬅️ Back. Below the list: «➕ Add» (account or provider, then the model; an entry of a backend the list does not use yet — an OpenCode model next to Claude accounts, or the reverse — asks first, because a limit then hands a conversation over in compacted form; including a 🚫 entry that does that asks the same way), «🔄 Fill from connected» (a draft from what is connected; entries you left out stay left out; asks first when a list exists), «🗑 Clear». The list is ONE instance-wide list and is editable from every topic. **Two settings** decide what a limit does: «🔁 Auto switch» — auto switch to a fallback model (OFF by default: the limit notice carries «🔁 Switch to …» buttons instead) and «⏳ Wait for reset» — wait for the reset and continue (ON by default; while a wait is armed the topic screen also offers «⏭ Skip once»). In General they are the defaults for all topics and each is one button that flips the value. In a regular topic each is one short full-width button showing the effective value (`🔁 Auto switch: ON`; one line of text above the list says where each value comes from — `🔁 as in General · ⏳ set for this topic`); a tap opens the setting in the same message with ON / OFF / «As in General (<the General value>)» — the topic's own choice marked ✓ — and ⬅️ Back, and a choice applies and returns to the screen. Switch ON: the topic moves to the first available entry at once. OFF: buttons on the notice, and if none is pressed the bot waits for the reset (waiting ON); both OFF: it only reports the limit. When every enabled entry, the current one included, is limited, the wait ends at the EARLIEST reset and the topic continues on that entry (the notice names it and the time). Text forms: `/limits_autoswitch rebuild`, `/limits_autoswitch clear`, `/limits_autoswitch switch on\|off\|same`, `/limits_autoswitch wait on\|off\|same` (the same verbs work after `/limits`). `/fallback` and `/auto_continue_limits [on\|off]` still work as hidden aliases. See [Usage limits and the fallback models](#usage-limits-and-the-fallback-models-limits-and-limits_autoswitch) |
|
|
121
|
+
| `/limits` | The **switch board**: every signed-in Claude account and every connected OpenCode provider on one screen. The **message** carries the figures — `Usage (% used)` and a line per account in the same wording `/accounts` uses (`default — ⏱ 5h 14% 🔄 in 3h · week 3% 🔄 in 6d`; `⛔ at its limit until …` while the account is limited; `(stale)` when the last poll could not refresh), a provider signed in through a ChatGPT subscription after them (`openai (ChatGPT) — ⏱ 5h 12% 🔄 in 3h · week 40% 🔄 in 4d`), the two automatic-switching settings' state with a link to `/limits_autoswitch`, and the caption «Choose the active model:». The **buttons** are one full-width name each — `✓ Claude · work`, `Claude · default`, `OpenCode · openai`, `Claude · console 💳` for an account billed to API credits — with no figure on them (the figures do not fit a phone's button); ✓ marks where the topic runs; a signed-out account is not listed. **A tap switches this topic**: another Claude account (the running session restarts under it, same conversation — at the end of its turn when it is working), an OpenCode provider (opens its model page, 10 models per page with ⛔ on a limited one; a provider with one model switches at once), the ✓ row (the model page of where the topic runs: change the model). Across backends with a conversation to hand over the bot asks first (✅ Continue / ✖️ Cancel); while a usage-limit wait is armed the tap is the limit move — the wait ends and the work continues, no question — and «⏭ Skip once» is offered. An unbound topic is told to bind a folder first. In **General** a Claude row sets the default account for all topics (the caption reads «Choose the default Claude account:»), and an OpenCode row only says that a model is picked inside a topic. The limit notice names this command. The old text forms `/limits rebuild`, `/limits clear`, `/limits switch …`, `/limits wait …` still work (they are `/limits_autoswitch`'s verbs). See [Usage limits and the fallback models](#usage-limits-and-the-fallback-models-limits-and-limits_autoswitch) |
|
|
122
|
+
| `/limits_autoswitch` | The setup of automatic switching on a usage limit, with a short text: a title, what the topic runs on and where its two settings come from. **Fallback models** — an ordered list of Claude accounts (with an optional model) and OpenCode providers with a model, top = preferred, where a topic continues when its agent hits a limit. One full-width button per entry (`✓ 1. Claude · work · opus`, `2. Claude · default ⛔ 14:00`, `3. OpenCode · openai · gpt-5 🚫` — ✓ where the topic runs, ⛔ limited until, 🔒 not signed in, ❓ no longer offered, 💸 API credits used up, 🚫 left out of automatic switching); a tap opens that entry in the same message with ⬆️ Up / ⬇️ Down, 🚫 Don't use / ✅ Use (a left-out entry stays usable by hand through `/model` and `/accounts`), 🗑 Remove and ⬅️ Back. Below the list: «➕ Add» (account or provider, then the model; an entry of a backend the list does not use yet — an OpenCode model next to Claude accounts, or the reverse — asks first, because a limit then hands a conversation over in compacted form; including a 🚫 entry that does that asks the same way), «🔄 Fill from connected» (a draft from what is connected; entries you left out stay left out; an account billed to API credits comes last and left out unless you had included it; asks first when a list exists), «🗑 Clear». The list is ONE instance-wide list and is editable from every topic. **Two settings** decide what a limit does: «🔁 Auto switch» — auto switch to a fallback model (OFF by default: the limit notice carries «🔁 Switch to …» buttons instead) and «⏳ Wait for reset» — wait for the reset and continue (ON by default; while a wait is armed the topic screen also offers «⏭ Skip once»). In General they are the defaults for all topics and each is one button that flips the value. In a regular topic each is one short full-width button showing the effective value (`🔁 Auto switch: ON`; one line of text above the list says where each value comes from — `🔁 as in General · ⏳ set for this topic`); a tap opens the setting in the same message with ON / OFF / «As in General (<the General value>)» — the topic's own choice marked ✓ — and ⬅️ Back, and a choice applies and returns to the screen. Switch ON: the topic moves to the first available entry at once. OFF: buttons on the notice, and if none is pressed the bot waits for the reset (waiting ON); both OFF: it only reports the limit. When every enabled entry, the current one included, is limited, the wait ends at the EARLIEST reset and the topic continues on that entry (the notice names it and the time). Text forms: `/limits_autoswitch rebuild`, `/limits_autoswitch clear`, `/limits_autoswitch switch on\|off\|same`, `/limits_autoswitch wait on\|off\|same` (the same verbs work after `/limits`). `/fallback` and `/auto_continue_limits [on\|off]` still work as hidden aliases. See [Usage limits and the fallback models](#usage-limits-and-the-fallback-models-limits-and-limits_autoswitch) |
|
|
122
123
|
| `/bind` | Bare: current binding + folder picker, with «leave current dir» (the old `/unbind`) and «create new folder» buttons |
|
|
124
|
+
| `/topic [name]` | Open another forum topic on a folder, without leaving this one. Asks the new topic's name (`/topic <name>` takes it from the command), then the folder: «📁 <folder> (as here)» — the folder this topic is bound to — or «📂 Other folder», which is the `/bind` picker with «create new folder»; in General and in an unbound topic the picker comes at once. Then the bot creates the topic (it needs the `can_manage_topics` right — `/doctor` checks it), binds it, shows the usual binding welcome there and turns the question into the answer with an «Open topic →» button. «✖️ Cancel» on the question and in the picker, and `/esc` at any step, end it. No agent starts by itself: start one in the new topic as in any bound topic. Works in the group only — in the bot's private chat it says so |
|
|
123
125
|
| `/mcp` | List MCP servers active for this thread |
|
|
124
126
|
|
|
125
127
|
#### Info / ops (work anywhere)
|
|
@@ -132,7 +134,8 @@ actually start an agent or terminal in the folder.
|
|
|
132
134
|
| `/list` | List existing topics and their bindings |
|
|
133
135
|
| `/status` | This topic's status; in General — a global view of all topics + active agents. A non-General topic also reports the account it runs on (Claude profile · email, ⛔ at its limit) and the resolved workdir; a live one the model actually running, runtime version and context use (unknown when the backend cannot report it) |
|
|
134
136
|
| `/doctor` | Self-diagnose: admin rights, privacy mode, paths, CLIs |
|
|
135
|
-
| `/version` | Versions: bot, claude, opencode, node, tmux |
|
|
137
|
+
| `/version` | Versions: bot, claude, opencode, node, tmux; a line when an update is available |
|
|
138
|
+
| `/update` | Self-update screen: what this instance runs (npm / git, hot), automatic updates `Automatic` · `Notify only` · `Off` (default automatic), the «what's new» switch, Check now, Update now. Controls in General, read-only elsewhere; typed forms `/update on\|notify\|off`, `/update whatsnew on\|off`, `/update check`, `/update now` — see [Updating](SETUP.md#updating) |
|
|
136
139
|
| `/whoami` | Show userId, chatId, threadId, isAllowed, binding |
|
|
137
140
|
| `/trace` | Output-trace recorder (`on`/`off`, `on all`/`off all`; bare = status) — see [Observability](#observability) |
|
|
138
141
|
| `/timestamps` | Prepend the send time to prompts forwarded to the agent (`on`/`off`; bare = status) |
|
|
@@ -292,7 +295,8 @@ so one account's usage limit does not stop every topic.
|
|
|
292
295
|
`claude_profiles` — optionally with the model it will run — and gets every
|
|
293
296
|
profile with its windows plus `recommended`: the signed-in, unlimited profile
|
|
294
297
|
with the most headroom (the session window and the shared weekly window bound
|
|
295
|
-
every model; Fable additionally drains its own weekly window)
|
|
298
|
+
every model; Fable additionally drains its own weekly window) — never an
|
|
299
|
+
account billed to API credits. It then
|
|
296
300
|
starts the child with `CLAUDE_CONFIG_DIR=<configDir>` (`null` = the default
|
|
297
301
|
profile: set nothing). The same answer from a shell, for a worker without
|
|
298
302
|
MCP: `charness claude-profiles [--best] [--model <name>] [--json]` —
|
|
@@ -300,6 +304,73 @@ so one account's usage limit does not stop every topic.
|
|
|
300
304
|
`CLAUDE_CONFIG_DIR="$(charness claude-profiles --best --model fable)"`
|
|
301
305
|
works as is; it reads the bot's cache off `DATA_DIR/state.json`.
|
|
302
306
|
|
|
307
|
+
#### An account billed to API credits (Claude Console)
|
|
308
|
+
|
|
309
|
+
Besides subscriptions, an account can bill the **API credits of a Claude Console
|
|
310
|
+
organization** — useful as a fallback when every subscription is at its limit.
|
|
311
|
+
Such an account pays per request (no 5-hour or weekly windows: its limit is the
|
|
312
|
+
balance), so the bot never uses it without you choosing it.
|
|
313
|
+
|
|
314
|
+
- **Adding one:** `/accounts` → «➕ Claude API account (Console credits)» (or
|
|
315
|
+
`/accounts add console api`) — give it a name. The bot runs
|
|
316
|
+
`claude auth login --console` for it: open the link, sign in to the Console
|
|
317
|
+
organization whose credits it should spend and paste the code back. Claude
|
|
318
|
+
Code then creates an API key in that organization's workspace and keeps it in
|
|
319
|
+
the account's own directory (`DATA_DIR/claude-profiles/<name>/`), where only
|
|
320
|
+
that account's sessions read it. Your Console role must allow creating a key
|
|
321
|
+
(«Claude Code» or «Developer»).
|
|
322
|
+
- **Or paste a key:** while that sign-in waits, paste an existing API key
|
|
323
|
+
(`sk-ant-api…`, on its own or as an `ANTHROPIC_API_KEY=…` line) instead of the
|
|
324
|
+
code. The message is deleted at once (so is a key pasted where the name is
|
|
325
|
+
asked, or typed on the `/accounts` command line), the key
|
|
326
|
+
is checked with the API (a refused key is not stored), then kept in the
|
|
327
|
+
account's directory (`0600`) and handed to its sessions only, through an
|
|
328
|
+
`apiKeyHelper` in that account's launch settings — never in `state.json`, never
|
|
329
|
+
in an environment variable an agent or a child process could read, never in
|
|
330
|
+
the trace (any `sk-ant-…` text is redacted from it). `/accounts login <name>`
|
|
331
|
+
of an API account runs the same flow again; a later Console sign-in replaces
|
|
332
|
+
a pasted key.
|
|
333
|
+
- The Console's keyless sign-in («Sign in with your Console account» in
|
|
334
|
+
Claude Code's own `/login`) is **not** used: it is stored outside the account's
|
|
335
|
+
directory, for the whole machine, and signs the subscriptions out.
|
|
336
|
+
- Every other account stays a subscription exactly as before: the bot still
|
|
337
|
+
removes any `ANTHROPIC_API_KEY` from the environment of every session and of
|
|
338
|
+
every sign-in.
|
|
339
|
+
- **Recognising one:** `/accounts` shows it as `console — you@example.com, 💳 API
|
|
340
|
+
· pay per use` (`💳 API key · pay per use` for a pasted key), `/status` marks
|
|
341
|
+
the account `· 💳 API`, and picking it — in a topic, or as the default in
|
|
342
|
+
General — says that every request is billed. The bot reads the billing from
|
|
343
|
+
`claude auth status` each time it checks the account, so a mistaken
|
|
344
|
+
subscription login shows as a subscription.
|
|
345
|
+
- **Never used by itself.** It has no windows, so to every headroom rule it
|
|
346
|
+
would look inexhaustible: the `claude_profiles` recommendation (and
|
|
347
|
+
`charness claude-profiles --best`) never names it, the within-Claude switch
|
|
348
|
+
never offers it, and «🔄 Fill from connected» in `/limits_autoswitch` puts it
|
|
349
|
+
LAST in the fallback list and left out of automatic switching (🚫). To use it,
|
|
350
|
+
tap it on the `/limits` board (`Claude · console 💳`) — or include its entry
|
|
351
|
+
(«✅ Use») so a limit notice offers it, or switches to it by itself with
|
|
352
|
+
switching on. A rebuilt list keeps it included once you did.
|
|
353
|
+
- **When the credits run out** («Credit balance is too low») the bot does not
|
|
354
|
+
wait for a reset — there is none — and never retries hourly. The topic gets
|
|
355
|
+
one `💸` notice, the account is marked as out of credits (`💸` in
|
|
356
|
+
`/limits_autoswitch`, `/accounts`, `/limits` and `/status`) and the fallback
|
|
357
|
+
list decides as for a limit: switching on moves the topic at once, otherwise
|
|
358
|
+
the notice carries «🔁 Switch to …» buttons. If nothing can take over now but
|
|
359
|
+
another entry comes back at a known time (a subscription's weekly reset), the
|
|
360
|
+
topic waits for that and continues there; otherwise the notice is all. The
|
|
361
|
+
mark lasts until you act: pick the account again (after topping the balance
|
|
362
|
+
up), or sign it in again — or until a request on it goes through again. A
|
|
363
|
+
rate limit of the API (429) is still a short retry.
|
|
364
|
+
- **What it spent.** On the default (stream) backend every turn reports the
|
|
365
|
+
conversation's running cost; the bot counts the part each turn on the API
|
|
366
|
+
account added (a subscription turn of the same conversation is never
|
|
367
|
+
counted) and shows the total under the account in `/accounts` and `/limits`
|
|
368
|
+
(`💳 $12.34 spent since 23.10 · last turn $0.21`), on `/status`, in the line a
|
|
369
|
+
limit switch onto the account adds («billed per request … $X spent through
|
|
370
|
+
the bot so far») and in its «credits used up» notice. It is what the bot
|
|
371
|
+
saw, not the organization's balance — that one is on the Console's Billing
|
|
372
|
+
page. The tmux backend reports no cost.
|
|
373
|
+
|
|
303
374
|
### Usage limits and the fallback models (`/limits` and `/limits_autoswitch`)
|
|
304
375
|
|
|
305
376
|
When a topic's agent stops on a usage limit — a Claude account window, an
|
package/SETUP.md
CHANGED
|
@@ -103,36 +103,76 @@ hostnames: their ports and tmux servers are their own.
|
|
|
103
103
|
|
|
104
104
|
### Updating
|
|
105
105
|
|
|
106
|
-
|
|
107
|
-
|
|
106
|
+
**The bot updates itself.** With `autoUpdate` on (the default) an instance checks for a new version every hour (the first
|
|
107
|
+
check 10 minutes after it starts), installs it when nobody is using the bot, restarts **in place** — the same process id, so
|
|
108
|
+
systemd, pm2, `nohup` or a terminal see nothing, and every agent keeps running (what survives:
|
|
109
|
+
[Restart behaviour](README.md#restart-behaviour)) — and says in General what changed:
|
|
108
110
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
111
|
+
```
|
|
112
|
+
🔄 Charness updated: 3.4.0 → 3.5.0
|
|
113
|
+
• Charness now updates itself.
|
|
114
|
+
• A reset written in several parts is read whole.
|
|
115
|
+
• …and 3 more — CHANGELOG: <link>
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Control it from **`/update` in General** (Automatic · Notify only · Off, the «what's new» switch, Check now, Update to X
|
|
119
|
+
now), or by hand in `settings.json` ([Instance settings](#instance-settings-settingsjson)). **Notify only** says that a new
|
|
120
|
+
version is out and puts an «Update to X» button under it; **Off** never looks. In any other topic `/update` is the same
|
|
121
|
+
status without the controls.
|
|
122
|
+
|
|
123
|
+
What it does depends on how this instance is installed — `/update` names the kind:
|
|
124
|
+
|
|
125
|
+
| Install | What the updater does |
|
|
126
|
+
|---|---|
|
|
127
|
+
| **npm global** (`npm install -g charness`, a prefix the bot's user can write) | Takes a new version from the registry **4 hours after the bot first saw it**, so a hastily fixed release never reaches you first; installs it with the `npm` beside the running `node`, runs `charness self-check` on the NEW install before switching, then restarts onto it. Never `sudo`. |
|
|
128
|
+
| **git checkout** (a clone, an `npm link`, the one the Docker container mounts) | Fast-forwards through `scripts/self-update.sh`, with no hold — a checkout follows `main` — and rebuilds. In hot mode the watcher reloads the worker by itself (a pull that changes no compiled source — docs, the CHANGELOG, scripts — rebuilds nothing, so the updater asks the worker to reload); when a file the hot supervisor loaded changed, the worker asks the supervisor to re-execute itself (same pid; the OpenCode server and the speech engine are left alone). |
|
|
129
|
+
| anything else — a read-only folder (a root-owned npm prefix), pnpm / yarn / bun, a project-local install, a Node without `process.execve` (needs 22.15+, not Windows), `npx` | Says that a new version is out and how to update by hand; `npx` gets nothing to update. |
|
|
130
|
+
|
|
131
|
+
**When it installs.** Only when no agent is working, no input waits to be consumed, no sign-in or wizard is open and no
|
|
132
|
+
person has written to the bot for 10 minutes. A tap on «Update to X now» skips the quiet period, never a running turn.
|
|
133
|
+
**What it offers instead of installing:** a major version, a version that needs a newer Node than this one, and a
|
|
134
|
+
checkout range that adds a [migration guide](MIGRATION_RENAME_TO_CHARNESS.md) — each is announced in General and waits
|
|
135
|
+
for your tap. A deprecated version is skipped.
|
|
136
|
+
|
|
137
|
+
**A version that does not start is put back.** The install is written to `update-pending.json` before the switch; the new
|
|
138
|
+
version is confirmed 60 seconds after it launched, and one that fails to boot twice is rolled back to the previous version
|
|
139
|
+
(npm reinstalls it, a checkout resets and rebuilds), the target is not retried, and General says so. In hot mode a pull
|
|
140
|
+
that has not produced a working worker within 10 minutes is rolled back the same way.
|
|
141
|
+
|
|
142
|
+
**After the update** General gets «Updated a → b» with the CHANGELOG entries the update brought (each opens with a bold
|
|
143
|
+
sentence; `whatsNew: false` leaves the list out). **An update that renames something ships a migration guide** — it is
|
|
144
|
+
named in that message; the names renamed from TelegramCode to Charness (environment variables, the data dir, the Docker
|
|
145
|
+
names, …) still work for now and print a deprecation line at start; the steps are in
|
|
112
146
|
[MIGRATION_RENAME_TO_CHARNESS.md](MIGRATION_RENAME_TO_CHARNESS.md), the summary in the top entry of
|
|
113
|
-
[CHANGELOG.md](CHANGELOG.md).
|
|
147
|
+
[CHANGELOG.md](CHANGELOG.md).
|
|
148
|
+
|
|
149
|
+
**By hand** nothing changed: `npm install -g charness@latest` (an instance that finds a newer version installed on disk
|
|
150
|
+
restarts onto it by itself at its first idle moment), or `scripts/self-update.sh` in a checkout. Two instances of one npm
|
|
151
|
+
install on a host take turns — the second finds the version the first installed and restarts onto it.
|
|
114
152
|
|
|
115
|
-
#### Updating a checkout (self-update
|
|
153
|
+
#### Updating a checkout (`scripts/self-update.sh`, no root)
|
|
116
154
|
|
|
117
155
|
A checkout — the one the [Docker container](#run-with-docker) runs, or a clone from
|
|
118
|
-
[DEVELOPMENT.md](DEVELOPMENT.md#local-development) — updates with `scripts/self-update.sh` (not in the npm package)
|
|
119
|
-
|
|
120
|
-
|
|
156
|
+
[DEVELOPMENT.md](DEVELOPMENT.md#local-development) — updates with `scripts/self-update.sh` (not in the npm package); the
|
|
157
|
+
bot's own updater drives it, and it can still be run by hand or from cron (then set `autoUpdate` to `off` so the two do not
|
|
158
|
+
race). It refreshes the checkout in place, running as the checkout's owning user — no root, no cross-user copying. It is
|
|
159
|
+
safe to run blindly:
|
|
121
160
|
|
|
122
161
|
- fast-forward only: it skips silently when the tree has tracked changes, a
|
|
123
162
|
merge/rebase is in progress, or local history diverged from the upstream —
|
|
124
163
|
a dev clone that is ahead of origin is never touched;
|
|
164
|
+
- `--check` fetches and changes nothing, `--hold-breaking` updates unless the incoming range adds a `MIGRATION_*.md`;
|
|
125
165
|
- `yarn install --immutable` runs only when `yarn.lock` / `package.json`
|
|
126
166
|
changed;
|
|
127
167
|
- a hot-mode instance (`charness hot`) rebuilds and restarts the worker
|
|
128
168
|
by itself (after a dependency install the script touches `tsconfig.json`
|
|
129
169
|
so `tsc -w` recompiles with the new modules); a non-hot instance gets
|
|
130
|
-
`yarn build`
|
|
170
|
+
`yarn build` — the script never kills processes (the bot's updater restarts it);
|
|
131
171
|
- changes to the hot supervisor itself (`src/cli.ts`, `src/cli/hot.ts`,
|
|
132
|
-
`nodemon.json`) are flagged with a warning:
|
|
133
|
-
`charness hot` restart (nodemon reloads only the worker).
|
|
172
|
+
`nodemon.json`) are flagged with a warning: with the bot's updater the supervisor
|
|
173
|
+
re-executes itself, run by hand they need a manual `charness hot` restart (nodemon reloads only the worker).
|
|
134
174
|
|
|
135
|
-
For unattended updates give the deploying user read access to the repo (e.g.
|
|
175
|
+
For unattended updates **without** the bot's updater give the deploying user read access to the repo (e.g.
|
|
136
176
|
a read-only GitLab deploy key on a passphrase-less SSH key) and add a cron
|
|
137
177
|
entry:
|
|
138
178
|
|
|
@@ -257,7 +297,9 @@ This step is **[manual]** — it all happens inside the Telegram app.
|
|
|
257
297
|
|
|
258
298
|
1. Open the group; in the General topic send `/ls` — the bot lists subfolders
|
|
259
299
|
under the work root.
|
|
260
|
-
2. Create a topic (the `+` button)
|
|
300
|
+
2. Create a topic (the `+` button) — or run `/topic` in any topic of the group
|
|
301
|
+
(General included): it asks for the name and the folder, creates the topic,
|
|
302
|
+
binds it and links to it, and you can skip step 3.
|
|
261
303
|
3. In the new topic: `/bind <subdir>` (auto-bound if the topic name matches a
|
|
262
304
|
subdir).
|
|
263
305
|
4. `/claude` or `/opencode` → talk to the agent (text or voice).
|
|
@@ -358,12 +400,14 @@ be written, the tap that needed it says so and names the path. The file is optio
|
|
|
358
400
|
a hand edit applies to the next session start, no restart.
|
|
359
401
|
|
|
360
402
|
```json
|
|
361
|
-
{ "defaultEffort": "medium" }
|
|
403
|
+
{ "defaultEffort": "medium", "autoUpdate": "on", "whatsNew": true }
|
|
362
404
|
```
|
|
363
405
|
|
|
364
406
|
| Field | Meaning |
|
|
365
407
|
|---|---|
|
|
366
408
|
| `defaultEffort` | The reasoning effort of every topic that has no `/effort` pick of its own: `low`, `medium`, `high`, `xhigh`, `max`, `auto` or `ultracode`. Set it from **`/effort` in the General topic** (a tap writes the file), or by hand. Leave it out and the built-in default, `medium`, applies |
|
|
409
|
+
| `autoUpdate` | What the instance does about a new charness version: `on` installs it by itself when the bot is idle, `notify` says it is out and offers a button, `off` never looks. Set it from **`/update` in General**, or by hand. Leave it out and `on` applies ([Updating](#updating)) |
|
|
410
|
+
| `whatsNew` | `true` (default): after an update General lists the CHANGELOG entries it brought; `false`: only the «Updated a → b» line. Set from `/update` in General, or by hand |
|
|
367
411
|
|
|
368
412
|
What a new Claude session starts with, first that exists: the topic's own `/effort` pick, the platform's default
|
|
369
413
|
(a Jira conversation: `effort` in `jira.json`, `high` when absent — Jira never reads `defaultEffort`), `defaultEffort`,
|
|
@@ -625,9 +669,11 @@ Running it:
|
|
|
625
669
|
|
|
626
670
|
- **Restart the bot only** (agents keep running and are adopted): `docker exec charness-main
|
|
627
671
|
charness-restart-bot`. A crashed bot is restarted by the container after 20 s.
|
|
628
|
-
- **Update the bot**:
|
|
629
|
-
|
|
630
|
-
|
|
672
|
+
- **Update the bot**: it updates itself (`/update` in General, [Updating](#updating)): the mounted checkout is pulled when
|
|
673
|
+
no agent is working, hot mode reloads the worker, and a change to `src/cli.ts`, `src/cli/hot.ts` or `nodemon.json`
|
|
674
|
+
makes the supervisor re-execute itself — the same process, so the container's entrypoint sees no exit and no restart
|
|
675
|
+
delay. By hand: `docker exec charness-main /opt/charness/scripts/self-update.sh`; an old supervisor (one that predates
|
|
676
|
+
re-exec) says once that it needs the bot restart above. **Update Claude Code / OpenCode**: they update themselves in the agents' home, or
|
|
631
677
|
`docker exec charness-main npm install -g @anthropic-ai/claude-code` / `… opencode-ai`.
|
|
632
678
|
- **A container restart is a reboot**: every agent process ends; each conversation resumes with its next message.
|
|
633
679
|
- **Rootless Docker** (recommended): the container's root is your user, so everything written on the mounts is
|
|
@@ -2899,7 +2899,7 @@ class ClaudeCliAdapter extends events_1.EventEmitter {
|
|
|
2899
2899
|
...claudePermissionArgs,
|
|
2900
2900
|
'--session-id', claudeSessionId,
|
|
2901
2901
|
...mcpFlagsArr,
|
|
2902
|
-
...(0, claudeCompactHook_1.prepareClaudeCompactHookFlags)((0, state_1.resolveDataDir)()),
|
|
2902
|
+
...(0, claudeCompactHook_1.prepareClaudeCompactHookFlags)((0, state_1.resolveDataDir)(), configDir),
|
|
2903
2903
|
...(args ? [args] : []),
|
|
2904
2904
|
];
|
|
2905
2905
|
const claudeShellCmd = claudeArgv.map(tmuxExec_1.shellSingleQuote).join(' ');
|
|
@@ -3530,7 +3530,7 @@ class ClaudeCliAdapter extends events_1.EventEmitter {
|
|
|
3530
3530
|
...claudePermissionArgs,
|
|
3531
3531
|
'--resume', sessionId,
|
|
3532
3532
|
...mcpFlagsArr,
|
|
3533
|
-
...(0, claudeCompactHook_1.prepareClaudeCompactHookFlags)((0, state_1.resolveDataDir)()),
|
|
3533
|
+
...(0, claudeCompactHook_1.prepareClaudeCompactHookFlags)((0, state_1.resolveDataDir)(), configDir),
|
|
3534
3534
|
];
|
|
3535
3535
|
const claudeShellCmd = claudeArgv.map(tmuxExec_1.shellSingleQuote).join(' ');
|
|
3536
3536
|
try {
|