tokenmix 0.2.2 → 0.3.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 (42) hide show
  1. package/README.md +11 -2
  2. package/dist/agents/aider.js +24 -3
  3. package/dist/agents/aider.js.map +1 -1
  4. package/dist/agents/claude.js +59 -4
  5. package/dist/agents/claude.js.map +1 -1
  6. package/dist/agents/kilo.js +2 -0
  7. package/dist/agents/kilo.js.map +1 -1
  8. package/dist/agents/opencode.js +29 -0
  9. package/dist/agents/opencode.js.map +1 -1
  10. package/dist/api/client.js +12 -6
  11. package/dist/api/client.js.map +1 -1
  12. package/dist/cli.js +5 -55
  13. package/dist/cli.js.map +1 -1
  14. package/dist/commands/agent-runner.js +60 -23
  15. package/dist/commands/agent-runner.js.map +1 -1
  16. package/dist/commands/balance.js +5 -4
  17. package/dist/commands/balance.js.map +1 -1
  18. package/dist/commands/doctor.js +11 -10
  19. package/dist/commands/doctor.js.map +1 -1
  20. package/dist/commands/list.js +19 -9
  21. package/dist/commands/list.js.map +1 -1
  22. package/dist/commands/login.js +24 -20
  23. package/dist/commands/login.js.map +1 -1
  24. package/dist/commands/logout.js +21 -1
  25. package/dist/commands/logout.js.map +1 -1
  26. package/dist/commands/models.js +24 -12
  27. package/dist/commands/models.js.map +1 -1
  28. package/dist/commands/topup.js +4 -3
  29. package/dist/commands/topup.js.map +1 -1
  30. package/dist/config/store.js +1 -1
  31. package/dist/config/store.js.map +1 -1
  32. package/dist/i18n/index.js +33 -0
  33. package/dist/i18n/index.js.map +1 -0
  34. package/dist/i18n/messages.js +156 -0
  35. package/dist/i18n/messages.js.map +1 -0
  36. package/dist/program.js +61 -0
  37. package/dist/program.js.map +1 -0
  38. package/dist/utils/browser.js +12 -0
  39. package/dist/utils/browser.js.map +1 -1
  40. package/dist/utils/prompt.js +3 -2
  41. package/dist/utils/prompt.js.map +1 -1
  42. package/package.json +17 -8
