threadwire 0.1.9 → 0.1.11

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 CHANGED
@@ -2,6 +2,13 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 0.1.10 - 2026-07-28
6
+
7
+ - Accept official slash-qualified Kimi model aliases through workspace-free
8
+ OAuth verification, model-only provider selection, exact runtime/broker
9
+ allowlisting, and fresh/resume execution without weakening argument or grant
10
+ boundaries.
11
+
5
12
  ## 0.1.9 - 2026-07-28
6
13
 
7
14
  - Add native Kimi Code subscription support through official OAuth, a distinct
@@ -182,9 +182,16 @@ Kimi runtime and broker admin tokens of at least 32 characters, the Kimi image d
182
182
  such as:
183
183
 
184
184
  ```sh
185
- export THREADWIRE_ALLOWED_KIMI_MODELS='{"default":{"model":"<verified-account-model>","protocol":"kimi"}}'
185
+ export THREADWIRE_ALLOWED_KIMI_MODELS='{"default":{"model":"kimi-for-coding","protocol":"kimi"},"kimi-code/kimi-for-coding":{"model":"kimi-for-coding","protocol":"kimi"}}'
186
186
  ```
187
187
 
188
+ `default` is the server-owned selection for no-argument and Telegram jobs.
189
+ `kimi-code/kimi-for-coding` is the exact official provider-qualified alias for
190
+ explicit callers. Each key is an opaque allowlisted value, not a path, and
191
+ Threadwire never normalizes or strips its prefix. The `model` field is the
192
+ independently verified wire request model; do not derive it by splitting the
193
+ alias.
194
+
188
195
  OAuth writes only the named `threadwire-kimi-oauth` volume at the official
189
196
  `credentials/kimi-code.json` location. Stop the broker during interactive auth
190
197
  so the CLI and broker cannot race a refresh, then run the opt-in, workspace-free
@@ -193,7 +200,7 @@ auth service:
193
200
  ```sh
194
201
  docker compose -f compose.yaml -f compose.relay-write.yaml stop kimi-isolated-runtime kimi-model-broker
195
202
  docker compose -f compose.yaml -f compose.relay-write.yaml --profile kimi-auth run --rm kimi-auth login
196
- docker compose -f compose.yaml -f compose.relay-write.yaml --profile kimi-auth run --rm kimi-auth verify '<verified-account-model>'
203
+ docker compose -f compose.yaml -f compose.relay-write.yaml --profile kimi-auth run --rm kimi-auth verify 'kimi-code/kimi-for-coding'
197
204
  docker compose -f compose.yaml -f compose.relay-write.yaml --profile kimi up --detach --wait
198
205
  ```
199
206
 
@@ -201,9 +208,20 @@ Complete the official device flow directly in the operator terminal. Do not
201
208
  copy device codes into tickets, chat, logs, environment files, or Threadwire.
202
209
  The auth service has no workspace, ingress network, Docker socket, Threadwire
203
210
  control token, or Telegram credential and uses Docker logging driver `none`.
204
- `verify <account-model>` discards native output and prints only a fixed
205
- success/failure; use it to confirm each exact account model value before mapping
206
- that value to a server-approved Threadwire alias.
211
+ `verify <provider-qualified-alias>` discards native output and prints only a
212
+ fixed success/failure; use it to confirm each exact official alias before
213
+ adding that alias and its independently verified wire model to the server
214
+ allowlist. An explicit CLI job selects the exact key as one argv value:
215
+
216
+ ```sh
217
+ node bin/threadwire.js run \
218
+ --provider kimi \
219
+ --target telegram:-1001234567890:42 \
220
+ --workspace-profile container-runtime \
221
+ --prompt 'Inspect the project.' \
222
+ -- --model 'kimi-code/kimi-for-coding'
223
+ ```
224
+
207
225
  API keys, Moonshot platform mode, custom base URLs, discovery by ordinary jobs,
208
226
  and arbitrary aliases are unsupported.
209
227
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "threadwire",
3
- "version": "0.1.9",
3
+ "version": "0.1.11",
4
4
  "description": "Stream Codex, Claude, Kimi Code, and OpenCode worker progress to an explicit Telegram destination",
5
5
  "keywords": [
6
6
  "ai-agent",
@@ -59,6 +59,7 @@ const EXPECTED_FILES = [
59
59
  "src/notice-queue.js",
60
60
  "src/notifiers/fetch-transport.js",
61
61
  "src/notifiers/telegram.js",
62
+ "src/path-safety.js",
62
63
  "src/providers/claude.js",
63
64
  "src/providers/codex.js",
64
65
  "src/providers/executable.js",
@@ -5,7 +5,7 @@ import {randomBytes} from "node:crypto"
5
5
  const TOKEN_PATTERN = /^[A-Za-z0-9_-]{32,128}$/u
6
6
  const ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9_.:-]{0,127}$/u
7
7
  const MODEL_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._:/-]{0,255}$/u
8
- const ALIAS_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/u
8
+ const ALIAS_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._/-]{0,63}$/u
9
9
  const TASK_PATTERN = /^[0-9a-f]{64}$/u
10
10
  const SESSION_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,511}$/u
11
11
 
@@ -16,7 +16,9 @@ const ALLOWED_HEADERS = new Set([
16
16
  "accept-language", "sec-fetch-mode", "user-agent",
17
17
  "x-stainless-arch", "x-stainless-lang", "x-stainless-os",
18
18
  "x-stainless-package-version", "x-stainless-runtime", "x-stainless-runtime-version",
19
- "x-stainless-retry-count", "x-stainless-timeout", "x-stainless-async"
19
+ "x-stainless-retry-count", "x-stainless-timeout", "x-stainless-async",
20
+ "x-msh-device-id", "x-msh-device-model", "x-msh-device-name", "x-msh-os-version",
21
+ "x-msh-platform", "x-msh-version"
20
22
  ])
21
23
  const BODY_KEYS = new Set([
22
24
  "model", "messages", "stream", "stream_options", "tools", "thinking",
@@ -0,0 +1,8 @@
1
+ // @ts-check
2
+
3
+ import {isAbsolute} from "node:path"
4
+
5
+ /** @param {string} path */
6
+ export function escapesDirectory(path) {
7
+ return path === ".." || path.startsWith("../") || isAbsolute(path)
8
+ }
@@ -1,7 +1,7 @@
1
1
  // @ts-check
2
2
 
3
3
  const EXECUTABLE = "/usr/local/bin/kimi"
4
- const ALIAS_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/u
4
+ const ALIAS_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._/-]{0,63}$/u
5
5
  const SESSION_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,511}$/u
6
6
  const TOOL_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,255}$/u
7
7
  const TOOL_NAME_PATTERN = /^[A-Za-z_][A-Za-z0-9_.:-]{0,127}$/u