ticlawk 0.1.15-dev.4 → 0.1.15-dev.6

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.md CHANGED
@@ -321,11 +321,6 @@ Usage:
321
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
322
  ticlawk auth <adapter> [adapter-auth-args...]
323
323
  ticlawk connect
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
324
  ticlawk profile list
330
325
  ticlawk profile current
331
326
  ticlawk profile use ticlawk:<user-id>
@@ -359,15 +354,7 @@ Config examples:
359
354
 
360
355
  Examples:
361
356
  ticlawk connect
362
- ticlawk connect --type codex --workdir /path/to/project
363
- ticlawk connect --type openclaw --agent-id main
364
357
  ticlawk auth telegram --bot-token <bot-token>
365
- ticlawk connect --adapter telegram --workdir /path/to/project
366
- ticlawk connect --adapter telegram --session-id <claude-session-id>
367
- ticlawk connect --adapter telegram --type codex --workdir /path/to/project
368
- ticlawk connect --adapter telegram --type openclaw --agent-id main
369
- ticlawk connect --adapter telegram --type opencode --workdir /path/to/project
370
- ticlawk connect --adapter telegram --type pi --workdir /path/to/project
371
358
  ```
372
359
  <!-- usage:end -->
373
360
 
package/bin/ticlawk.mjs CHANGED
@@ -1,7 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  import { request } from 'node:http';
4
- import { resolve } from 'node:path';
5
4
  import { installProcessDiagnostics } from '../src/core/diagnostics.mjs';
6
5
  import {
7
6
  AF_ADAPTER_KEY,
@@ -9,11 +8,9 @@ import {
9
8
  loadPersistentConfig,
10
9
  getStreamingConfigView,
11
10
  normalizeAdapterConfigTarget,
12
- normalizeAdapterName,
13
11
  normalizeRuntimeConfigTarget,
14
12
  normalizeStreamingTarget,
15
13
  persistConfig,
16
- SUPPORTED_ADAPTERS,
17
14
  TICLAWK_CONNECTOR_API_KEY,
18
15
  TICLAWK_CONNECTOR_WS_URL,
19
16
  } from '../src/core/config.mjs';
@@ -27,10 +24,7 @@ import { getAdapterAuthHelp, runAdapterAuth } from '../src/core/adapter-registry
27
24
  import { runTiclawkConnect } from '../src/core/ticlawk-control.mjs';
28
25
  import {
29
26
  RUNTIME_DEFINITIONS,
30
- getRuntimeDefinition,
31
- getRuntimeDisplayName,
32
27
  getRuntimeExecutableDefinitions,
33
- normalizeServiceType,
34
28
  } from '../src/core/runtime-registry.mjs';
35
29
  import { runSelfUpdate, readPkgVersion } from '../src/core/update.mjs';
36
30
  import { getUninstallHelp, runSelfUninstall } from '../src/core/uninstall.mjs';
@@ -44,40 +38,12 @@ function getConfigKeyUsage() {
44
38
  return ['adapter', 'streaming...', ...runtimeKeys, 'telegram.bot-token', 'ticlawk.connector-api-key', 'ticlawk.api-url', 'ticlawk.connector-ws-url'].join('|');
45
39
  }
46
40
 
47
- function getRuntimeConnectUsageLines() {
48
- return RUNTIME_DEFINITIONS
49
- .filter((runtime) => !runtime.aliases.includes(''))
50
- .map((runtime) => {
51
- if (runtime.connect?.locator === 'agentId') {
52
- return ` ticlawk connect [--adapter <adapter>] --type ${runtime.name} --agent-id <id> [--name <name>] [--runtime-path <path>] [--switch-user]`;
53
- }
54
- return ` ticlawk connect [--adapter <adapter>] --type ${runtime.name} [--session-id <id>] [--workdir <dir>] [--name <name>] [--runtime-path <path>] [--switch-user]`;
55
- })
56
- .join('\n');
57
- }
58
-
59
41
  function getRuntimeConfigExamples() {
60
42
  return getRuntimeExecutableDefinitions()
61
43
  .map((runtime) => ` ticlawk config set ${runtime.executableCliKey} /path/to/${runtime.name} # advanced/manual`)
