ticlawk 0.1.12-dev.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.
Files changed (55) hide show
  1. package/LICENSE +15 -0
  2. package/README.md +426 -0
  3. package/agent-freeway.mjs +2 -0
  4. package/assets/ticlawk-concept.svg +137 -0
  5. package/bin/agent-freeway.mjs +4 -0
  6. package/bin/ticlawk.mjs +594 -0
  7. package/cc-watcher.mjs +3 -0
  8. package/package.json +72 -0
  9. package/scripts/postinstall.mjs +61 -0
  10. package/src/adapters/telegram/index.mjs +359 -0
  11. package/src/adapters/ticlawk/api.mjs +360 -0
  12. package/src/adapters/ticlawk/cards.mjs +149 -0
  13. package/src/adapters/ticlawk/credentials.mjs +25 -0
  14. package/src/adapters/ticlawk/index.mjs +1229 -0
  15. package/src/adapters/ticlawk/wake-client.mjs +204 -0
  16. package/src/core/adapter-registry.mjs +50 -0
  17. package/src/core/argv.mjs +38 -0
  18. package/src/core/bindings/store.mjs +81 -0
  19. package/src/core/bus.mjs +91 -0
  20. package/src/core/config.mjs +203 -0
  21. package/src/core/daemon-install.mjs +246 -0
  22. package/src/core/diagnostics.mjs +79 -0
  23. package/src/core/events/worker-events.mjs +80 -0
  24. package/src/core/executables.mjs +106 -0
  25. package/src/core/host-id.mjs +48 -0
  26. package/src/core/http.mjs +65 -0
  27. package/src/core/logger.mjs +34 -0
  28. package/src/core/media/inbound.mjs +127 -0
  29. package/src/core/media/outbound.mjs +163 -0
  30. package/src/core/profiles.mjs +173 -0
  31. package/src/core/runtime-contract.mjs +68 -0
  32. package/src/core/runtime-env.mjs +9 -0
  33. package/src/core/runtime-registry.mjs +93 -0
  34. package/src/core/runtime-support.mjs +197 -0
  35. package/src/core/setup-readiness.mjs +86 -0
  36. package/src/core/store/json-file-store.mjs +47 -0
  37. package/src/core/ticlawk-control.mjs +92 -0
  38. package/src/core/uninstall.mjs +142 -0
  39. package/src/core/update-state.mjs +62 -0
  40. package/src/core/update.mjs +178 -0
  41. package/src/runtimes/claude-code/index.mjs +363 -0
  42. package/src/runtimes/claude-code/session.mjs +388 -0
  43. package/src/runtimes/claude-code/transcripts.mjs +206 -0
  44. package/src/runtimes/codex/index.mjs +306 -0
  45. package/src/runtimes/codex/session.mjs +750 -0
  46. package/src/runtimes/openclaw/gateway.mjs +269 -0
  47. package/src/runtimes/openclaw/identity.mjs +34 -0
  48. package/src/runtimes/openclaw/index.mjs +228 -0
  49. package/src/runtimes/openclaw/inflight.mjs +46 -0
  50. package/src/runtimes/openclaw/target.mjs +57 -0
  51. package/src/runtimes/opencode/index.mjs +318 -0
  52. package/src/runtimes/opencode/session.mjs +413 -0
  53. package/src/runtimes/pi/index.mjs +287 -0
  54. package/src/runtimes/pi/session.mjs +423 -0
  55. package/ticlawk.mjs +260 -0