@@ -0,0 +1,61 @@
1
+ import { createRequire } from 'node:module';
2
+ import { Command } from 'commander';
3
+ import { loginCommand } from './commands/login.js';
4
+ import { logoutCommand } from './commands/logout.js';
5
+ import { balanceCommand } from './commands/balance.js';
6
+ import { topupCommand } from './commands/topup.js';
7
+ import { modelsCommand } from './commands/models.js';
8
+ import { listCommand } from './commands/list.js';
9
+ import { doctorCommand } from './commands/doctor.js';
10
+ import { registerAgentCommands } from './commands/agent-runner.js';
11
+ // Read version from package.json so we never have to bump it in two places.
12
+ const pkg = createRequire(import.meta.url)('../package.json');
13
+ // Build the fully-wired commander program WITHOUT parsing argv.
14
+ // Keeping construction separate from execution makes the CLI unit-testable.
15
+ export function buildProgram(deps = {}) {
16
+ const program = new Command();
17
+ // Required so that agent subcommands can use passThroughOptions() to forward
18
+ // --version / --help / --any to the underlying agent binary instead of having
19
+ // tokenmix consume them.
20
+ program.enablePositionalOptions();
21
+ program
22
+ .name('tokenmix')
23
+ .description('Zero-config CLI to use any open-source coding agent with TokenMix as the unified LLM backend.')
24
+ .version(pkg.version);
25
+ program
26
+ .command('login')
27
+ .description('Log in to TokenMix (default: browser device authorization)')
28
+ .option('-k, --key <apiKey>', 'Paste an API key directly (skip browser flow, useful in CI)')
29
+ .option('-p, --paste', 'Force interactive paste prompt instead of browser flow')
30
+ .option('-u, --url <baseUrl>', 'Override API base URL (default: https://api.tokenmix.ai)')
31
+ .action(loginCommand);
32
+ program
33
+ .command('logout')
34
+ .description('Remove stored credentials from this machine')
35
+ .action(logoutCommand);
36
+ program
37
+ .command('balance')
38
+ .description('Open the dashboard to view your balance')
39
+ .action(balanceCommand);
40
+ program
41
+ .command('topup')
42
+ .description('Open the browser to top up your account')
43
+ .action(topupCommand);
44
+ program
45
+ .command('models')
46
+ .description('List available models with prices')
47
+ .option('-t, --type <type>', 'Filter by type: chat | embedding | image | audio | video')
48
+ .action(modelsCommand);
49
+ program
50
+ .command('list')
51
+ .description('List supported coding agents')
52
+ .action(listCommand);
53
+ program
54
+ .command('doctor')
55
+ .description('Diagnose CLI configuration and agent installation')
56
+ .action(doctorCommand);
57
+ // Register one subcommand per supported agent (opencode, claude, aider, kilo, ...).
58
+ registerAgentCommands(program, deps.runAgent);
59
+ return program;
60
+ }
61
+ //# sourceMappingURL=program.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"program.js","sourceRoot":"","sources":["../src/program.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAC3C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AACpD,OAAO,EAAE,qBAAqB,EAAe,MAAM,4BAA4B,CAAA;AAE/E,4EAA4E;AAC5E,MAAM,GAAG,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,iBAAiB,CAAwB,CAAA;AAOpF,gEAAgE;AAChE,4EAA4E;AAC5E,MAAM,UAAU,YAAY,CAAC,OAAoB,EAAE;IACjD,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAA;IAE7B,6EAA6E;IAC7E,8EAA8E;IAC9E,yBAAyB;IACzB,OAAO,CAAC,uBAAuB,EAAE,CAAA;IAEjC,OAAO;SACJ,IAAI,CAAC,UAAU,CAAC;SAChB,WAAW,CAAC,+FAA+F,CAAC;SAC5G,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;IAEvB,OAAO;SACJ,OAAO,CAAC,OAAO,CAAC;SAChB,WAAW,CAAC,4DAA4D,CAAC;SACzE,MAAM,CAAC,oBAAoB,EAAE,6DAA6D,CAAC;SAC3F,MAAM,CAAC,aAAa,EAAE,wDAAwD,CAAC;SAC/E,MAAM,CAAC,qBAAqB,EAAE,0DAA0D,CAAC;SACzF,MAAM,CAAC,YAAY,CAAC,CAAA;IAEvB,OAAO;SACJ,OAAO,CAAC,QAAQ,CAAC;SACjB,WAAW,CAAC,6CAA6C,CAAC;SAC1D,MAAM,CAAC,aAAa,CAAC,CAAA;IAExB,OAAO;SACJ,OAAO,CAAC,SAAS,CAAC;SAClB,WAAW,CAAC,yCAAyC,CAAC;SACtD,MAAM,CAAC,cAAc,CAAC,CAAA;IAEzB,OAAO;SACJ,OAAO,CAAC,OAAO,CAAC;SAChB,WAAW,CAAC,yCAAyC,CAAC;SACtD,MAAM,CAAC,YAAY,CAAC,CAAA;IAEvB,OAAO;SACJ,OAAO,CAAC,QAAQ,CAAC;SACjB,WAAW,CAAC,mCAAmC,CAAC;SAChD,MAAM,CAAC,mBAAmB,EAAE,0DAA0D,CAAC;SACvF,MAAM,CAAC,aAAa,CAAC,CAAA;IAExB,OAAO;SACJ,OAAO,CAAC,MAAM,CAAC;SACf,WAAW,CAAC,8BAA8B,CAAC;SAC3C,MAAM,CAAC,WAAW,CAAC,CAAA;IAEtB,OAAO;SACJ,OAAO,CAAC,QAAQ,CAAC;SACjB,WAAW,CAAC,mDAAmD,CAAC;SAChE,MAAM,CAAC,aAAa,CAAC,CAAA;IAExB,oFAAoF;IACpF,qBAAqB,CAAC,OAAO,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAA;IAE7C,OAAO,OAAO,CAAA;AAChB,CAAC"}
@@ -1,5 +1,17 @@
1
1
  import open from 'open';