62
44
  .join('\n');
63
45
  }
64
46
 
65
- function getRuntimeConnectExamples() {
66
- return [
67
- ' ticlawk connect --adapter telegram --workdir /path/to/project',
68
- ' ticlawk connect --adapter telegram --session-id <claude-session-id>',
69
- ...RUNTIME_DEFINITIONS
70
- .filter((runtime) => !runtime.aliases.includes(''))
71
- .slice(0, 4)
72
- .map((runtime) => {
73
- if (runtime.connect?.locator === 'agentId') {
74
- return ` ticlawk connect --adapter telegram --type ${runtime.name} --agent-id main`;
75
- }
76
- return ` ticlawk connect --adapter telegram --type ${runtime.name} --workdir /path/to/project`;
77
- }),
78
- ].join('\n');
79
- }
80
-
81
47
  function getUsageText() {
82
48
  const configKeys = getConfigKeyUsage();
83
49
  return `ticlawk
@@ -92,8 +58,6 @@ Usage:
92
58
  ticlawk config set <${configKeys}> <value>
93
59
  ticlawk auth <adapter> [adapter-auth-args...]
94
60
  ticlawk connect
95
- ticlawk connect [--adapter <adapter>] [--session-id <id>] [--workdir <dir>] [--switch-user]
96
- ${getRuntimeConnectUsageLines()}
97
61
  ticlawk profile list
98
62
  ticlawk profile current
99
63
  ticlawk profile use ticlawk:<user-id>
@@ -124,10 +88,7 @@ ${getRuntimeConfigExamples()}
124
88
 
125
89
  Examples:
126
90
  ticlawk connect
127
- ticlawk connect --type codex --workdir /path/to/project
128
- ticlawk connect --type openclaw --agent-id main
129
91
  ticlawk auth telegram --bot-token <bot-token>
130
- ${getRuntimeConnectExamples()}
131
92
  `;
132
93
  }
133
94
 
@@ -153,14 +114,10 @@ Use \`connect\` to connect the selected adapter to a local runtime.
153
114
  For ticlawk, connect starts the QR pairing flow when no local credential exists.
154
115
  Run \`ticlawk connect\` from a project directory to auto-detect
155
116
  Codex, Claude Code, opencode, and pi, then choose the runtime in ticlawk.
156
- By default connect records the runtime binary found in your current terminal.
157
- Use \`--runtime-path <path>\` only when you need to override that discovery.
117
+ No pairing QR code is shown when no local agent harness is detected.
158
118
 
159
119
  Examples:
160
120
  ticlawk connect
161
- ticlawk connect --type codex --workdir /path/to/project
162
- ticlawk connect --type openclaw --agent-id main
163
- ${getRuntimeConnectExamples()}
164
121
  `;
165
122
  }
166
123
 
@@ -260,84 +217,35 @@ function formatSecretConfigValue(configKey, value) {
260
217
  return value || '';
261
218
  }
262
219
 