package/LICENSE ADDED
@@ -0,0 +1,15 @@
1
+ ISC License
2
+
3
+ Copyright (c) 2026 ticlawk
4
+
5
+ Permission to use, copy, modify, and/or distribute this software for any
6
+ purpose with or without fee is hereby granted, provided that the above
7
+ copyright notice and this permission notice appear in all copies.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
10
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
12
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
14
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15
+ PERFORMANCE OF THIS SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,426 @@
1
+ # ticlawk
2
+
3
+ [![npm version](https://img.shields.io/npm/v/ticlawk)](https://www.npmjs.com/package/ticlawk)
4
+
5
+ **Connect any agent harness to any mobile client.**
6
+
7
+ *M agent harnesses × N mobile clients used to be M×N integrations. ticlawk makes it M+N.*
8
+
9
+ You run the harness locally — Claude Code, Codex, OpenClaw, whatever you're
10
+ testing this week. `ticlawk` is the layer that lets any of them talk
11
+ through any mobile/web client you like to use (Telegram,
12
+ [ticlawk](https://ticlawk.com), more to come).
13
+
14
+ <p align="center">
15
+ <img src="assets/ticlawk-concept.svg" alt="ticlawk connects any client to any agent" width="860">
16
+ </p>
17
+
18
+ Left side: any agent harness that runs on your machine.
19
+ Middle: `ticlawk`.
20
+ Right side: any mobile or web app you like to use to manage your agent.
21
+
22
+ ---
23
+
24
+ ## Quickstart — Telegram in 5 minutes
25
+
26
+ This is the fastest way to see it work. You need a Telegram bot token from
27
+ [@BotFather](https://t.me/BotFather) and a project directory on this machine
28
+ where Claude Code can run.
29
+
30
+ ```bash
31
+ # 1. install
32
+ curl -fsSL https://raw.githubusercontent.com/darthjaja6/ticlawk/main/install.sh | bash
33
+
34
+ # 2. choose Telegram as the active adapter
35
+ ticlawk config set adapter telegram
36
+
37
+ # 3. store Telegram auth locally
38
+ ticlawk auth telegram --bot-token <your-bot-token>
39
+
40
+ # 4. restart the daemon so it starts polling the bot
41
+ # Linux
42
+ systemctl --user restart ticlawk
43
+
44
+ # macOS
45
+ launchctl kickstart -k gui/$(id -u)/ticlawk
46
+
47
+ # 5. connect that bot to a Claude Code project
48
+ ticlawk connect --adapter telegram --workdir /path/to/project
49
+
50
+ # optional: if you want to resume an existing Claude Code session instead,
51
+ # add --session-id <claude-session-id>
52
+
53
+ # 6. say hi to your bot on Telegram — the first DM becomes the bot's only chat
54
+ ```
55
+
56
+ `--workdir` is the important part. `ticlawk` binds the adapter to a local
57
+ project directory and runtime. `--session-id` is optional: use it only when you
58
+ want to resume an existing Claude Code or Codex conversation instead of letting
59
+ the next message create a fresh session automatically.
60
+
61
+ **Finding `<claude-session-id>`** — if you want to resume, use the filename
62
+ (without `.jsonl`) of the transcript under `~/.claude/projects/**/`. Pick the
63
+ one whose working directory matches the project you want the bot to work on.
64
+
65
+ If `hello` in Telegram comes back as a reply from that Claude Code session,
66
+ you're done. Everything below is for when you want ticlawk, Codex, OpenClaw,
67
+ or more control.
68
+
69
+ > ⚠️ **Single user, by design.** The Telegram bot binds to the **first** private
70
+ > DM that messages it, and refuses everyone else. This is not a bug — it's the
71
+ > security boundary. The bot can run shell commands and edit files in your
72
+ > project; locking it to one chat keeps that capability where you intended.
73
+ > Don't add the bot to groups, and don't share its token.
74
+
75
+ ---
76
+
77
+ ## Using ticlawk instead of Telegram
78
+
79
+ If you want the [ticlawk mobile app](https://ticlawk.com) instead, connect from
80
+ the project directory and scan the QR code with ticlawk. `ticlawk` will
81
+ detect local runtimes in that directory, and ticlawk will ask you which one to
82
+ connect:
83
+
84
+ ```bash
85
+ cd /path/to/project
86
+ ticlawk connect
87
+ ```
88
+
89
+ Full walkthrough: [docs/clients/ticlawk.md](docs/clients/ticlawk.md).
90
+ Telegram details: [docs/clients/telegram.md](docs/clients/telegram.md).
91
+
92
+ ---
93
+
94
+ ## Using Codex, OpenClaw, or opencode instead of Claude Code
95
+
96
+ Keep the same two-step adapter flow:
97
+
98
+ 1. `ticlawk auth <adapter> ...`
99
+ 2. `ticlawk connect --adapter <adapter> ...`
100
+
101
+ Then swap the runtime locator with `--type`:
102
+
103
+ ```bash
104
+ # Telegram + Codex
105
+ ticlawk connect --adapter telegram --type codex --workdir /path/to/project
106
+
107
+ # ticlawk + Codex, when you want to bypass mobile runtime selection
108
+ ticlawk connect --adapter ticlawk --type codex --workdir /path/to/project
109
+
110
+ # Telegram + OpenClaw
111
+ ticlawk connect --adapter telegram --type openclaw --agent-id main
112
+
113
+ # ticlawk + OpenClaw
114
+ ticlawk connect --adapter ticlawk --type openclaw --agent-id main
115
+
116
+ # Telegram + opencode
117
+ ticlawk connect --adapter telegram --type opencode --workdir /path/to/project
118
+
119
+ # ticlawk + opencode, when you want to bypass mobile runtime selection
120
+ ticlawk connect --adapter ticlawk --type opencode --workdir /path/to/project
121
+ ```
122
+
123
+ Runtime locators at a glance:
124
+
125
+ | Runtime | Required | Optional resume handle | Where to find it |
126
+ |-------------|----------------|------------------------|---------------------------------------------------------------|
127
+ | Claude Code | `--workdir` | `--session-id` | filename of `~/.claude/projects/**/*.jsonl` (without `.jsonl`)|
128
+ | Codex | `--workdir` | `--session-id` | `payload.id` in the first `session_meta` record of `~/.codex/sessions/**/*.jsonl` |
129
+ | OpenClaw | `--agent-id` | none | logical agent name (`main` by default) |
130
+ | opencode | `--workdir` | `--session-id` (with `--workdir`) | `.id` from `opencode session list --format json` (run inside the project dir) |
131
+
132
+ [OpenClaw](https://github.com/openclaw/openclaw) is an open-source local-first
133
+ agent runtime; skip this row if you don't use it.
134
+
135
+ OpenClaw has built-in channels; use `ticlawk` only if you want a single
136
+ chat surface across Claude Code, Codex, OpenClaw, and opencode.
137
+
138
+ [opencode](https://opencode.ai) is provider-agnostic — it doesn't carry its own
139
+ account system. Before connecting through `ticlawk`, install the CLI
140
+ (`npm i -g opencode-ai`) and authenticate it once against the LLM provider
141
+ you want it to use (`opencode auth login`, then pick Anthropic / OpenAI /
142
+ Google / OpenRouter / etc. and paste the corresponding API key). Model
143
+ selection lives in opencode's own config (`opencode.json` in the project
144
+ root, or user-level config) — `ticlawk` does not pass `--model`.
145
+
146
+ `ticlawk` spawns opencode with `--dangerously-skip-permissions`
147
+ (matching how Codex is wired), so chat messages can drive shell commands and
148
+ file edits in the bound `--workdir` without further confirmation prompts.
149
+ This is the same security boundary documented above; only connect a workdir
150
+ you trust to a chat you control.
151
+
152
+ ---
153
+
154
+ ## `auth` vs `connect`
155
+
156
+ You only need to know this once:
157
+
158
+ - **`auth`** — store adapter-specific setup input locally.
159
+ Telegram takes `--bot-token`. ticlawk uses QR pairing from `connect`.
160
+ - **`connect`** — connect the selected adapter to a local runtime.
161
+ For ticlawk, `ticlawk connect` auto-detects local runtimes and
162
+ lets you pick in the mobile app. Use `--workdir` for Telegram or explicit
163
+ ticlawk runtime selection, optionally add `--session-id` to resume, or use
164
+ `--agent-id` for OpenClaw.
165
+
166
+ `auth` is adapter-specific by subcommand shape:
167
+ - `ticlawk auth telegram --bot-token ...`
168
+
169
+ That keeps adapter auth flags scoped to the adapter without making users learn
170
+ the `--` passthrough convention.
171
+
172
+ ---
173
+
174
+ ## Daily use
175
+
176
+ After setup, the usual workflow is simple:
177
+
178
+ - Keep `ticlawk` running as a user service. If Linux prints an
179
+ `Action required` message during install or connect, run the command it
180
+ shows so the daemon keeps running after logout and reboot.
181
+ - Keep using the same Telegram chat or ticlawk channel. The adapter auth and
182
+ channel binding stay on disk until you change them.
183
+ - If you want to have the work done just like tiktoking, run
184
+ `ticlawk connect ...` again with the new `--workdir`.
185
+ - If you want to resume an existing Claude Code or Codex conversation, add
186
+ `--session-id`; otherwise the next message creates a fresh session.
187
+ - If an OpenClaw agent changes, reconnect with the new `--agent-id`.
188
+ - If replies stop because the local runtime session ended, run `connect` again
189
+ or reset the session from the client UI.
190
+ - `ticlawk health` is the first thing to check when something feels off.
191
+
192
+ ---
193
+
194
+ ## Verifying and troubleshooting
195
+
196
+ ```bash
197
+ ticlawk health
198
+ ```
199
+
200
+ - `ok: true` and the adapter-specific fields populated → you're good.
201
+ - Can't reach `127.0.0.1:8741` → the daemon isn't running. Start it with
202
+ `systemctl --user restart ticlawk`,
203
+ `launchctl kickstart -k gui/$(id -u)/ticlawk`, or `ticlawk start`.
204
+ - Telegram shows `runtimeConnected: true` and `connectedChat: false` →
205
+ send the first DM to the bot to claim its only chat.
206
+ - Telegram shows `botConfigured: false` → rerun
207
+ `ticlawk auth telegram --bot-token ...`, then restart the daemon.
208
+ - ticlawk shows `apiKey: false` → rerun `ticlawk connect`
209
+ from the project directory and scan the QR code.
210
+
211
+ Logs:
212
+
213
+ ```bash
214
+ tail -f ~/.ticlawk/ticlawk.log # normal output
215
+ tail -f ~/.ticlawk/ticlawk-crash.log # crashes, signals, exit diagnostics
216
+ ```
217
+
218
+ ---
219
+
220
+ ## What the installer does
221
+
222
+ ```bash
223
+ curl -fsSL https://raw.githubusercontent.com/darthjaja6/ticlawk/main/install.sh | bash
224
+ ```
225
+
226
+ It expects local `node` and `npm`, then:
227
+
228
+ - installs or updates the npm package with `npm install -g ticlawk`
229
+ - creates `~/.ticlawk/` for config and logs
230
+ - installs a user-level service — systemd on Linux, launchd on macOS — so the
231
+ daemon restarts automatically
232
+
233
+ On Linux, if systemd linger is off, the installer prints:
234
+
235
+ ```text
236
+ Action required
237
+
238
+ ticlawk may stop when you log out because systemd linger is off.
239
+
240
+ Run this command to keep it running after logout and reboot:
241
+ sudo loginctl enable-linger <user>
242
+ ```
243
+
244
+ Prefer not to `curl | bash`? Install with npm, then connect from the project
245
+ directory you want the agent to use:
246
+
247
+ ```bash
248
+ npm install -g ticlawk
249
+ ticlawk connect
250
+ ```
251
+
252
+ `connect` saves the pairing and refreshes the background service. If Linux
253
+ systemd linger is off, it prints the same `Action required` message shown by
254
+ the installer.
255
+
256
+ Update with `ticlawk update`. To remove the service and legacy managed
257
+ install files while keeping `~/.ticlawk` config, bindings, profiles, and
258
+ logs:
259
+
260
+ ```bash
261
+ ticlawk uninstall
262
+ ```
263
+
264
+ That removes:
265
+
266
+ - legacy `~/.local/share/ticlawk`
267
+ - legacy `~/.local/bin/ticlawk`
268
+ - `~/.config/systemd/user/ticlawk.service` (Linux)
269
+ - `~/Library/LaunchAgents/ticlawk.plist` (macOS)
270
+
271
+ `~/.ticlawk` is preserved. Use `npm uninstall -g ticlawk` to remove
272
+ the npm package itself.
273
+
274
+ ---
275
+
276
+ ## Config
277
+
278
+ Config lives in `~/.ticlawk/.config`. Most people only need to set
279
+ `adapter`, then use `auth` for adapter-specific setup. The dotted
280
+ credential keys below still exist for manual or advanced setups.
281
+
282
+ ```bash
283
+ ticlawk config # show current config
284
+ ticlawk config set adapter telegram # or: ticlawk
285
+ ticlawk auth telegram --bot-token <t>
286
+ ticlawk config set telegram.bot-token <t> # advanced/manual override
287
+ ticlawk config set ticlawk.connector-api-key <k> # advanced/manual override
288
+ ticlawk config set ticlawk.connector-ws-url <url> # advanced/manual override
289
+ ticlawk config set streaming off # disable streaming output globally
290
+ ticlawk config set streaming.codex on # force streaming on for codex only
291
+ ticlawk config set streaming.codex default # clear the codex override; inherit the global setting
292
+ ```
293
+
294
+ Key mapping (for anyone editing the file directly):
295
+
296
+ | Config key | Env var |
297
+ |-----------------------|----------------------|
298
+ | `adapter` | `AF_ADAPTER` |
299
+ | `telegram.bot-token` | `TELEGRAM_BOT_TOKEN` |
300
+ | `ticlawk.connector-api-key` | `TICLAWK_CONNECTOR_API_KEY` |
301
+ | `ticlawk.api-url` | `TICLAWK_API_URL` |
302
+ | `ticlawk.connector-ws-url` | `TICLAWK_CONNECTOR_WS_URL` |
303
+
304
+ Streaming defaults to on. Full CLI reference: `ticlawk help`.
305
+
306
+ ---
307
+
308
+ ## CLI reference
309
+
310
+ <!-- usage:start -->
311
+ ```text
312
+ ticlawk
313
+
314
+ Usage:
315
+ ticlawk help
316
+ ticlawk help <command>
317
+ ticlawk start
318
+ ticlawk health
319
+ ticlawk config
320
+ ticlawk config get <adapter|streaming...|runtimes.claude_code.path|runtimes.codex.path|runtimes.opencode.path|runtimes.pi.path|telegram.bot-token|ticlawk.connector-api-key|ticlawk.api-url|ticlawk.connector-ws-url>
321
+ ticlawk config set <adapter|streaming...|runtimes.claude_code.path|runtimes.codex.path|runtimes.opencode.path|runtimes.pi.path|telegram.bot-token|ticlawk.connector-api-key|ticlawk.api-url|ticlawk.connector-ws-url> <value>
322
+ ticlawk auth <adapter> [adapter-auth-args...]
323
+ ticlawk connect [ticlawk] [codex|claude|opencode|openclaw|pi] [runtime args...]
324
+ ticlawk connect [--adapter <adapter>] [--session-id <id>] --workdir <dir> [--switch-user]
325
+ ticlawk connect [--adapter <adapter>] --type codex [--session-id <id>] --workdir <dir> [--name <name>] [--runtime-path <path>] [--switch-user]
326
+ ticlawk connect [--adapter <adapter>] --type openclaw --agent-id <id> [--name <name>] [--runtime-path <path>] [--switch-user]
327
+ ticlawk connect [--adapter <adapter>] --type opencode [--session-id <id>] --workdir <dir> [--name <name>] [--runtime-path <path>] [--switch-user]
328
+ ticlawk connect [--adapter <adapter>] --type pi [--session-id <id>] --workdir <dir> [--name <name>] [--runtime-path <path>] [--switch-user]
329
+ ticlawk profile list
330
+ ticlawk profile current
331
+ ticlawk profile use ticlawk:<user-id>
332
+ ticlawk install-daemon
333
+ ticlawk update [-y]
334
+ ticlawk uninstall [-y]
335
+ ticlawk version
336
+
337
+ Commands:
338
+ auth store adapter-specific auth/setup input locally
339
+ connect connect the selected adapter to a local runtime
340
+ profile list or switch saved local identities
341
+ install-daemon install or refresh the background daemon
342
+ update update the npm package and refresh the daemon
343
+ uninstall remove service and legacy install files, preserving ~/.ticlawk
344
+
345
+ Config examples:
346
+ ticlawk config get adapter
347
+ ticlawk config set adapter telegram
348
+ ticlawk config set adapter ticlawk
349
+ ticlawk config set streaming off # turn streaming off for all runtimes
350
+ ticlawk config set streaming.codex default # clear the codex-specific override and inherit the global streaming setting
351
+ ticlawk config set runtimes.claude_code.path /path/to/claude_code # advanced/manual
352
+ ticlawk config set runtimes.codex.path /path/to/codex # advanced/manual
353
+ ticlawk config set runtimes.opencode.path /path/to/opencode # advanced/manual
354
+ ticlawk config set runtimes.pi.path /path/to/pi # advanced/manual
355
+ ticlawk config set telegram.bot-token <bot-token> # advanced/manual
356
+ ticlawk config set ticlawk.connector-api-key <key> # advanced/manual
357
+ ticlawk config set ticlawk.api-url <api-url> # advanced/manual
358
+ ticlawk config set ticlawk.connector-ws-url <url> # advanced/manual
359
+
360
+ Examples:
361
+ ticlawk connect
362
+ ticlawk connect ticlawk
363
+ ticlawk connect ticlawk codex
364
+ ticlawk connect ticlawk openclaw --agent-id main
365
+ ticlawk auth telegram --bot-token <bot-token>
366
+ ticlawk connect --adapter telegram --workdir /path/to/project
367
+ ticlawk connect --adapter telegram --session-id <claude-session-id>
368
+ ticlawk connect --adapter telegram --type codex --workdir /path/to/project
369
+ ticlawk connect --adapter telegram --type openclaw --agent-id main
370
+ ticlawk connect --adapter telegram --type opencode --workdir /path/to/project
371
+ ticlawk connect --adapter telegram --type pi --workdir /path/to/project
372
+ ```
373
+ <!-- usage:end -->
374
+
375
+ ---
376
+
377
+ ## Security model
378
+
379
+ This is the part to read before you set anything up.
380
+
381
+ - **The bot can run code on your machine.** Whatever Claude Code / Codex /
382
+ OpenClaw can do in the bound `--workdir`, the chat client can ask it to do.
383
+ Treat the chat as you'd treat a shell.
384
+ - **Single chat, single user.** The Telegram adapter binds to the first private
385
+ DM and rejects all others. The ticlawk adapter binds to one channel per
386
+ connect. Don't share bot tokens or connector credentials.
387
+ - **Secrets stay local.** Bot tokens, ticlawk API keys, and binding metadata
388
+ live in `~/.ticlawk/.config` (mode `0600`) and never leave your
389
+ machine. The daemon listens on `127.0.0.1:8741` only — it does not bind to
390
+ any external interface.
391
+ - **Token leak = remote shell.** If your Telegram bot token leaks, anyone with
392
+ it can take over the bot and start a chat as the first DM. Rotate via
393
+ [@BotFather](https://t.me/BotFather) immediately. Same applies to a leaked
394
+ ticlawk connector API key — revoke it from the ticlawk app.
395
+ - **No telemetry.** `ticlawk` does not send analytics or usage data
396
+ anywhere. The only outbound traffic is to Telegram (when the telegram
397
+ adapter is active) or to your configured ticlawk API URL (default
398
+ `ticlawk.com`, when the ticlawk adapter is active).
399
+
400
+ ---
401
+
402
+ ## How it works
403
+
404
+ 1. You send a message in Telegram or ticlawk.
405
+ 2. The adapter delivers it to the local `ticlawk` daemon.
406
+ 3. The daemon routes it into the bound Claude Code / Codex / OpenClaw session
407
+ on your machine.
408
+ 4. The runtime replies; `ticlawk` captures the output (including
409
+ streaming tokens and supported artifacts).
410
+ 5. The reply goes back through the adapter to the same chat.
411
+
412
+ For ticlawk inbound delivery, `ticlawk` keeps a WebSocket connection to
413
+ the ticlawk connector wake endpoint. Wake events such as `jobs.available` and
414
+ `bindings.changed` do not include message text, media, or task payloads. On wake,
415
+ the local daemon uses the existing HTTP APIs to claim pending jobs and refresh
416
+ channel bindings. The durable queue and `claim-pending` API remain the only
417
+ ownership boundary. By default the wake endpoint is
418
+ `wss://edge.ticlawk.com/functions/v1/connector-wake`; override it with
419
+ `ticlawk.connector-ws-url` only for local development or advanced setups.
420
+ Low-frequency recovery audits still run so a missed wake or reconnect window
421
+ does not strand durable jobs; they stay slow and do not speed up when the wake
422
+ connection is disconnected.
423
+
424
+ The daemon owns the binding — which adapter target talks to which local
425
+ runtime, and the metadata needed to resume that runtime later. Adapters own
426
+ their own authentication. That's the whole architecture.
@@ -0,0 +1,2 @@
1
+ // Legacy module alias kept so direct local imports can survive the rename.
2
+ export * from './ticlawk.mjs';
@@ -0,0 +1,137 @@
1
+ <svg width="960" height="520" viewBox="0 0 960 520" fill="none" xmlns="http://www.w3.org/2000/svg" role="img" aria-labelledby="title desc">
2
+ <title id="title">ticlawk connects any client to any agent</title>
3
+ <desc id="desc">A hub-and-spoke diagram with clients on the left, ticlawk in the center, and agent runtimes on the right.</desc>
4
+
5
+ <defs>
6
+ <linearGradient id="hub" x1="372" y1="162" x2="588" y2="378" gradientUnits="userSpaceOnUse">
7
+ <stop stop-color="#1D4ED8"/>
8
+ <stop offset="0.52" stop-color="#0F766E"/>
9
+ <stop offset="1" stop-color="#7C2D12"/>
10
+ </linearGradient>
11
+ <linearGradient id="clientLine" x1="180" y1="72" x2="460" y2="260" gradientUnits="userSpaceOnUse">
12
+ <stop stop-color="#2563EB"/>
13
+ <stop offset="1" stop-color="#0F766E"/>
14
+ </linearGradient>
15
+ <linearGradient id="agentLine" x1="500" y1="260" x2="780" y2="448" gradientUnits="userSpaceOnUse">
16
+ <stop stop-color="#0F766E"/>
17
+ <stop offset="1" stop-color="#C2410C"/>
18
+ </linearGradient>
19
+ <filter id="shadow" x="-20%" y="-20%" width="140%" height="140%" color-interpolation-filters="sRGB">
20
+ <feDropShadow dx="0" dy="10" stdDeviation="16" flood-color="#0F172A" flood-opacity="0.12"/>
21
+ </filter>
22
+ <style>
23
+ .label { fill: #0f172a; font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; font-weight: 700; font-size: 16px; }
24
+ .small { fill: #475569; font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; font-weight: 600; font-size: 13px; }
25
+ .hubText { fill: white; font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; font-weight: 800; font-size: 27px; }
26
+ .hubSub { fill: #E0F2FE; font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; font-weight: 650; font-size: 13px; letter-spacing: 0.08em; }
27
+ .caption { fill: #334155; font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; font-weight: 650; font-size: 14px; }
28
+ .node { fill: #FFFFFF; stroke: #CBD5E1; stroke-width: 1.4; }
29
+ .dot { fill: #F8FAFC; stroke: #CBD5E1; stroke-width: 1.4; }
30
+ </style>
31
+ </defs>
32
+
33
+ <rect width="960" height="520" rx="22" fill="#F8FAFC"/>
34
+ <rect x="24" y="24" width="912" height="472" rx="18" fill="#FFFFFF" stroke="#E2E8F0"/>
35
+
36
+ <text x="180" y="64" text-anchor="middle" class="caption">Any client surface</text>
37
+ <text x="780" y="64" text-anchor="middle" class="caption">Any agent runtime</text>
38
+
39
+ <path d="M230 116 C310 126 350 166 405 215" stroke="url(#clientLine)" stroke-width="4" stroke-linecap="round"/>
40
+ <path d="M230 188 C310 192 354 216 405 244" stroke="url(#clientLine)" stroke-width="4" stroke-linecap="round"/>
41
+ <path d="M230 260 C306 260 348 260 405 260" stroke="url(#clientLine)" stroke-width="4" stroke-linecap="round"/>
42
+ <path d="M230 332 C310 328 354 304 405 276" stroke="url(#clientLine)" stroke-width="4" stroke-linecap="round"/>
43
+ <path d="M230 404 C310 394 350 354 405 305" stroke="url(#clientLine)" stroke-width="4" stroke-linecap="round"/>
44
+
45
+ <path d="M555 215 C610 166 650 126 730 116" stroke="url(#agentLine)" stroke-width="4" stroke-linecap="round"/>
46
+ <path d="M555 244 C606 216 650 192 730 188" stroke="url(#agentLine)" stroke-width="4" stroke-linecap="round"/>
47
+ <path d="M555 260 C612 260 654 260 730 260" stroke="url(#agentLine)" stroke-width="4" stroke-linecap="round"/>
48
+ <path d="M555 276 C606 304 650 328 730 332" stroke="url(#agentLine)" stroke-width="4" stroke-linecap="round"/>
49
+ <path d="M555 305 C610 354 650 394 730 404" stroke="url(#agentLine)" stroke-width="4" stroke-linecap="round"/>
50
+
51
+ <g filter="url(#shadow)">
52
+ <rect x="70" y="88" width="160" height="56" rx="8" class="node"/>
53
+ <circle cx="100" cy="116" r="14" fill="#DBEAFE"/>
54
+ <path d="M94 116h12M100 110v12" stroke="#2563EB" stroke-width="2.4" stroke-linecap="round"/>
55
+ <text x="124" y="112" class="label">Telegram</text>
56
+ <text x="124" y="130" class="small">chat bot</text>
57
+
58
+ <rect x="70" y="160" width="160" height="56" rx="8" class="node"/>
59
+ <circle cx="100" cy="188" r="14" fill="#CCFBF1"/>
60
+ <rect x="94" y="180" width="12" height="16" rx="3" stroke="#0F766E" stroke-width="2.2"/>
61
+ <path d="M98 202h4" stroke="#0F766E" stroke-width="2.2" stroke-linecap="round"/>
62
+ <text x="124" y="184" class="label">ticlawk</text>
63
+ <text x="124" y="202" class="small">mobile app</text>
64
+
65
+ <rect x="70" y="232" width="160" height="56" rx="8" class="node"/>
66
+ <circle cx="100" cy="260" r="14" fill="#FDE68A"/>
67
+ <path d="M92 256h16M92 262h16M100 252v16" stroke="#A16207" stroke-width="2" stroke-linecap="round"/>
68
+ <text x="124" y="256" class="label">Web UI</text>
69
+ <text x="124" y="274" class="small">browser</text>
70
+
71
+ <rect x="70" y="304" width="160" height="56" rx="8" class="node"/>
72
+ <circle cx="100" cy="332" r="14" fill="#EDE9FE"/>
73
+ <path d="M94 326l6 6-6 6M102 338h6" stroke="#6D28D9" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/>
74
+ <text x="124" y="328" class="label">CLI</text>
75
+ <text x="124" y="346" class="small">terminal</text>
76
+
77
+ <rect x="70" y="376" width="160" height="56" rx="8" class="node"/>
78
+ <circle cx="100" cy="404" r="14" fill="#FFE4E6"/>
79
+ <path d="M94 398h12v12H94z" stroke="#BE123C" stroke-width="2.2" stroke-linejoin="round"/>
80
+ <path d="M97 395h6M97 413h6" stroke="#BE123C" stroke-width="2.2" stroke-linecap="round"/>
81
+ <text x="124" y="400" class="label">Custom app</text>
82
+ <text x="124" y="418" class="small">your surface</text>
83
+ </g>
84
+
85
+ <g filter="url(#shadow)">
86
+ <rect x="730" y="88" width="160" height="56" rx="8" class="node"/>
87
+ <circle cx="760" cy="116" r="14" fill="#FEF3C7"/>
88
+ <path d="M753 121l7-12 7 12M756 117h8" stroke="#B45309" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/>
89
+ <text x="784" y="112" class="label">Claude Code</text>
90
+ <text x="784" y="130" class="small">project agent</text>
91
+
92
+ <rect x="730" y="160" width="160" height="56" rx="8" class="node"/>
93
+ <circle cx="760" cy="188" r="14" fill="#DBEAFE"/>
94
+ <path d="M754 188a6 6 0 1 1 12 0a6 6 0 1 1-12 0" stroke="#1D4ED8" stroke-width="2.2"/>
95
+ <path d="M760 176v4M760 196v4M748 188h4M768 188h4" stroke="#1D4ED8" stroke-width="2.2" stroke-linecap="round"/>
96
+ <text x="784" y="184" class="label">Codex</text>
97
+ <text x="784" y="202" class="small">coding agent</text>
98
+
99
+ <rect x="730" y="232" width="160" height="56" rx="8" class="node"/>
100
+ <circle cx="760" cy="260" r="14" fill="#CCFBF1"/>
101
+ <path d="M752 260h16M760 252v16M755 255l10 10M765 255l-10 10" stroke="#0F766E" stroke-width="2" stroke-linecap="round"/>
102
+ <text x="784" y="256" class="label">OpenClaw</text>
103
+ <text x="784" y="274" class="small">local runtime</text>
104
+
105
+ <rect x="730" y="304" width="160" height="56" rx="8" class="node"/>
106
+ <circle cx="760" cy="332" r="14" fill="#FCE7F3"/>
107
+ <path d="M752 332c3-8 13-8 16 0c-3 8-13 8-16 0Z" stroke="#BE185D" stroke-width="2.2"/>
108
+ <circle cx="760" cy="332" r="3" fill="#BE185D"/>
109
+ <text x="784" y="328" class="label">opencode</text>
110
+ <text x="784" y="346" class="small">provider agnostic</text>
111
+
112
+ <rect x="730" y="376" width="160" height="56" rx="8" class="node"/>
113
+ <circle cx="760" cy="404" r="14" fill="#E0E7FF"/>
114
+ <path d="M754 398h12v12h-12zM751 401h3M766 401h3M751 407h3M766 407h3" stroke="#4338CA" stroke-width="2" stroke-linejoin="round"/>
115
+ <text x="784" y="400" class="label">Custom agent</text>
116
+ <text x="784" y="418" class="small">your harness</text>
117
+ </g>
118
+
119
+ <g filter="url(#shadow)">
120
+ <circle cx="480" cy="260" r="118" fill="url(#hub)"/>
121
+ <circle cx="480" cy="260" r="86" fill="#FFFFFF" fill-opacity="0.12" stroke="#FFFFFF" stroke-opacity="0.32" stroke-width="1.5"/>
122
+ <circle cx="480" cy="260" r="52" fill="#FFFFFF" fill-opacity="0.16" stroke="#FFFFFF" stroke-opacity="0.38" stroke-width="1.4"/>
123
+
124
+ <circle cx="480" cy="176" r="8" class="dot"/>
125
+ <circle cx="548" cy="212" r="8" class="dot"/>
126
+ <circle cx="548" cy="308" r="8" class="dot"/>
127
+ <circle cx="480" cy="344" r="8" class="dot"/>
128
+ <circle cx="412" cy="308" r="8" class="dot"/>
129
+ <circle cx="412" cy="212" r="8" class="dot"/>
130
+ <path d="M480 184v152M420 216l120 88M540 216l-120 88" stroke="#FFFFFF" stroke-opacity="0.65" stroke-width="2.6" stroke-linecap="round"/>
131
+
132
+ <text x="480" y="253" text-anchor="middle" class="hubText">ticlawk</text>
133
+ <text x="480" y="281" text-anchor="middle" class="hubSub">UNIVERSAL ROUTER</text>
134
+ </g>
135
+
136
+ <text x="480" y="465" text-anchor="middle" class="small">Bind sessions, relay streams, keep every side replaceable.</text>
137
+ </svg>
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env node
2
+
3
+ // Legacy CLI alias kept so existing automation can survive the package rename.
4
+ import './ticlawk.mjs';