twinny 1.0.0 → 1.1.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/README.en.md +293 -0
- package/README.md +134 -112
- package/dist/app/startup-error-telemetry.d.ts +21 -0
- package/dist/app/startup-error-telemetry.js +169 -0
- package/dist/app/startup-error-telemetry.js.map +1 -0
- package/dist/app/startup-probe.js +3 -0
- package/dist/app/startup-probe.js.map +1 -1
- package/dist/app/wiring.d.ts +7 -0
- package/dist/app/wiring.js +68 -19
- package/dist/app/wiring.js.map +1 -1
- package/dist/cli/commands.js +72 -18
- package/dist/cli/commands.js.map +1 -1
- package/dist/cli/install-guide.d.ts +5 -1
- package/dist/cli/install-guide.js +8 -3
- package/dist/cli/install-guide.js.map +1 -1
- package/dist/cli/install-wizard.d.ts +165 -6
- package/dist/cli/install-wizard.js +912 -115
- package/dist/cli/install-wizard.js.map +1 -1
- package/dist/cli/update.d.ts +26 -0
- package/dist/cli/update.js +112 -0
- package/dist/cli/update.js.map +1 -0
- package/dist/codex/appserver.js +6 -1
- package/dist/codex/appserver.js.map +1 -1
- package/dist/codex/goal.d.ts +2 -1
- package/dist/codex/goal.js +10 -12
- package/dist/codex/goal.js.map +1 -1
- package/dist/codex/turn.d.ts +11 -1
- package/dist/codex/turn.js +64 -5
- package/dist/codex/turn.js.map +1 -1
- package/dist/config/loader.d.ts +7 -1
- package/dist/config/loader.js +83 -1
- package/dist/config/loader.js.map +1 -1
- package/dist/config/paths.js +9 -1
- package/dist/config/paths.js.map +1 -1
- package/dist/config/secrets.d.ts +21 -1
- package/dist/config/secrets.js +81 -1
- package/dist/config/secrets.js.map +1 -1
- package/dist/conversation/manager.d.ts +121 -5
- package/dist/conversation/manager.js +1316 -149
- package/dist/conversation/manager.js.map +1 -1
- package/dist/lark/cards.js +12 -5
- package/dist/lark/cards.js.map +1 -1
- package/dist/lark/doc-comments.d.ts +58 -0
- package/dist/lark/doc-comments.js +540 -0
- package/dist/lark/doc-comments.js.map +1 -0
- package/dist/lark/events.d.ts +2 -1
- package/dist/lark/events.js +14 -2
- package/dist/lark/events.js.map +1 -1
- package/dist/lark/filters.d.ts +11 -1
- package/dist/lark/filters.js +54 -0
- package/dist/lark/filters.js.map +1 -1
- package/dist/lark/index.d.ts +1 -0
- package/dist/lark/index.js +1 -0
- package/dist/lark/index.js.map +1 -1
- package/dist/lark/messages.d.ts +2 -0
- package/dist/lark/messages.js +38 -0
- package/dist/lark/messages.js.map +1 -1
- package/dist/lark/openapi.js +28 -3
- package/dist/lark/openapi.js.map +1 -1
- package/dist/lark/types.d.ts +8 -3
- package/dist/lark/types.js +21 -2
- package/dist/lark/types.js.map +1 -1
- package/dist/launchd/install.d.ts +14 -6
- package/dist/launchd/install.js +102 -42
- package/dist/launchd/install.js.map +1 -1
- package/dist/launchd/plist.d.ts +5 -0
- package/dist/launchd/plist.js +27 -1
- package/dist/launchd/plist.js.map +1 -1
- package/dist/observability/health.d.ts +1 -1
- package/dist/observability/health.js +11 -8
- package/dist/observability/health.js.map +1 -1
- package/dist/service/index.d.ts +2 -0
- package/dist/service/index.js +3 -0
- package/dist/service/index.js.map +1 -0
- package/dist/service/install.d.ts +17 -0
- package/dist/service/install.js +64 -0
- package/dist/service/install.js.map +1 -0
- package/dist/service/lock.d.ts +6 -0
- package/dist/service/lock.js +23 -0
- package/dist/service/lock.js.map +1 -0
- package/dist/store/db.d.ts +29 -2
- package/dist/store/db.js +136 -4
- package/dist/store/db.js.map +1 -1
- package/dist/store/migrations.d.ts +4 -4
- package/dist/store/migrations.js +52 -2
- package/dist/store/migrations.js.map +1 -1
- package/dist/store/repositories.d.ts +27 -4
- package/dist/store/repositories.js +204 -3
- package/dist/store/repositories.js.map +1 -1
- package/dist/systemd/install.d.ts +17 -0
- package/dist/systemd/install.js +82 -0
- package/dist/systemd/install.js.map +1 -0
- package/dist/systemd/unit.d.ts +9 -0
- package/dist/systemd/unit.js +60 -0
- package/dist/systemd/unit.js.map +1 -0
- package/dist/types.d.ts +51 -1
- package/dist/types.js.map +1 -1
- package/dist/version.js +1 -1
- package/dist/version.json +1 -1
- package/migrations/0002_lark_doc_watcher.sql +15 -0
- package/migrations/0003_lark_message_doc_comment_id.sql +6 -0
- package/package.json +3 -10
- package/README.zh-CN.md +0 -252
package/README.en.md
ADDED
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
# Twinny
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/twinny)
|
|
6
|
+
|
|
7
|
+
[简体中文](./README.md)
|
|
8
|
+
|
|
9
|
+
## Requirements
|
|
10
|
+
|
|
11
|
+
- macOS or Linux. The installer manages a macOS LaunchAgent, or a `--system-daemon` LaunchDaemon, on macOS and a systemd user service on Linux.
|
|
12
|
+
- Node.js 22.18.0 or newer. Twinny uses Node.js' built-in `node:sqlite` module and does not require an extra SQLite native addon.
|
|
13
|
+
- Codex CLI 0.130.0 or newer in `PATH`, or set `CODEX_BINARY`; the installer can install Codex automatically if it is missing.
|
|
14
|
+
- A Feishu/Lark bot app with the permissions and event subscriptions listed below.
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
### Installation guide for Codex
|
|
19
|
+
|
|
20
|
+
Copy this prompt into Codex and let it run the agent installer:
|
|
21
|
+
|
|
22
|
+
```text
|
|
23
|
+
Read https://raw.githubusercontent.com/hachiwii/twinny/master/agent_installation_guide.md and follow instructions in it.
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### Install Manually
|
|
27
|
+
|
|
28
|
+
Run the interactive installer with `npx`:
|
|
29
|
+
|
|
30
|
+
```sh
|
|
31
|
+
npx twinny@latest install
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
On macOS, Twinny installs as a LaunchAgent in the current GUI session by default. In SSH, CI, or another environment without a GUI LaunchAgent, the installer exits and asks you to use system daemon mode:
|
|
35
|
+
|
|
36
|
+
```sh
|
|
37
|
+
npx twinny@latest install --system-daemon
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
`--system-daemon` writes the plist to `/Library/LaunchDaemons` through `sudo` and sets `UserName` to the current user. Later `start`, `stop`, `restart`, and `status` commands keep using LaunchDaemon based on the service settings in `config.toml`.
|
|
41
|
+
|
|
42
|
+
Useful daemon commands:
|
|
43
|
+
|
|
44
|
+
```sh
|
|
45
|
+
npx twinny@latest doctor
|
|
46
|
+
npx twinny@latest status
|
|
47
|
+
npx twinny@latest update
|
|
48
|
+
npx twinny@latest start
|
|
49
|
+
npx twinny@latest stop
|
|
50
|
+
npx twinny@latest restart
|
|
51
|
+
npx twinny@latest uninstall
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Use `TWINNY_HOME=/path/to/home` with any command when you are not using the default home.
|
|
55
|
+
|
|
56
|
+
Secrets are stored outside `config.toml`. Non-macOS installs store the Lark `app_secret` in the `lark_app_secret` field in `TWINNY_HOME/auth.json`. macOS installs use the system Keychain by default; with `--disable-keychain`, or if the Keychain write fails, the installer stores the secret in `auth.json` instead. On startup, Twinny reads `auth.json` first, then falls back to `TWINNY_LARK_APP_SECRET` and the legacy secret store (macOS Keychain, `runtime/secrets.json` on other platforms).
|
|
57
|
+
|
|
58
|
+
## Feishu/Lark App Configuration
|
|
59
|
+
|
|
60
|
+
You need to grant these API permissions in the Feishu/Lark developer console:
|
|
61
|
+
|
|
62
|
+
```text
|
|
63
|
+
im:message.p2p_msg:readonly
|
|
64
|
+
im:message.group_msg
|
|
65
|
+
im:message:readonly
|
|
66
|
+
im:message:send_as_bot
|
|
67
|
+
im:message:update
|
|
68
|
+
im:message:recall
|
|
69
|
+
im:message.reactions:write_only
|
|
70
|
+
im:chat:read
|
|
71
|
+
im:chat:create
|
|
72
|
+
im:chat:update
|
|
73
|
+
im:resource
|
|
74
|
+
docs:document.comment:read
|
|
75
|
+
docs:document.comment:create
|
|
76
|
+
docs:document.comment:write_only
|
|
77
|
+
wiki:node:read
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Subscribe to these events/callbacks:
|
|
81
|
+
|
|
82
|
+
```text
|
|
83
|
+
im.message.receive_v1
|
|
84
|
+
im.message.recalled_v1
|
|
85
|
+
drive.notice.comment_add_v1
|
|
86
|
+
application.bot.menu_v6
|
|
87
|
+
card.action.trigger
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Use the Feishu/Lark event long connection (WebSocket) mode. Twinny does not require a public HTTP callback URL for message events.
|
|
91
|
+
|
|
92
|
+
Optional bot shortcut menu entries can use these `event_key` values:
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
| Event key | Action |
|
|
96
|
+
| --------- | ---------------------------------------------------- |
|
|
97
|
+
| `help` | Send command help. |
|
|
98
|
+
| `status` | Show the current conversation and thread status. |
|
|
99
|
+
| `queue` | Toggle queue-next-message mode. |
|
|
100
|
+
| `new` | Open a new Codex thread in the current conversation. |
|
|
101
|
+
| `stop` | Stop the active turn and clear queued work. |
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
## Usage
|
|
105
|
+
|
|
106
|
+
Send normal messages to the bot to start or continue a Codex turn. In groups, the owner must activate the group before ordinary messages are routed to Codex.
|
|
107
|
+
|
|
108
|
+
### Conversation Commands
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
| Command | Usage |
|
|
112
|
+
| ------------------------------------- | ------------------------------------------------------------------------------------------------------------ |
|
|
113
|
+
| `/help` | Show available commands. |
|
|
114
|
+
| `/status` | Show conversation, Codex thread, model, token, and queue status. |
|
|
115
|
+
| `/new` | Stop the current task, clear queued messages, and open a new Codex thread. |
|
|
116
|
+
| `/stop [all\|<side_id>]` | Stop the active task and clear queued messages. Use `all` to stop side turns too, or a side id to stop one side turn. |
|
|
117
|
+
| `/next` | Interrupt the current task and start the next queued message. |
|
|
118
|
+
| `/steer` | Inject the next queued batch into the currently running Codex turn. |
|
|
119
|
+
| `/queue [message]` | Without a message, queue your next message. With a message, add that message to the next turn. |
|
|
120
|
+
| `/goal <objective>` | Set and run a Codex goal. A later `/goal` while the goal is active updates the objective. |
|
|
121
|
+
| `/plan [message]` | Enter plan mode. If a message is provided, process it in plan mode immediately. |
|
|
122
|
+
| `/exit` | Exit plan mode in the next queued control step. |
|
|
123
|
+
| `/side <message>` or `/btw <message>` | Start an ephemeral side conversation forked from the current Codex thread. |
|
|
124
|
+
| `/compact` | Compact the current Codex thread context in the next queued control step. |
|
|
125
|
+
| `/thread [message]` | Create a new Lark topic backed by a new Codex thread. If `message` is present, proxy it into that new topic. |
|
|
126
|
+
| `/fork [message]` | Fork the current Codex thread into a new Lark topic. If `message` is present, proxy it into that new topic. |
|
|
127
|
+
| `/watch <lark_doc_url> [owner\|all\|none]` | Watch @bot comments on a Feishu/Lark document and route them to the current thread. Without arguments, list watchers for the current thread. `owner` responds only to the owner, `all` responds to everyone, and `none` disables the watcher. |
|
|
128
|
+
| `/model <model> <effort>` | Set the model and reasoning effort for future turns in the current thread. |
|
|
129
|
+
| `/logo` | Send the Twinny logo image. |
|
|
130
|
+
| `/twinny` or `/banner` | Send the Twinny banner card. |
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
### Group Administration
|
|
134
|
+
|
|
135
|
+
Only the configured owner can run these commands:
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
| Command | Usage |
|
|
139
|
+
| ------------------------------- | ---------------------------------------------------------------------- |
|
|
140
|
+
| `/activate <owner_at\|owner\|all_at\|all> [profile]` | Activate a group, set who can route messages to Codex, refresh the group name, and optionally bind the group to a profile. |
|
|
141
|
+
| `/deactivate` | Disable Twinny in the current group and clear pending work. |
|
|
142
|
+
| `/pair {guest_ou_id} <profile>` | Authorize a non-owner P2P user and bind that user to a profile. |
|
|
143
|
+
| `/reload [profile]` | Reload all Codex profiles, or one named profile, after editing config. |
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
Response modes:
|
|
147
|
+
|
|
148
|
+
- `owner_at`: only owner messages that mention the bot.
|
|
149
|
+
- `owner`: all owner messages.
|
|
150
|
+
- `all_at`: messages from any group member that mention the bot.
|
|
151
|
+
- `all`: all messages from any group member.
|
|
152
|
+
|
|
153
|
+
## Recommended Practice
|
|
154
|
+
|
|
155
|
+
Create a dedicated Feishu/Lark group for a project. Write an [AGENTS.md](http://AGENTS.md) inside the group's workspace. Let the owner activate the group with the least permissive useful mode, then create one topic per development task:
|
|
156
|
+
|
|
157
|
+
```text
|
|
158
|
+
/activate all host
|
|
159
|
+
/thread fix the login callback race
|
|
160
|
+
/thread add the GitHub README
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
Use `/fork` when a task needs an alternative direction while preserving the original Codex thread history:
|
|
164
|
+
|
|
165
|
+
```text
|
|
166
|
+
/fork try the smaller refactor path
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
Keep each task's discussion inside its topic. This keeps Codex context, local workspace state, Lark discussion, and status cards separated by task.
|
|
170
|
+
|
|
171
|
+
## Security Notes
|
|
172
|
+
|
|
173
|
+
Twinny runs on the owner's local machine. Treat it as a local automation bridge, not as a hardened multi-tenant execution service.
|
|
174
|
+
|
|
175
|
+
The current default configuration is not fully ready for broad multi-user sharing. In particular, if you activate a group with the `host` profile and `all` response mode, every group member who can speak in that group can run work with the same Codex execution authority as the owner:
|
|
176
|
+
|
|
177
|
+
```text
|
|
178
|
+
/activate all host
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
Be careful with `all_at` as well: every group member who can mention the bot can submit work when the group is bound to a powerful profile.
|
|
182
|
+
|
|
183
|
+
Before using Twinny in shared groups:
|
|
184
|
+
|
|
185
|
+
- Prefer a dedicated `codex_home` for guest or team profiles instead of sharing the owner's `~/.codex`.
|
|
186
|
+
- Configure Codex sandbox, filesystem, network, and approval-related settings for that profile.
|
|
187
|
+
- Add workspace-level `.codex` overrides where your Codex setup supports project-local safety policy.
|
|
188
|
+
- Keep `permissions.p2p_default_profile = "none"` unless you intentionally want unpaired P2P users to get access.
|
|
189
|
+
- Use `owner_at` or `owner` instead of `all` or `all_at` unless the group is tightly controlled.
|
|
190
|
+
|
|
191
|
+
## Advanced Configuration
|
|
192
|
+
|
|
193
|
+
Twinny reads `config.toml` from `TWINNY_HOME`.
|
|
194
|
+
|
|
195
|
+
Recognized fields:
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
| Field | Meaning and values |
|
|
199
|
+
| --------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
200
|
+
| `[codex].binary` | Codex CLI executable path or command name. Defaults to `codex`. Use an absolute path when the LaunchAgent cannot find Codex through `PATH`. |
|
|
201
|
+
| `[lark.reaction].working` | Lark emoji type added while Twinny is working. Defaults to `JubilantRabbit`. |
|
|
202
|
+
| `[lark.reaction].queued` | Lark emoji type added to queued messages. Defaults to `OneSecond`. |
|
|
203
|
+
| `[lark.redaction].email` | Redaction strategy for email addresses in outgoing Lark payloads. `mask` keeps the domain and masks the local part, for example `alice@example.com` becomes `a***e@example.com`; `whitespace` inserts spaces, for example `alice @ example.com`; `none` sends raw email addresses. Feishu may reject bot messages that contain raw email addresses or phone numbers. Defaults to `mask`. |
|
|
204
|
+
| `[lark.redaction].chinese_phone_number` | Redaction strategy for Chinese phone numbers in outgoing Lark payloads. `mask` keeps the first 3 and last 4 digits, for example `138****5678`; `whitespace` inserts spaces, for example `138 1234 5678`; `none` sends raw phone numbers. Feishu may reject bot messages that contain raw email addresses or phone numbers. Defaults to `mask`. |
|
|
205
|
+
| `[permissions].p2p_default_profile` | Profile used when an unpaired P2P user first messages Twinny. Use `none` to deny by default, or a configured profile name to auto-authorize. Defaults to `none`. |
|
|
206
|
+
| `[service.launchd].mode` | macOS launchd placement. `gui` uses the current `gui/<uid>` LaunchAgent by default; `daemon` uses a system LaunchDaemon. Usually written by `twinny install --system-daemon`. |
|
|
207
|
+
| `[service.launchd].user_name` | The plist `UserName` when `mode = "daemon"`. Usually written automatically by `twinny install --system-daemon` from the current user. |
|
|
208
|
+
| `[profiles.<name>].codex_home` | `CODEX_HOME` for that profile. Absolute paths are used as-is; relative paths are resolved under `TWINNY_HOME`. `host` defaults to `~/.codex`; other profiles inherit `host` unless set. |
|
|
209
|
+
| `[profiles.<name>].default_model` | Default model for new threads in that profile. `host` defaults to `gpt-5.5`; other profiles inherit `host` unless set. |
|
|
210
|
+
| `[profiles.<name>].default_effort` | Default reasoning effort for new threads in that profile. Common values are `minimal`, `low`, `medium`, `high`, and `xhigh`; `host` defaults to `medium`; other profiles inherit `host` unless set. |
|
|
211
|
+
| `[telemetry].enabled` | Boolean opt-out for telemetry-capable builds. Set to `false` to disable event capture. See [Telemetry](#telemetry). |
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
Telemetry data scope and opt-out settings are covered in [Telemetry](#telemetry).
|
|
215
|
+
|
|
216
|
+
Example `config.toml`:
|
|
217
|
+
|
|
218
|
+
```toml
|
|
219
|
+
[codex]
|
|
220
|
+
binary = "/opt/homebrew/bin/codex"
|
|
221
|
+
|
|
222
|
+
[lark.reaction]
|
|
223
|
+
working = "JubilantRabbit"
|
|
224
|
+
queued = "OneSecond"
|
|
225
|
+
|
|
226
|
+
[lark.redaction]
|
|
227
|
+
email = "mask"
|
|
228
|
+
chinese_phone_number = "mask"
|
|
229
|
+
|
|
230
|
+
[permissions]
|
|
231
|
+
p2p_default_profile = "none"
|
|
232
|
+
|
|
233
|
+
[profiles.host]
|
|
234
|
+
codex_home = "~/.codex"
|
|
235
|
+
default_model = "gpt-5.5"
|
|
236
|
+
default_effort = "medium"
|
|
237
|
+
|
|
238
|
+
[profiles.guest]
|
|
239
|
+
codex_home = "./profiles/guest-codex"
|
|
240
|
+
default_model = "gpt-5.5"
|
|
241
|
+
default_effort = "medium"
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
Relative `codex_home` paths are resolved under `TWINNY_HOME`. Each profile starts its own Codex app-server process with `CODEX_HOME` set to that profile's `codex_home`.
|
|
245
|
+
|
|
246
|
+
After editing profile config, run `/reload [profile]` from Lark or restart the daemon.
|
|
247
|
+
|
|
248
|
+
## Multiple Instances With `TWINNY_HOME`
|
|
249
|
+
|
|
250
|
+
Run multiple isolated Twinny instances by giving each instance its own home:
|
|
251
|
+
|
|
252
|
+
```sh
|
|
253
|
+
TWINNY_HOME="$HOME/.twinny-work" npx twinny@latest install
|
|
254
|
+
TWINNY_HOME="$HOME/.twinny-personal" npx twinny@latest install
|
|
255
|
+
|
|
256
|
+
TWINNY_HOME="$HOME/.twinny-work" npx twinny@latest status
|
|
257
|
+
TWINNY_HOME="$HOME/.twinny-personal" npx twinny@latest logs
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
Each home gets separate config and needs a separate Feishu bot app.
|
|
261
|
+
|
|
262
|
+
## Telemetry
|
|
263
|
+
|
|
264
|
+
Twinny builds with telemetry enabled may send anonymous, best-effort usage and reliability events. The data is used to monitor product quality, understand failure patterns, and support the maintainer's personal research interests around local-agent workflows.
|
|
265
|
+
|
|
266
|
+
Twinny does not collect or upload conversation content or credentials. This includes Lark message text, prompts, Codex answers, Feishu/Lark app secrets or tokens, Codex credentials or session tokens, chat names, sender names, raw Lark or Codex IDs, raw local paths, environment variable values, API keys, and other secrets. Identifiers such as install, conversation, thread, turn, sender, message, and Codex binary are salted and hashed locally before upload.
|
|
267
|
+
|
|
268
|
+
Telemetry may include:
|
|
269
|
+
|
|
270
|
+
- install and launch lifecycle status, startup duration, and LaunchAgent setup state;
|
|
271
|
+
- runtime health signals such as heartbeat, uptime, queue and active-turn counts, memory usage, and Lark/Codex readiness;
|
|
272
|
+
- message routing metadata such as conversation type, message or action type, route kind, queue depth, and resource counts;
|
|
273
|
+
- turn metadata such as status, type, model, reasoning effort, token counts, duration, generated image count, and error code/category when a turn fails;
|
|
274
|
+
- environment metadata such as Twinny, Codex, Node, OS version/platform/arch, Lark brand, and profile count.
|
|
275
|
+
|
|
276
|
+
Telemetry failures are ignored by the product path and should not affect install, launch, message handling, or Codex turns.
|
|
277
|
+
|
|
278
|
+
Disable telemetry in `config.toml`:
|
|
279
|
+
|
|
280
|
+
```toml
|
|
281
|
+
[telemetry]
|
|
282
|
+
enabled = false
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
Or disable it for a process with an environment variable:
|
|
286
|
+
|
|
287
|
+
```sh
|
|
288
|
+
TWINNY_TELEMETRY_ENABLED=false npx twinny@latest start
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
## License
|
|
292
|
+
|
|
293
|
+
MIT
|