2
+ import { logger } from './logger.js';
3
+ import { t } from '../i18n/index.js';
2
4
  export async function openInBrowser(url) {
3
5
  await open(url);
4
6
  }
7
+ // Try to open the browser; on failure (headless / SSH / no desktop environment),
8
+ // print the URL so the user can open it manually instead of crashing.
9
+ export async function openOrHint(url) {
10
+ try {
11
+ await open(url);
12
+ }
13
+ catch {
14
+ logger.info(t('browser.manual', { url }));
15
+ }
16
+ }
5
17
  //# sourceMappingURL=browser.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"browser.js","sourceRoot":"","sources":["../../src/utils/browser.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,MAAM,CAAA;AAEvB,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,GAAW;IAC7C,MAAM,IAAI,CAAC,GAAG,CAAC,CAAA;AACjB,CAAC"}
1
+ {"version":3,"file":"browser.js","sourceRoot":"","sources":["../../src/utils/browser.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,MAAM,CAAA;AACvB,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACpC,OAAO,EAAE,CAAC,EAAE,MAAM,kBAAkB,CAAA;AAEpC,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,GAAW;IAC7C,MAAM,IAAI,CAAC,GAAG,CAAC,CAAA;AACjB,CAAC;AAED,iFAAiF;AACjF,sEAAsE;AACtE,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,GAAW;IAC1C,IAAI,CAAC;QACH,MAAM,IAAI,CAAC,GAAG,CAAC,CAAA;IACjB,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,gBAAgB,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC,CAAA;IAC3C,CAAC;AACH,CAAC"}
@@ -1,10 +1,11 @@
1
1
  import prompts from 'prompts';
2
+ import { t } from '../i18n/index.js';
2
3
  export async function promptApiKey() {
3
4
  const r = await prompts({
4
5
  type: 'password',
5
6
  name: 'apiKey',
6
- message: 'Paste your TokenMix API key (sk-tm-...)',
7
- validate: (v) => v && v.startsWith('sk-tm-') ? true : 'API key should start with sk-tm-',
7
+ message: t('prompt.pasteKey'),
8
+ validate: (v) => v && v.startsWith('sk-tm-') ? true : t('login.keyMustStart'),
8
9
  });
9
10
  const key = r.apiKey?.trim();
10
11
  return key || null;
@@ -1 +1 @@
1
- {"version":3,"file":"prompt.js","sourceRoot":"","sources":["../../src/utils/prompt.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,SAAS,CAAA;AAE7B,MAAM,CAAC,KAAK,UAAU,YAAY;IAChC,MAAM,CAAC,GAAG,MAAM,OAAO,CAAC;QACtB,IAAI,EAAE,UAAU;QAChB,IAAI,EAAE,QAAQ;QACd,OAAO,EAAE,yCAAyC;QAClD,QAAQ,EAAE,CAAC,CAAS,EAAE,EAAE,CACtB,CAAC,IAAI,CAAC,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,kCAAkC;KAC1E,CAAC,CAAA;IACF,MAAM,GAAG,GAAI,CAAC,CAAC,MAA6B,EAAE,IAAI,EAAE,CAAA;IACpD,OAAO,GAAG,IAAI,IAAI,CAAA;AACpB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,OAAe,EAAE,UAAmB,IAAI;IACpE,MAAM,CAAC,GAAG,MAAM,OAAO,CAAC;QACtB,IAAI,EAAE,SAAS;QACf,IAAI,EAAE,IAAI;QACV,OAAO;QACP,OAAO;KACR,CAAC,CAAA;IACF,OAAO,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAA;AACtB,CAAC;AAQD,MAAM,CAAC,KAAK,UAAU,MAAM,CAC1B,OAAe,EACf,OAA0B;IAE1B,MAAM,CAAC,GAAG,MAAM,OAAO,CAAC;QACtB,IAAI,EAAE,QAAQ;QACd,IAAI,EAAE,OAAO;QACb,OAAO;QACP,OAAO;KACR,CAAC,CAAA;IACF,OAAQ,CAAC,CAAC,KAAW,IAAI,IAAI,CAAA;AAC/B,CAAC"}
1
+ {"version":3,"file":"prompt.js","sourceRoot":"","sources":["../../src/utils/prompt.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,SAAS,CAAA;AAC7B,OAAO,EAAE,CAAC,EAAE,MAAM,kBAAkB,CAAA;AAEpC,MAAM,CAAC,KAAK,UAAU,YAAY;IAChC,MAAM,CAAC,GAAG,MAAM,OAAO,CAAC;QACtB,IAAI,EAAE,UAAU;QAChB,IAAI,EAAE,QAAQ;QACd,OAAO,EAAE,CAAC,CAAC,iBAAiB,CAAC;QAC7B,QAAQ,EAAE,CAAC,CAAS,EAAE,EAAE,CACtB,CAAC,IAAI,CAAC,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,oBAAoB,CAAC;KAC/D,CAAC,CAAA;IACF,MAAM,GAAG,GAAI,CAAC,CAAC,MAA6B,EAAE,IAAI,EAAE,CAAA;IACpD,OAAO,GAAG,IAAI,IAAI,CAAA;AACpB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,OAAe,EAAE,UAAmB,IAAI;IACpE,MAAM,CAAC,GAAG,MAAM,OAAO,CAAC;QACtB,IAAI,EAAE,SAAS;QACf,IAAI,EAAE,IAAI;QACV,OAAO;QACP,OAAO;KACR,CAAC,CAAA;IACF,OAAO,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAA;AACtB,CAAC;AAQD,MAAM,CAAC,KAAK,UAAU,MAAM,CAC1B,OAAe,EACf,OAA0B;IAE1B,MAAM,CAAC,GAAG,MAAM,OAAO,CAAC;QACtB,IAAI,EAAE,QAAQ;QACd,IAAI,EAAE,OAAO;QACb,OAAO;QACP,OAAO;KACR,CAAC,CAAA;IACF,OAAQ,CAAC,CAAC,KAAW,IAAI,IAAI,CAAA;AAC/B,CAAC"}
package/package.json CHANGED
@@ -1,11 +1,20 @@
1
1
  {
2
2
  "name": "tokenmix",
3
- "version": "0.2.2",
3
+ "version": "0.3.0",
4
4
  "description": "Zero-config CLI to use any open-source coding agent with TokenMix as the unified LLM backend.",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "tokenmix": "./bin/tokenmix.js"
8
8
  },
9
+ "scripts": {
10
+ "build": "tsc",
11
+ "dev": "tsx src/cli.ts",
12
+ "start": "node bin/tokenmix.js",
13
+ "typecheck": "tsc --noEmit",
14
+ "test": "vitest run",
15
+ "test:watch": "vitest",
16
+ "prepublishOnly": "pnpm build"
17
+ },
9
18
  "engines": {
10
19
  "node": ">=18"
11
20
  },
@@ -48,12 +57,12 @@
48
57
  "@types/prompts": "^2.4.9",
49
58
  "@types/which": "^3.0.4",
50
59
  "tsx": "^4.19.2",
51
- "typescript": "^5.6.3"
60
+ "typescript": "^5.6.3",
61
+ "vitest": "^4.1.7"
52
62
  },
53
- "scripts": {
54
- "build": "tsc",
55
- "dev": "tsx src/cli.ts",
56
- "start": "node bin/tokenmix.js",
57
- "typecheck": "tsc --noEmit"
63
+ "pnpm": {
64
+ "onlyBuiltDependencies": [
65
+ "esbuild"
66
+ ]
58
67
  }
59
- }
68
+ }