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
@@ -0,0 +1,594 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { request } from 'node:http';
4
+ import { resolve } from 'node:path';
5
+ import { installProcessDiagnostics } from '../src/core/diagnostics.mjs';
6
+ import {
7
+ AF_ADAPTER_KEY,
8
+ getConfiguredAdapter,
9
+ loadPersistentConfig,
10
+ getStreamingConfigView,
11
+ LEGACY_TICLAWK_API_KEY,
12
+ normalizeAdapterConfigTarget,
13
+ normalizeAdapterName,
14
+ normalizeRuntimeConfigTarget,
15
+ normalizeStreamingTarget,
16
+ persistConfig,
17
+ SUPPORTED_ADAPTERS,
18
+ TICLAWK_CONNECTOR_API_KEY,
19
+ TICLAWK_CONNECTOR_WS_URL,
20
+ } from '../src/core/config.mjs';
21
+ import { parseOptionArgs } from '../src/core/argv.mjs';
22
+ import {
23
+ activateProfile,
24
+ getActiveProfile,
25
+ listProfiles,
26
+ } from '../src/core/profiles.mjs';
27
+ import { getAdapterAuthHelp, runAdapterAuth } from '../src/core/adapter-registry.mjs';
28
+ import { runTiclawkConnect } from '../src/core/ticlawk-control.mjs';
29
+ import {
30
+ RUNTIME_DEFINITIONS,
31
+ getRuntimeDefinition,
32
+ getRuntimeDisplayName,
33
+ getRuntimeExecutableDefinitions,
34
+ normalizeServiceType,
35
+ } from '../src/core/runtime-registry.mjs';
36
+ import { runSelfUpdate, readPkgVersion } from '../src/core/update.mjs';
37
+ import { getUninstallHelp, runSelfUninstall } from '../src/core/uninstall.mjs';
38
+ import { getInstallDaemonHelp, runInstallDaemon } from '../src/core/daemon-install.mjs';
39
+ import { runSetupReadiness } from '../src/core/setup-readiness.mjs';
40
+
41
+ const TICLAWK_PORT = Number(process.env.FEED_RELAY_PORT || 8741);
42
+
43
+ function getConfigKeyUsage() {
44
+ const runtimeKeys = getRuntimeExecutableDefinitions().map((runtime) => runtime.executableCliKey);
45
+ return ['adapter', 'streaming...', ...runtimeKeys, 'telegram.bot-token', 'ticlawk.connector-api-key', 'ticlawk.api-url', 'ticlawk.connector-ws-url'].join('|');
46
+ }
47
+
48
+ function getRuntimeConnectUsageLines() {
49
+ return RUNTIME_DEFINITIONS
50
+ .filter((runtime) => !runtime.aliases.includes(''))
51
+ .map((runtime) => {
52
+ if (runtime.connect?.locator === 'agentId') {
53
+ return ` ticlawk connect [--adapter <adapter>] --type ${runtime.name} --agent-id <id> [--name <name>] [--runtime-path <path>] [--switch-user]`;
54
+ }
55
+ return ` ticlawk connect [--adapter <adapter>] --type ${runtime.name} [--session-id <id>] --workdir <dir> [--name <name>] [--runtime-path <path>] [--switch-user]`;
56
+ })
57
+ .join('\n');
58
+ }
59
+
60
+ function getRuntimeConfigExamples() {
61
+ return getRuntimeExecutableDefinitions()
62
+ .map((runtime) => ` ticlawk config set ${runtime.executableCliKey} /path/to/${runtime.name} # advanced/manual`)
63
+ .join('\n');
64
+ }
65
+
66
+ function getRuntimeConnectExamples() {
67
+ return [
68
+ ' ticlawk connect --adapter telegram --workdir /path/to/project',
69
+ ' ticlawk connect --adapter telegram --session-id <claude-session-id>',
70
+ ...RUNTIME_DEFINITIONS
71
+ .filter((runtime) => !runtime.aliases.includes(''))
72
+ .slice(0, 4)
73
+ .map((runtime) => {
74
+ if (runtime.connect?.locator === 'agentId') {
75
+ return ` ticlawk connect --adapter telegram --type ${runtime.name} --agent-id main`;
76
+ }
77
+ return ` ticlawk connect --adapter telegram --type ${runtime.name} --workdir /path/to/project`;
78
+ }),
79
+ ].join('\n');
80
+ }
81
+
82
+ function getUsageText() {
83
+ const configKeys = getConfigKeyUsage();
84
+ return `ticlawk
85
+
86
+ Usage:
87
+ ticlawk help
88
+ ticlawk help <command>
89
+ ticlawk start
90
+ ticlawk health
91
+ ticlawk config
92
+ ticlawk config get <${configKeys}>
93
+ ticlawk config set <${configKeys}> <value>
94
+ ticlawk auth <adapter> [adapter-auth-args...]
95
+ ticlawk connect [ticlawk] [codex|claude|opencode|openclaw|pi] [runtime args...]
96
+ ticlawk connect [--adapter <adapter>] [--session-id <id>] --workdir <dir> [--switch-user]
97
+ ${getRuntimeConnectUsageLines()}
98
+ ticlawk profile list
99
+ ticlawk profile current
100
+ ticlawk profile use ticlawk:<user-id>
101
+ ticlawk install-daemon
102
+ ticlawk update [-y]
103
+ ticlawk uninstall [-y]
104
+ ticlawk version
105
+
106
+ Commands:
107
+ auth store adapter-specific auth/setup input locally
108
+ connect connect the selected adapter to a local runtime
109
+ profile list or switch saved local identities
110
+ install-daemon install or refresh the background daemon
111
+ update update the npm package and refresh the daemon
112
+ uninstall remove service and legacy install files, preserving ~/.ticlawk
113
+
114
+ Config examples:
115
+ ticlawk config get adapter
116
+ ticlawk config set adapter telegram
117
+ ticlawk config set adapter ticlawk
118
+ ticlawk config set streaming off # turn streaming off for all runtimes
119
+ ticlawk config set streaming.codex default # clear the codex-specific override and inherit the global streaming setting
120
+ ${getRuntimeConfigExamples()}
121
+ ticlawk config set telegram.bot-token <bot-token> # advanced/manual
122
+ ticlawk config set ticlawk.connector-api-key <key> # advanced/manual
123
+ ticlawk config set ticlawk.api-url <api-url> # advanced/manual
124
+ ticlawk config set ticlawk.connector-ws-url <url> # advanced/manual
125
+
126
+ Examples:
127
+ ticlawk connect
128
+ ticlawk connect ticlawk
129
+ ticlawk connect ticlawk codex
130
+ ticlawk connect ticlawk openclaw --agent-id main
131
+ ticlawk auth telegram --bot-token <bot-token>
132
+ ${getRuntimeConnectExamples()}
133
+ `;
134
+ }
135
+
136
+ function getAuthHelp() {
137
+ return `ticlawk auth
138
+
139
+ Use \`auth\` to store adapter-specific auth/setup input locally.
140
+ Adapter-specific args live after \`--\` so new adapters can define their own flags
141
+ without changing the top-level CLI.
142
+
143
+ Examples:
144
+ ticlawk auth telegram --bot-token <bot-token>
145
+
146
+ Per-adapter help:
147
+ ticlawk auth telegram --help
148
+ `;
149
+ }
150
+
151
+ function getConnectHelp() {
152
+ return `ticlawk connect
153
+
154
+ Use \`connect\` to connect the selected adapter to a local runtime.
155
+ For ticlawk, connect starts the QR pairing flow when no local credential exists.
156
+ Run \`ticlawk connect\` from a project directory to auto-detect
157
+ Codex, Claude Code, opencode, and pi, then choose the runtime in ticlawk.
158
+ By default connect records the runtime binary found in your current terminal.
159
+ Use \`--runtime-path <path>\` only when you need to override that discovery.
160
+
161
+ Examples:
162
+ ticlawk connect
163
+ ticlawk connect ticlawk
164
+ ticlawk connect ticlawk codex
165
+ ticlawk connect ticlawk openclaw --agent-id main
166
+ ${getRuntimeConnectExamples()}
167
+ `;
168
+ }
169
+
170
+ function printUsage() {
171
+ console.log(getUsageText());
172
+ }
173
+
174
+ function printHelp(helpPath, args = {}) {
175
+ const [head] = helpPath;
176
+ if (!head) {
177
+ printUsage();
178
+ return;
179
+ }
180
+ if (head === 'auth') {
181
+ const adapterValue = helpPath[1] || args._?.[1];
182
+ if (adapterValue) {
183
+ console.log(getAdapterAuthHelp(requireAdapter(adapterValue)));
184
+ return;
185
+ }
186
+ console.log(getAuthHelp());
187
+ return;
188
+ }
189
+ if (head === 'connect') {
190
+ console.log(getConnectHelp());
191
+ return;
192
+ }
193
+ if (head === 'uninstall') {
194
+ console.log(getUninstallHelp());
195
+ return;
196
+ }
197
+ if (head === 'install-daemon') {
198
+ console.log(getInstallDaemonHelp());
199
+ return;
200
+ }
201
+ printUsage();
202
+ }
203
+
204
+ function formatStreamingValue(value, inherited = false) {
205
+ const text = value ? 'on' : 'off';
206
+ return inherited ? `default(${text})` : text;
207
+ }
208
+
209
+ function parseConfigBoolean(value) {
210
+ const normalized = String(value || '').trim().toLowerCase();
211
+ if (['1', 'true', 'on', 'yes'].includes(normalized)) return '1';
212
+ if (['0', 'false', 'off', 'no'].includes(normalized)) return '0';
213
+ if (normalized === 'default') return null;
214
+ return undefined;
215
+ }
216
+
217
+ function printConfigView(config = loadPersistentConfig()) {
218
+ console.log(`adapter=${getConfiguredAdapter(config)}`);
219
+ const view = getStreamingConfigView(config);
220
+ console.log(`streaming=${formatStreamingValue(view.streaming.value, view.streaming.inherited)}`);
221
+ for (const runtime of RUNTIME_DEFINITIONS) {
222
+ const key = `streaming.${runtime.name}`;
223
+ if (!view[key]) continue;
224
+ console.log(`${key}=${formatStreamingValue(view[key].value, view[key].inherited)}`);
225
+ }
226
+ for (const runtime of getRuntimeExecutableDefinitions()) {
227
+ console.log(`${runtime.executableCliKey}=${config[runtime.executableConfigKey] || ''}`);
228
+ }
229
+ console.log(`telegram.bot-token=${config.TELEGRAM_BOT_TOKEN ? 'set' : 'unset'}`);
230
+ console.log(`ticlawk.connector-api-key=${config[TICLAWK_CONNECTOR_API_KEY] || config[LEGACY_TICLAWK_API_KEY] ? 'set' : 'unset'}`);
231
+ console.log(`ticlawk.api-url=${config.TICLAWK_API_URL || ''}`);
232
+ console.log(`ticlawk.connector-ws-url=${config[TICLAWK_CONNECTOR_WS_URL] || ''}`);
233
+ }
234
+
235
+ function getLocal(path) {
236
+ return new Promise((resolve, reject) => {
237
+ const req = request(
238
+ { host: '127.0.0.1', port: TICLAWK_PORT, path, method: 'GET' },
239
+ (res) => {
240
+ let data = '';
241
+ res.on('data', (chunk) => { data += chunk; });
242
+ res.on('end', () => {
243
+ try {
244
+ resolve({
245
+ statusCode: res.statusCode || 0,
246
+ body: data ? JSON.parse(data) : {},
247
+ });
248
+ } catch (err) {
249
+ reject(err);
250
+ }
251
+ });
252
+ }
253
+ );
254
+ req.on('error', reject);
255
+ req.end();
256
+ });
257
+ }
258
+
259
+ function formatSecretConfigValue(configKey, value) {
260
+ if (configKey === 'TELEGRAM_BOT_TOKEN' || configKey === TICLAWK_CONNECTOR_API_KEY || configKey === LEGACY_TICLAWK_API_KEY) {
261
+ return value ? 'set' : 'unset';
262
+ }
263
+ return value || '';
264
+ }
265
+
266
+ function requireAdapter(value) {
267
+ const adapterId = normalizeAdapterName(value);
268
+ if (!adapterId) {
269
+ const supported = SUPPORTED_ADAPTERS.join(', ');
270
+ console.error(`invalid adapter: ${value || ''} (supported: ${supported})`);
271
+ process.exit(1);
272
+ }
273
+ return adapterId;
274
+ }
275
+
276
+ function getConnectAdapter(value) {
277
+ if (value === undefined || value === null || value === '') {
278
+ return getConfiguredAdapter();
279
+ }
280
+ return requireAdapter(value);
281
+ }
282
+
283
+ function buildConnectPayload(args) {
284
+ const positionalAdapter = normalizeAdapterName(args._?.[1]) ? args._[1] : null;
285
+ const positionalRuntime = positionalAdapter ? args._?.[2] : args._?.[1];
286
+ const serviceType = normalizeServiceType(args.type || positionalRuntime);
287
+ const explicitWorkdir = args.workdir || args.cwd || args['project-dir'];
288
+ const workdir = explicitWorkdir || (positionalAdapter ? resolve('.') : null);
289
+ const hasExplicitAdapter = Boolean(args.adapter || positionalAdapter);
290
+ const adapter = (!serviceType && !hasExplicitAdapter)
291
+ ? 'ticlawk'
292
+ : getConnectAdapter(args.adapter || positionalAdapter);
293
+ if (!serviceType) {
294
+ if (adapter === 'ticlawk' && !args.type && !positionalRuntime) {
295
+ return {
296
+ adapter,
297
+ autoRuntime: true,
298
+ switchUser: Boolean(args['switch-user']),
299
+ ...(workdir ? { workdir } : {}),
300
+ ...(args.name ? { name: args.name } : {}),
301
+ };
302
+ }
303
+ console.error(`invalid runtime type: ${args.type || positionalRuntime || ''}`);
304
+ process.exit(1);
305
+ }
306
+
307
+ const runtimeDefinition = getRuntimeDefinition(serviceType);
308
+ if (runtimeDefinition?.connect?.locator === 'agentId') {
309
+ return {
310
+ adapter,
311
+ serviceType,
312
+ agentId: args['agent-id'],
313
+ ...(workdir ? { workdir } : {}),
314
+ ...(args['runtime-path'] ? { runtimePath: resolve(args['runtime-path']) } : {}),
315
+ name: args.name || args['agent-id'],
316
+ switchUser: Boolean(args['switch-user']),
317
+ };
318
+ }
319
+
320
+ return {
321
+ adapter,
322
+ serviceType,
323
+ sessionId: args['session-id'],
324
+ switchUser: Boolean(args['switch-user']),
325
+ ...(workdir ? { workdir } : {}),
326
+ ...(args.name ? { name: args.name } : {}),
327
+ ...(args['runtime-path'] ? { runtimePath: resolve(args['runtime-path']) } : {}),
328
+ };
329
+ }
330
+
331
+ function validateConnectPayload(payload) {
332
+ if (payload.autoRuntime) return;
333
+ const runtimeDefinition = getRuntimeDefinition(payload.serviceType);
334
+ if (runtimeDefinition?.connect?.locator === 'agentId' && !payload.agentId) {
335
+ console.error(`--agent-id is required for ${getRuntimeDisplayName(payload.serviceType)} connect`);
336
+ process.exit(1);
337
+ }
338
+ if (runtimeDefinition?.connect?.locator !== 'agentId' && !payload.sessionId && !payload.workdir) {
339
+ const runtimeName = getRuntimeDisplayName(payload.serviceType);
340
+ console.error(`either --session-id or --workdir is required for ${runtimeName} connect`);
341
+ process.exit(1);
342
+ }
343
+ }
344
+
345
+ function printCommandResult(result) {
346
+ if (result?.body?.help) {
347
+ console.log(result.body.help);
348
+ return;
349
+ }
350
+ console.log(JSON.stringify(result?.body || {}, null, 2));
351
+ }
352
+
353
+ function formatProfileIdentity(profile) {
354
+ const meta = profile.meta || {};
355
+ const parts = [
356
+ profile.ref,
357
+ meta.emailMasked || meta.email_masked || '',
358
+ meta.phoneMasked || meta.phone_masked || '',
359
+ ].filter(Boolean);
360
+ return parts.join(' ');
361
+ }
362
+
363
+ function parseProfileUseRef(value) {
364
+ const raw = String(value || '').trim();
365
+ const [adapter, ...rest] = raw.split(':');
366
+ const userId = rest.join(':');
367
+ if (!adapter || !userId) return null;
368
+ return { adapter, userId };
369
+ }
370
+
371
+ async function main() {
372
+ const rawArgv = process.argv.slice(2);
373
+ const args = parseOptionArgs(rawArgv);
374
+ const command = args._[0] || 'start';
375
+
376
+ if (command === 'help' || args.help || args.h) {
377
+ const helpPath = command === 'help' ? args._.slice(1) : args._;
378
+ printHelp(helpPath, args);
379
+ return;
380
+ }
381
+
382
+ if (command === 'version' || args.version) {
383
+ console.log(readPkgVersion());
384
+ return;
385
+ }
386
+
387
+ if (command === 'start') {
388
+ installProcessDiagnostics();
389
+ const { startTiclawk } = await import('../ticlawk.mjs');
390
+ await startTiclawk();
391
+ return;
392
+ }
393
+
394
+ if (command === 'health') {
395
+ const res = await getLocal('/health');
396
+ console.log(JSON.stringify(res.body, null, 2));
397
+ process.exitCode = res.statusCode >= 400 ? 1 : 0;
398
+ return;
399
+ }
400
+
401
+ if (command === 'config') {
402
+ const subcommand = args._[1];
403
+ const config = loadPersistentConfig();
404
+ if (!subcommand) {
405
+ printConfigView(config);
406
+ return;
407
+ }
408
+
409
+ if (subcommand === 'get') {
410
+ const key = args._[2];
411
+ if (key === 'adapter') {
412
+ console.log(getConfiguredAdapter(config));
413
+ return;
414
+ }
415
+ const adapterTarget = normalizeAdapterConfigTarget(key);
416
+ if (adapterTarget) {
417
+ console.log(formatSecretConfigValue(adapterTarget.configKey, config[adapterTarget.configKey]));
418
+ return;
419
+ }
420
+ const runtimeTarget = normalizeRuntimeConfigTarget(key);
421
+ if (runtimeTarget) {
422
+ console.log(config[runtimeTarget.configKey] || '');
423
+ return;
424
+ }
425
+ const target = normalizeStreamingTarget(key);
426
+ if (!target) {
427
+ console.error(`unknown config key: ${key || ''}`);
428
+ process.exit(1);
429
+ }
430
+ const view = getStreamingConfigView();
431
+ const current = view[target.key];
432
+ console.log(formatStreamingValue(current.value, current.inherited));
433
+ return;
434
+ }
435
+
436
+ if (subcommand === 'set') {
437
+ const key = args._[2];
438
+ const rawValue = args._[3];
439
+ if (key === 'adapter') {
440
+ if (!rawValue) {
441
+ console.error('config set adapter requires a value');
442
+ process.exit(1);
443
+ }
444
+ const adapterId = requireAdapter(rawValue);
445
+ persistConfig({ [AF_ADAPTER_KEY]: adapterId });
446
+ console.log(`adapter=${adapterId}`);
447
+ return;
448
+ }
449
+ const adapterTarget = normalizeAdapterConfigTarget(key);
450
+ if (adapterTarget) {
451
+ if (!rawValue) {
452
+ console.error(`config set ${key} requires a value`);
453
+ process.exit(1);
454
+ }
455
+ persistConfig({ [adapterTarget.configKey]: rawValue });
456
+ console.log(`${adapterTarget.key}=${formatSecretConfigValue(adapterTarget.configKey, rawValue)}`);
457
+ return;
458
+ }
459
+ const runtimeTarget = normalizeRuntimeConfigTarget(key);
460
+ if (runtimeTarget) {
461
+ if (!rawValue) {
462
+ console.error(`config set ${key} requires a value`);
463
+ process.exit(1);
464
+ }
465
+ persistConfig({ [runtimeTarget.configKey]: rawValue === 'default' ? '' : rawValue });
466
+ console.log(`${runtimeTarget.key}=${rawValue === 'default' ? '' : rawValue}`);
467
+ return;
468
+ }
469
+ const target = normalizeStreamingTarget(key);
470
+ if (!target) {
471
+ console.error(`unknown config key: ${key || ''}`);
472
+ process.exit(1);
473
+ }
474
+ if (!rawValue) {
475
+ console.error('config set requires a value');
476
+ process.exit(1);
477
+ }
478
+ const parsedValue = parseConfigBoolean(rawValue);
479
+ if (parsedValue === undefined) {
480
+ console.error(`invalid config value: ${rawValue}`);
481
+ process.exit(1);
482
+ }
483
+ persistConfig({ [target.configKey]: parsedValue });
484
+ const view = getStreamingConfigView(loadPersistentConfig());
485
+ const currentKey = target.key;
486
+ const current = view[currentKey];
487
+ console.log(`${currentKey}=${formatStreamingValue(current.value, current.inherited)}`);
488
+ return;
489
+ }
490
+
491
+ console.error(`unknown config subcommand: ${subcommand}`);
492
+ process.exit(1);
493
+ }
494
+
495
+ if (command === 'profile') {
496
+ const subcommand = args._[1] || 'list';
497
+ const active = getActiveProfile();
498
+ if (subcommand === 'current') {
499
+ console.log(active?.ref || 'none');
500
+ return;
501
+ }
502
+ if (subcommand === 'list') {
503
+ const profiles = listProfiles();
504
+ console.log(`Active profile: ${active?.ref || 'none'}`);
505
+ if (!profiles.length) {
506
+ console.log('No saved profiles.');
507
+ return;
508
+ }
509
+ for (const profile of profiles) {
510
+ const marker = active?.ref === profile.ref ? '*' : ' ';
511
+ console.log(`${marker} ${formatProfileIdentity(profile)}`);
512
+ }
513
+ return;
514
+ }
515
+ if (subcommand === 'use') {
516
+ const target = parseProfileUseRef(args._[2]);
517
+ if (!target) {
518
+ console.error('profile use requires a profile ref like ticlawk:<user-id>');
519
+ process.exit(1);
520
+ }
521
+ const activated = activateProfile(target.adapter, target.userId);
522
+ console.log(`Active profile: ${activated.ref}`);
523
+ console.log('Restart ticlawk for the daemon to use the selected profile.');
524
+ return;
525
+ }
526
+ console.error(`unknown profile subcommand: ${subcommand}`);
527
+ process.exit(1);
528
+ }
529
+
530
+ if (command === 'update') {
531
+ await runSelfUpdate(Boolean(args.y || args.yes));
532
+ return;
533
+ }
534
+
535
+ if (command === 'install-daemon') {
536
+ if (args.help || args.h) {
537
+ console.log(getInstallDaemonHelp());
538
+ return;
539
+ }
540
+ await runInstallDaemon();
541
+ return;
542
+ }
543
+
544
+ if (command === 'setup-readiness') {
545
+ await runSetupReadiness({ ensureDaemon: Boolean(args['ensure-daemon']) });
546
+ return;
547
+ }
548
+
549
+ if (command === 'uninstall') {
550
+ if (args.help || args.h) {
551
+ console.log(getUninstallHelp());
552
+ return;
553
+ }
554
+ await runSelfUninstall(Boolean(args.y || args.yes));
555
+ return;
556
+ }
557
+
558
+ if (command === 'auth') {
559
+ if (args.help || args.h) {
560
+ printHelp(['auth'], args);
561
+ return;
562
+ }
563
+ const adapterId = requireAdapter(args._[1]);
564
+ const adapterArgv = rawArgv.slice(2);
565
+ const res = await runAdapterAuth(adapterId, adapterArgv);
566
+ printCommandResult(res);
567
+ process.exitCode = res.statusCode >= 400 ? 1 : 0;
568
+ return;
569
+ }
570
+
571
+ if (command === 'connect') {
572
+ if (args.help || args.h) {
573
+ console.log(getConnectHelp());
574
+ return;
575
+ }
576
+ const payload = buildConnectPayload(args);
577
+ validateConnectPayload(payload);
578
+ const res = await runTiclawkConnect(payload);
579
+ printCommandResult(res);
580
+ if (res.statusCode < 400) {
581
+ await runSetupReadiness({ ensureDaemon: true });
582
+ }
583
+ process.exitCode = res.statusCode >= 400 ? 1 : 0;
584
+ return;
585
+ }
586
+
587
+ printUsage();
588
+ process.exit(1);
589
+ }
590
+
591
+ main().catch((err) => {
592
+ console.error(err.message || String(err));
593
+ process.exit(1);
594
+ });
package/cc-watcher.mjs ADDED
@@ -0,0 +1,3 @@
1
+ // Compatibility entry for older deep imports.
2
+ // Runtime code imports the implementation from src/runtimes/claude-code/.
3
+ export * from './src/runtimes/claude-code/transcripts.mjs';
package/package.json ADDED
@@ -0,0 +1,72 @@
1
+ {
2
+ "name": "ticlawk",
3
+ "version": "0.1.12-dev.0",
4
+ "description": "Connect local agent harnesses to Ticlawk, Telegram, and other mobile clients.",
5
+ "type": "module",
6
+ "main": "ticlawk.mjs",
7
+ "exports": {
8
+ ".": "./ticlawk.mjs",
9
+ "./package.json": "./package.json"
10
+ },
11
+ "bin": {
12
+ "ticlawk": "bin/ticlawk.mjs",
13
+ "agent-freeway": "bin/agent-freeway.mjs"
14
+ },
15
+ "files": [
16
+ "assets/",
17
+ "bin/",
18
+ "scripts/postinstall.mjs",
19
+ "src/",
20
+ "cc-watcher.mjs",
21
+ "ticlawk.mjs",
22
+ "agent-freeway.mjs",
23
+ "README.md",
24
+ "LICENSE"
25
+ ],
26
+ "publishConfig": {
27
+ "access": "public"
28
+ },
29
+ "engines": {
30
+ "node": ">=20"
31
+ },
32
+ "scripts": {
33
+ "postinstall": "node scripts/postinstall.mjs",
34
+ "start": "node ./bin/ticlawk.mjs start",
35
+ "health": "node ./bin/ticlawk.mjs health",
36
+ "dev": "echo 'Configure ~/.ticlawk/.config, then: npm run start'",
37
+ "generate:usage-docs": "node scripts/generate-usage-docs.mjs",
38
+ "verify:public-package": "bash scripts/verify-ticlawk-public.sh"
39
+ },
40
+ "repository": {
41
+ "type": "git",
42
+ "url": "git+https://github.com/darthjaja6/ticlawk.git"
43
+ },
44
+ "keywords": [
45
+ "ticlawk",
46
+ "claude-code",
47
+ "claude",
48
+ "anthropic",
49
+ "openclaw",
50
+ "codex",
51
+ "agent",
52
+ "ai-agent",
53
+ "telegram",
54
+ "telegram-bot",
55
+ "chatops",
56
+ "remote-agent",
57
+ "mobile",
58
+ "bridge",
59
+ "gateway"
60
+ ],
61
+ "author": "darthjaja6",
62
+ "license": "ISC",
63
+ "bugs": {
64
+ "url": "https://github.com/darthjaja6/ticlawk/issues"
65
+ },
66
+ "homepage": "https://github.com/darthjaja6/ticlawk#readme",
67
+ "dependencies": {
68
+ "dotenv": "^17.4.2",
69
+ "qrcode-terminal": "^0.12.0",
70
+ "ws": "^8.20.0"
71
+ }
72
+ }