263
- function requireAdapter(value) {
264
- const adapterId = normalizeAdapterName(value);
265
- if (!adapterId) {
266
- const supported = SUPPORTED_ADAPTERS.join(', ');
267
- console.error(`invalid adapter: ${value || ''} (supported: ${supported})`);
268
- process.exit(1);
269
- }
270
- return adapterId;
271
- }
272
-
273
- function getConnectAdapter(value) {
274
- if (value === undefined || value === null || value === '') {
275
- return getConfiguredAdapter();
276
- }
277
- return requireAdapter(value);
278
- }
279
-
280
220
  function buildConnectPayload(args) {
221
+ const legacyArgs = [
222
+ 'adapter',
223
+ 'type',
224
+ 'session-id',
225
+ 'workdir',
226
+ 'cwd',
227
+ 'project-dir',
228
+ 'agent-id',
229
+ 'runtime-path',
230
+ 'code',
231
+ ].filter((key) => args[key] !== undefined);
281
232
  const positionalRuntime = args._?.[1];
282
- const serviceType = normalizeServiceType(args.type || positionalRuntime);
283
- const explicitWorkdir = args.workdir || args.cwd || args['project-dir'];
284
- const workdir = explicitWorkdir ? resolve(explicitWorkdir) : process.cwd();
285
- const hasExplicitAdapter = Boolean(args.adapter);
286
- const adapter = (!serviceType && !hasExplicitAdapter)
287
- ? 'ticlawk'
288
- : getConnectAdapter(args.adapter);
289
- if (!serviceType) {
290
- if (adapter === 'ticlawk' && !args.type && !positionalRuntime) {
291
- return {
292
- adapter,
293
- autoRuntime: true,
294
- switchUser: Boolean(args['switch-user']),
295
- workdir,
296
- ...(args.name ? { name: args.name } : {}),
297
- };
298
- }
299
- console.error(`invalid runtime type: ${args.type || positionalRuntime || ''}`);
233
+ if (positionalRuntime || legacyArgs.length > 0) {
234
+ const suffix = positionalRuntime ? ` ${positionalRuntime}` : '';
235
+ console.error(`ticlawk connect${suffix} no longer accepts explicit runtime, adapter, session, or workdir arguments.`);
236
+ console.error('Run `ticlawk connect` from the directory you want to offer to local agent harnesses.');
237
+ console.error('Ticlawk will detect Codex, Claude Code, opencode, and pi locally, then let you choose in the app.');
300
238
  process.exit(1);
301
239
  }
302
-
303
- const runtimeDefinition = getRuntimeDefinition(serviceType);
304
- if (runtimeDefinition?.connect?.locator === 'agentId') {
305
- return {
306
- adapter,
307
- serviceType,
308
- agentId: args['agent-id'],
309
- ...(explicitWorkdir ? { workdir } : {}),
310
- ...(args['runtime-path'] ? { runtimePath: resolve(args['runtime-path']) } : {}),
311
- name: args.name || args['agent-id'],
312
- switchUser: Boolean(args['switch-user']),
313
- };
314
- }
315
-
316
240
  return {
317
- adapter,
318
- serviceType,
319
- sessionId: args['session-id'],
241
+ adapter: 'ticlawk',
242
+ autoRuntime: true,
320
243
  switchUser: Boolean(args['switch-user']),
321
- workdir,
244
+ workdir: process.cwd(),
322
245
  ...(args.name ? { name: args.name } : {}),
323
- ...(args['runtime-path'] ? { runtimePath: resolve(args['runtime-path']) } : {}),
324
246
  };
325
247
  }
326
248
 
327
- function validateConnectPayload(payload) {
328
- if (payload.autoRuntime) return;
329
- const runtimeDefinition = getRuntimeDefinition(payload.serviceType);
330
- if (runtimeDefinition?.connect?.locator === 'agentId' && !payload.agentId) {
331
- console.error(`--agent-id is required for ${getRuntimeDisplayName(payload.serviceType)} connect`);
332
- process.exit(1);
333
- }
334
- if (runtimeDefinition?.connect?.locator !== 'agentId' && !payload.sessionId && !payload.workdir) {
335
- const runtimeName = getRuntimeDisplayName(payload.serviceType);
336
- console.error(`either --session-id or --workdir is required for ${runtimeName} connect`);
337
- process.exit(1);
338
- }
339
- }
340
-
341
249
  function printCommandResult(result) {
342
250
  if (result?.body?.help) {
343
251
  console.log(result.body.help);
@@ -570,7 +478,6 @@ async function main() {
570
478
  return;
571
479
  }
572
480
  const payload = buildConnectPayload(args);
573
- validateConnectPayload(payload);
574
481
  const res = await runTiclawkConnect(payload);
575
482
  printCommandResult(res);
576
483
  if (res.statusCode < 400) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ticlawk",
3
- "version": "0.1.15-dev.4",
3
+ "version": "0.1.15-dev.6",
4
4
  "description": "Connect local agent harnesses to Ticlawk, Telegram, and other mobile clients.",
5
5
  "type": "module",
6
6
  "main": "ticlawk.mjs",
@@ -192,6 +192,19 @@ function runtimeLabel(runtime) {
192
192
  return runtime || 'Agent';
193
193
  }
194
194
 
195
+ function printDetectedRuntimeOptions(runtimeOptions = []) {
196
+ console.log('Detected agent harness:');
197
+ if (!runtimeOptions.length) {
198
+ console.log(' none');
199
+ return;
200
+ }
201
+ for (const option of runtimeOptions) {
202
+ const label = option.runtime_label || runtimeLabel(option.runtime);
203
+ const workdir = option.workdir ? ` (${option.workdir})` : '';
204
+ console.log(` - ${label}${workdir}`);
205
+ }
206
+ }
207
+
195
208
  async function buildAutoRuntimeOptions(ctx, payload = {}) {
196
209
  const workdir = getRuntimeWorkdir(payload) || process.cwd();
197
210
  const candidates = ['codex', 'claude_code', 'opencode', 'pi'];
@@ -875,8 +888,11 @@ export function createTiclawkAdapter(ctx) {
875
888
  async function connectWithQrPairing(payload) {
876
889
  const autoRuntime = Boolean(payload?.autoRuntime);
877
890
  const runtimeOptions = autoRuntime ? await buildAutoRuntimeOptions(ctx, payload) : [];
878
- if (autoRuntime && runtimeOptions.length === 0) {
879
- throw new Error('No supported local agent runtime found in this terminal. Install or sign in to Codex, Claude Code, OpenCode, or pi, then try again.');
891
+ if (autoRuntime) {
892
+ printDetectedRuntimeOptions(runtimeOptions);
893
+ if (runtimeOptions.length === 0) {
894
+ return connectError(400, 'No supported local agent harness detected in this terminal. Install or sign in to Codex, Claude Code, OpenCode, or pi, then run `ticlawk connect` again.');
895
+ }
880
896
  }
881
897
  const resolved = autoRuntime ? null : await ctx.resolveRuntimeBinding(payload);
882
898
  const runtimeMeta = resolved?.runtimeMeta || {};
@@ -996,15 +1012,24 @@ export function createTiclawkAdapter(ctx) {
996
1012
 
997
1013
  async connect(payload) {
998
1014
  const config = loadPersistentConfig();
999
- const connectCode = String(payload?.code || config.TICLAWK_SETUP_CODE || '').trim();
1000
- if (!connectCode) {
1015
+ if (!payload?.__legacyConnect) {
1001
1016
  try {
1002
- return await connectWithQrPairing.call(this, payload);
1017
+ return await connectWithQrPairing.call(this, {
1018
+ ...payload,
1019
+ autoRuntime: true,
1020
+ });
1003
1021
  } catch (err) {
1004
1022
  return connectError(err?.status || 500, err.message);
1005
1023
  }
1006
1024
  }
1007
1025
 
1026
+ // Archived setup-code connect path. It is intentionally not reachable
1027
+ // from the public CLI; keep it here only until the old flow is deleted.
1028
+ const connectCode = String(payload?.code || config.TICLAWK_SETUP_CODE || '').trim();
1029
+ if (!connectCode) {
1030
+ return connectError(400, 'legacy ticlawk setup-code connect requires code');
1031
+ }
1032
+
1008
1033
  try {
1009
1034
  const resolved = await ctx.resolveRuntimeBinding(payload);
1010
1035
  const runtimeMeta = resolved.runtimeMeta;