@atmorouter/helper 0.2.0 → 0.2.2

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
@@ -5,14 +5,14 @@ Configure coding agents for AtmoRouter, get IDE setup instructions, discover mod
5
5
  Requires Node.js 22 or newer. The public npm package uses the `yaml` runtime dependency to safely parse and preserve YAML configuration. No npm account or repository access is required.
6
6
 
7
7
  ```sh
8
- npx @atmorouter/helper@0.2.0 --help
9
- npx @atmorouter/helper@0.2.0 targets
10
- npx @atmorouter/helper@0.2.0 models --search claude
11
- npx @atmorouter/helper@0.2.0 configure --target opencode --model YOUR_MODEL_ID
12
- npx @atmorouter/helper@0.2.0 configure --target claude --model YOUR_MODEL_ID --write
8
+ npx @atmorouter/helper@0.2.2 --help
9
+ npx @atmorouter/helper@0.2.2 targets
10
+ npx @atmorouter/helper@0.2.2 models --search claude
11
+ npx @atmorouter/helper@0.2.2 configure --target opencode --model YOUR_MODEL_ID
12
+ npx @atmorouter/helper@0.2.2 configure --target claude --model YOUR_MODEL_ID --write
13
13
  ```
14
14
 
15
- The same version is available as `https://atmorouter.dev/downloads/atmorouter-helper-0.2.0.tgz`, with a `.sha256` checksum alongside it. Run it with `npx https://atmorouter.dev/downloads/atmorouter-helper-0.2.0.tgz --help`.
15
+ The same version is available as `https://atmorouter.dev/downloads/atmorouter-helper-0.2.2.tgz`, with a `.sha256` checksum alongside it. Run it with `npx https://atmorouter.dev/downloads/atmorouter-helper-0.2.2.tgz --help`.
16
16
 
17
17
  With no command, the interactive wizard searches live text models and previews the selected setup. `configure` is preview-only unless `--write` is supplied. Non-interactive file writes additionally require `--yes`. Tests use temporary `--config-dir` folders, never real agent settings.
18
18
 
@@ -42,10 +42,10 @@ The helper never saves or prints your API key. Set `ATMOROUTER_API_KEY` privatel
42
42
 
43
43
  ```sh
44
44
  export ANTHROPIC_AUTH_TOKEN="$ATMOROUTER_API_KEY"
45
- npx @atmorouter/helper@0.2.0 check-key
45
+ npx @atmorouter/helper@0.2.2 check-key
46
46
  ```
47
47
 
48
- `GET /v1/models` is public and **cannot validate a key**. The optional explicit key check sends an empty JSON body to `/v1/chat/completions`. Only HTTP 400 with `model is required` proves the gateway accepted the credential before rejecting the body. No model is selected, no inference is forwarded, and nothing is billed. The check consumes a rate-limit slot. HTTP 401 rejects the key; 429 and all other responses are inconclusive. Requests have a 15-second timeout and refuse redirects. No custom upstream origin can receive your key.
48
+ `GET /v1/models` is public and **cannot validate a key**. The optional explicit key check sends an empty JSON body to `/v1/chat/completions`. Only HTTP 400 with `model is required` proves the gateway accepted the credential before rejecting the body. No model is selected, no inference is forwarded, and nothing is billed. The check consumes a rate-limit slot. HTTP 401 rejects the key; 429 and all other responses are inconclusive. The key-check request has a 15-second timeout and refuse redirects. Catalog discovery has a 30-second timeout. No custom upstream origin can receive your key.
49
49
 
50
50
  ## Codex local bridge
51
51
 
@@ -53,13 +53,13 @@ The public gateway implements Chat Completions and Anthropic Messages, not `/v1/
53
53
 
54
54
  ```sh
55
55
  # Prints instructions only; does not start a server or write Codex settings.
56
- npx @atmorouter/helper@0.2.0 configure --target codex --model YOUR_MODEL_ID
56
+ npx @atmorouter/helper@0.2.2 configure --target codex --model YOUR_MODEL_ID
57
57
 
58
58
  # Starts a temporary local bridge and launches your installed Codex CLI.
59
- npx @atmorouter/helper@0.2.0 codex --model YOUR_MODEL_ID
59
+ npx @atmorouter/helper@0.2.2 codex --model YOUR_MODEL_ID
60
60
 
61
61
  # Or run the bridge separately and follow its printed client instructions.
62
- npx @atmorouter/helper@0.2.0 bridge --port 43187
62
+ npx @atmorouter/helper@0.2.2 bridge --port 43187
63
63
  ```
64
64
 
65
65
  Set `ATMOROUTER_API_KEY` in the process environment before starting the bridge. It listens on loopback only, authenticates local requests, and forwards inference to the official AtmoRouter endpoint. The launcher preserves Codex's permission defaults. It does not weaken approvals or sandbox settings.
@@ -5,9 +5,14 @@ import {readFile} from 'node:fs/promises';
5
5
  import fs from 'node:fs';
6
6
  import path from 'node:path';
7
7
  import {spawn} from 'node:child_process';
8
+ import {setDefaultResultOrder} from 'node:dns';
8
9
  import {models,modelId,checkKey,planConfiguration,writeConfiguration,environment,INTEGRATIONS,guidedConfiguration} from '../lib/helper.mjs';
9
10
  import {startResponsesBridge} from '../lib/bridge.mjs';
10
11
 
12
+ // Prefer IPv4 when both families are advertised; IPv6-only DNS still works.
13
+ // This affects this CLI process only, including the bridge's outbound requests.
14
+ setDefaultResultOrder('ipv4first');
15
+
11
16
  const HELP=`AtmoRouter helper
12
17
  Node.js 22+.
13
18
 
@@ -137,7 +142,7 @@ async function main(){
137
142
  }
138
143
  main().catch(error=>{
139
144
  let message=String(error?.message || 'Operation failed.');
140
- if(error?.code?.startsWith('ERR_PARSE_ARGS'))message='Unknown or unsupported command options. Do not pass API keys as arguments. Run --help.';
145
+ if(typeof error?.code==='string'&&error.code.startsWith('ERR_PARSE_ARGS'))message='Unknown or unsupported command options. Do not pass API keys as arguments. Run --help.';
141
146
  else if(error instanceof SyntaxError)message='Unexpected catalog JSON. Try again later.';
142
147
  else if(error instanceof TypeError || error?.name==='TimeoutError')message='Network operation failed. Check connectivity and retry.';
143
148
  if(process.env.ATMOROUTER_API_KEY)message=message.split(process.env.ATMOROUTER_API_KEY).join('[redacted]');
package/lib/helper.mjs CHANGED
@@ -12,11 +12,11 @@ export function modelId(value) {
12
12
  return value;
13
13
  }
14
14
  export async function models(fetcher = fetch) {
15
- const response = await fetcher(ORIGIN+'/v1/models', {redirect:'error',signal:AbortSignal.timeout(15000)});
15
+ const response = await fetcher(ORIGIN+'/v1/models', {redirect:'error',signal:AbortSignal.timeout(30000)});
16
16
  if (!response.ok) throw Error('Catalog request failed: HTTP '+response.status);
17
17
  const body = await response.json();
18
18
  if (!Array.isArray(body.data)) throw Error('Unexpected catalog response.');
19
- return body.data.filter(m => typeof m.id === 'string' && (!m.modality || ['text','chat','multimodal'].includes(m.modality.toLowerCase()))).map(m => ({...m,id:modelId(m.id)}));
19
+ return body.data.filter(m => typeof m.id === 'string' && (!m.modality || (typeof m.modality==='string' && m.modality.toLowerCase().split(/[,\s+/]+/).some(part=>['text','chat','multimodal'].includes(part))))).map(m => ({...m,id:modelId(m.id)}));
20
20
  }
21
21
  export async function checkKey(key, fetcher = fetch) {
22
22
  if (typeof key!=='string' || key.length!==51 || !/^ar-[a-f0-9]{48}$/.test(key)) throw Error('Set ATMOROUTER_API_KEY to your full ar- key. Do not pass secrets as command arguments.');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atmorouter/helper",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "description": "Configure AtmoRouter coding agents, guide IDE setup, and run a local Codex bridge",
5
5
  "homepage": "https://atmorouter.dev/docs/helper",
6
6
  "keywords": [