@coswic/aipay 0.7.2 → 0.8.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # @coswic/aipay
2
2
 
3
+ ## 0.8.0 — 2026-10-09
4
+
5
+ - `aipay test`: a 401 from the API now says that, during the invitation-only beta, the signed-in user may hold no current invitation (or not have accepted the latest Terms) and that refreshing does not help; a sign-in that never reaches the loopback callback prints the same hint next to the timeout.
6
+ - Developer commands: the 401 hint mentions that the developer account itself may not be invited yet, instead of only "run `aipay login` again".
7
+ - `aipay test` picks its default model among the ones the catalog marks available (`aipay.availability`, SDK 0.5.0 type); older servers without the field behave as before.
8
+ - Brand spelling follows the product: "AI Pay" (no hyphen) in the README, help text, messages, scaffolded templates and the generated `aipay-agent.md`; package.json names the provider, Coswic Labs (https://coswic.ai), as author. Command names, env keys and identifiers are unchanged.
9
+ - Requires `@coswic/aipay-sdk` ^0.5.0.
10
+
3
11
  ## 0.7.2 — 2026-10-09
4
12
 
5
13
  - README: describe AI-Pay's invitation-only beta instead of self sign-up seats (only invited users can create an account; public registration is not open; your users must be invited before their first sign-in through your app; production does not accept top-ups at the moment), and explain what `aipay test` and the developer commands do when the user or the developer account is not invited. No behavior change.
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # @coswic/aipay — AI-Pay CLI
1
+ # @coswic/aipay — AI Pay CLI
2
2
 
3
3
  The command-line companion to [`@coswic/aipay-sdk`](https://www.npmjs.com/package/@coswic/aipay-sdk).
4
4
  Made for developers and for the coding agents they hand the Console prompt to.
@@ -16,9 +16,9 @@ npx @coswic/aipay test
16
16
  - **Models and prices**: https://ai-pay.coswic.ai/models?lang=en · **API contract**: https://ai-pay.coswic.ai/openapi.yaml
17
17
  - **Product overview and what is open today**: https://ai-pay.coswic.ai/about?lang=en
18
18
 
19
- AI-Pay's production environment is in a free beta limited to invited users: only invited users can create an account and use the service, public registration is not open, and your users must also be invited before their first sign-in through your app's "Sign in with AI-Pay". Production does not accept top-ups at the moment. `<api base>` and `<authorization server>` are the endpoints of the environment you integrate with — the developer guide fetched from that environment has both filled in.
19
+ AI Pay's production environment is in a free beta limited to invited users: only invited users can create an account and use the service, public registration is not open, and your users must also be invited before their first sign-in through your app's "Sign in with AI Pay". Production does not accept top-ups at the moment. `<api base>` and `<authorization server>` are the endpoints of the environment you integrate with — the developer guide fetched from that environment has both filled in.
20
20
 
21
- `aipay test` signs in as a real user: during the invitation-only beta that user must already hold an invitation (and have accepted the latest Terms), otherwise the sign-in never reaches the callback and `test` ends with the loopback timeout. The developer account you use with `aipay login` must be invited too; otherwise the developer commands keep answering 401 ("run `aipay login` again").
21
+ `aipay test` signs in as a real user: during the invitation-only beta that user must already hold an invitation (and have accepted the latest Terms), otherwise the sign-in never reaches the callback and `test` ends with the loopback timeout. The developer account you use with `aipay login` must be invited too; otherwise the developer commands answer 401 and say so (since 0.8.0 the message mentions the invitation requirement instead of only "run `aipay login` again").
22
22
 
23
23
  ## Commands
24
24
 
@@ -31,7 +31,7 @@ AI-Pay's production environment is in a free beta limited to invited users: only
31
31
  | `aipay apps callbacks add --app <client_id> --callback <url>` | Add a registered callback while preserving the others. Adding an existing URL makes no write. |
32
32
  | `aipay apps callbacks remove --app <client_id> --callback <url>` | Remove one callback; removing an absent URL makes no write. The final callback cannot be removed. |
33
33
  | `aipay init` | Links the project to your app: writes `.aipay/project.json` (commit it), `.env.local` (public values only, git-ignored), a start/callback route for your framework (Next.js, Express, Fastify, Hono, plain Node) or a browser helper for a Vite SPA (`--framework` overrides detection), `aipay-agent.md` (the developer docs, fetched once, for your agent to read offline) and installs the SDK. Never overwrites a file it did not write this run. `--dry-run` shows the plan. |
34
- | `aipay test` | The proof: a real sign-in through the AI-Pay authorization server, received by the CLI on a loopback callback, then one chat completion on that user's behalf. Prints the receipt (`request_id`, amount charged). The Console's verify step turns green from the server side. The authorization server ignores the port for `127.0.0.1` redirect URIs (RFC 8252), so the CLI binds any free port and your dev server can keep running; `--port <n>` forces one. `--no-open` prints the URL instead of opening a browser; `--model <id>` picks the model. |
34
+ | `aipay test` | The proof: a real sign-in through the AI Pay authorization server, received by the CLI on a loopback callback, then one chat completion on that user's behalf. Prints the receipt (`request_id`, amount charged). The Console's verify step turns green from the server side. The authorization server ignores the port for `127.0.0.1` redirect URIs (RFC 8252), so the CLI binds any free port and your dev server can keep running; `--port <n>` forces one. `--no-open` prints the URL instead of opening a browser; `--model <id>` picks the model. |
35
35
  | `aipay doctor` | Checks Node, the link, `.env.local`, the SDK install, and that the authorization server and API are reachable. `--offline` skips the network. |
36
36
  | `aipay status` | What this directory is linked to. |
37
37
  | `aipay unlink` | Forgets the link (removes `.aipay/project.json`, strips `AIPAY_*` from `.env.local`); keeps your code. |
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * `aipay-agent.md`: the file a coding agent reads first. Header = the facts of THIS
3
- * project (app, endpoints, what was scaffolded, what "done" means); body = the AI-Pay
3
+ * project (app, endpoints, what was scaffolded, what "done" means); body = the AI Pay
4
4
  * developer docs fetched from the API (`/docs.md?lang=en`), so the agent does not need
5
5
  * network access to read them later.
6
6
  *
@@ -4,11 +4,11 @@ export function agentGuide(input) {
4
4
  const callback = new URL(p.callback);
5
5
  const verification = callback.protocol === 'https:' || callback.search
6
6
  ? 'Sign in through the running app and make one chat completion whose response carries a receipt (`aipay.request_id`). Alternatively, use `aipay test --callback <registered-http-loopback-url>` with an already registered HTTP loopback URL without a query; leave the project callback unchanged.'
7
- : '`aipay test` completes: a real sign-in through the AI-Pay authorization server and one chat completion whose response carries a receipt (`aipay.request_id`).';
7
+ : '`aipay test` completes: a real sign-in through the AI Pay authorization server and one chat completion whose response carries a receipt (`aipay.request_id`).';
8
8
  const files = input.scaffolded.length
9
9
  ? input.scaffolded.map((f) => `- \`${f}\``).join('\n')
10
10
  : '- (none — the project had them already)';
11
- const head = `# AI-Pay integration guide for this project
11
+ const head = `# AI Pay integration guide for this project
12
12
 
13
13
  > Written by \`aipay init\` on ${p.linked_at}. Regenerate with \`aipay init --app ${p.app.client_id}\`. Safe to commit: it contains no secrets.
14
14
 
@@ -47,7 +47,7 @@ ${files}
47
47
  const body = input.docsMarkdown
48
48
  ? `---
49
49
 
50
- # AI-Pay developer documentation
50
+ # AI Pay developer documentation
51
51
 
52
52
  _Fetched from ${input.docsUrl} by \`aipay init\`._
53
53
 
@@ -55,7 +55,7 @@ ${input.docsMarkdown.trim()}
55
55
  `
56
56
  : `---
57
57
 
58
- # AI-Pay developer documentation
58
+ # AI Pay developer documentation
59
59
 
60
60
  The docs could not be fetched when this file was written (see the \`aipay init\` output).
61
61
  Check the endpoint URL and network connectivity, then read
@@ -53,7 +53,7 @@ function thrownError(error) {
53
53
  ? error.publicError
54
54
  : error instanceof CliError
55
55
  ? { code: error.code, message: error.message }
56
- : { code: 'network_error', message: 'Could not confirm the callback request with AI-Pay.' };
56
+ : { code: 'network_error', message: 'Could not confirm the callback request with AI Pay.' };
57
57
  }
58
58
  /** Preserve exact URI strings: OAuth callback matching is not URL normalization. */
59
59
  function validateCallback(value) {
@@ -134,7 +134,7 @@ function checkEnvironment(project, auth) {
134
134
  if (!expected || expected !== normalized(auth[key]))
135
135
  throw new CallbackError({
136
136
  code: 'environment_mismatch',
137
- message: 'The linked project belongs to a different AI-Pay environment. Sign in to the correct environment first; use --app explicitly only to manage an app in the current login environment.',
137
+ message: 'The linked project belongs to a different AI Pay environment. Sign in to the correct environment first; use --app explicitly only to manage an app in the current login environment.',
138
138
  outcome: 'not_attempted',
139
139
  }, EXIT.problem);
140
140
  }
@@ -150,7 +150,7 @@ async function readCallbacks(api, path, appId) {
150
150
  (body.client_id !== undefined && body.client_id !== appId))
151
151
  throw new CallbackError({
152
152
  code: 'invalid_response',
153
- message: 'AI-Pay returned an invalid callback list.',
153
+ message: 'AI Pay returned an invalid callback list.',
154
154
  });
155
155
  const system = typeof body.test_callback_uri === 'string' ? body.test_callback_uri : undefined;
156
156
  return {
@@ -176,13 +176,13 @@ async function execute(api, input) {
176
176
  !/^"redirect-uris-[0-9a-f]{64}"$/.test(before.redirect_uris_etag))
177
177
  throw new CallbackError({
178
178
  code: 'conditional_update_unavailable',
179
- message: 'This AI-Pay service does not provide a supported callback version. Update the service before changing callbacks; callbacks list remains available.',
179
+ message: 'This AI Pay service does not provide a supported callback version. Update the service before changing callbacks; callbacks list remains available.',
180
180
  outcome: 'not_attempted',
181
181
  }, EXIT.problem);
182
182
  if (input.callback === before.test_callback_uri)
183
183
  throw new CallbackError({
184
184
  code: 'system_callback',
185
- message: 'This callback is managed by AI-Pay and cannot be added or removed.',
185
+ message: 'This callback is managed by AI Pay and cannot be added or removed.',
186
186
  outcome: 'not_attempted',
187
187
  }, EXIT.problem);
188
188
  const present = before.redirect_uris.includes(input.callback);
@@ -257,7 +257,7 @@ async function execute(api, input) {
257
257
  };
258
258
  }
259
259
  export async function runCallbacks(args, out, env) {
260
- // Reject malformed invocations before loading credentials or contacting AI-Pay.
260
+ // Reject malformed invocations before loading credentials or contacting AI Pay.
261
261
  const input = inputOf(args);
262
262
  let environment;
263
263
  try {
@@ -54,7 +54,7 @@ export async function fetchCliConfig(apiBase) {
54
54
  export function resolveApiBase(args, env, dir) {
55
55
  const v = flagString(args.flags, 'api') ?? env.AIPAY_API_BASE ?? readProjectSafe(dir)?.api_base ?? null;
56
56
  if (!v)
57
- throw new CliError('usage', 'which AI-Pay? pass --api <api base> (the Console prompt lists it) or set AIPAY_API_BASE', EXIT.usage);
57
+ throw new CliError('usage', 'which AI Pay? pass --api <api base> (the Console prompt lists it) or set AIPAY_API_BASE', EXIT.usage);
58
58
  try {
59
59
  return new URL(v).origin;
60
60
  }
@@ -99,7 +99,7 @@ export async function runLogin(args, out, deps = {}) {
99
99
  const loop = await startLoopback({ host: '127.0.0.1', port: 0, path: cfg.redirect_path }, { timeoutMs: timeoutS * 1000 });
100
100
  const redirectUri = `http://127.0.0.1:${loop.port}${cfg.redirect_path}`;
101
101
  const { url, state, codeVerifier } = managementAuthorizeUrl(cfg, redirectUri);
102
- out.line('info', `signing in to ${apiBase} as a developer — approve "AI-Pay CLI" in your browser:\n\n ${url}\n`);
102
+ out.line('info', `signing in to ${apiBase} as a developer — approve "AI Pay CLI" in your browser:\n\n ${url}\n`);
103
103
  if (cfg.device_authorization)
104
104
  out.line('info', 'no browser on this machine? run `aipay login --device` instead');
105
105
  if (out.json)
@@ -134,7 +134,7 @@ export async function runRegion(args, out, env = process.env) {
134
134
  return EXIT.ok;
135
135
  }
136
136
  if (!current.region.terms_current && !acceptTerms)
137
- throw new CliError('terms_required', `the AI-Pay Terms of Service (version ${current.terms_version_required}, ${termsUrl(api.auth.api_base, current)}) need your explicit acceptance — read them, then rerun with --accept-terms`, EXIT.problem);
137
+ throw new CliError('terms_required', `the AI Pay Terms of Service (version ${current.terms_version_required}, ${termsUrl(api.auth.api_base, current)}) need your explicit acceptance — read them, then rerun with --accept-terms`, EXIT.problem);
138
138
  const body = {
139
139
  country,
140
140
  ...(state ? { subdivision: state } : {}),
@@ -7,6 +7,17 @@ export interface TestDeps {
7
7
  onAuthorizeUrl?: (url: string) => void;
8
8
  }
9
9
  export declare function runTest(args: ParsedArgs, out: Reporter, deps?: TestDeps): Promise<number>;
10
- /** Cheapest sensible default: prefer a small/cheap model id if present, else the first. */
11
- export declare function pickModel(ids: string[]): string | null;
10
+ /** What pickModel needs from a `GET /v1/models` entry (plain ids still accepted). */
11
+ export type PickableModel = string | {
12
+ id: string;
13
+ aipay?: {
14
+ availability?: {
15
+ status: string;
16
+ };
17
+ };
18
+ };
19
+ /** Cheapest sensible default: skip models the catalog marks unavailable right now (v0.8.0;
20
+ * if every model is unavailable, fall back to all of them so the server can say why), then
21
+ * prefer a small/cheap model id if present, else the first. */
22
+ export declare function pickModel(models: PickableModel[]): string | null;
12
23
  export declare function formatUusd(uusd: string): string;
@@ -1,12 +1,12 @@
1
1
  /**
2
2
  * `aipay test [--model <id>] [--no-open] [--timeout <s>] [--json]`
3
3
  *
4
- * The one check only a CLI can do end to end: a real sign-in through the AI-Pay
4
+ * The one check only a CLI can do end to end: a real sign-in through the AI Pay
5
5
  * authorization server on the registered loopback callback, then one chat completion
6
6
  * on the user's behalf. The receipt in the response is the proof (and the Console's
7
7
  * verify step turns green from the server-side facts). Tokens live in memory only.
8
8
  */
9
- import { AIPayClient, AuthorizationError, ConnectError, createConnectUrl, getUserInfo, handleCallback, InsufficientBalanceError, } from '@coswic/aipay-sdk';
9
+ import { AIPayApiError, AIPayClient, AuthorizationError, ConnectError, createConnectUrl, getUserInfo, handleCallback, InsufficientBalanceError, } from '@coswic/aipay-sdk';
10
10
  import { flagBool, flagString } from '../args.js';
11
11
  import { openBrowser } from '../browser.js';
12
12
  import { parseCallback, portIsVariable, redirectUriFor, startLoopback } from '../loopback.js';
@@ -89,7 +89,7 @@ export async function runTest(args, out, deps = {}) {
89
89
  const models = await client.models.list().catch((e) => {
90
90
  throw new CliError('models', `cannot list models: ${e.message}`, EXIT.remote);
91
91
  });
92
- model = pickModel(models.map((m) => m.id));
92
+ model = pickModel(models);
93
93
  if (!model)
94
94
  throw new CliError('models', 'no sellable model right now — pass --model <id>', EXIT.remote);
95
95
  }
@@ -127,6 +127,10 @@ export async function runTest(args, out, deps = {}) {
127
127
  }
128
128
  if (e instanceof AuthorizationError)
129
129
  throw new CliError('unauthorized', `the API rejected the token: ${e.message}`, EXIT.remote);
130
+ // v0.8.0: during the invitation-only beta a 401 is also what an uninvited (or
131
+ // invitation-revoked / terms-not-accepted) user gets — refreshing does not help.
132
+ if (e instanceof AIPayApiError && e.status === 401)
133
+ throw new CliError('unauthorized', `the API rejected the user's token (401 ${e.code}). During the invitation-only beta this also happens when the signed-in user holds no current invitation or has not accepted the latest Terms — refreshing does not help; see ${project.api_base}/about`, EXIT.remote);
130
134
  throw e;
131
135
  }
132
136
  out.result(result);
@@ -146,6 +150,8 @@ export async function runTest(args, out, deps = {}) {
146
150
  out.line('bad', msg);
147
151
  if (/\b404\b/.test(msg))
148
152
  out.line('info', 'Check the endpoint URL and network connectivity before retrying.');
153
+ if (/no callback received/.test(msg))
154
+ out.line('info', `if the AI Pay sign-in page never completed, the user may not be invited: during the invitation-only beta only invited users can sign in (see ${project.api_base}/about)`);
149
155
  out.result(result);
150
156
  return EXIT.remote;
151
157
  }
@@ -153,8 +159,15 @@ export async function runTest(args, out, deps = {}) {
153
159
  await loop.close();
154
160
  }
155
161
  }
156
- /** Cheapest sensible default: prefer a small/cheap model id if present, else the first. */
157
- export function pickModel(ids) {
162
+ /** Cheapest sensible default: skip models the catalog marks unavailable right now (v0.8.0;
163
+ * if every model is unavailable, fall back to all of them so the server can say why), then
164
+ * prefer a small/cheap model id if present, else the first. */
165
+ export function pickModel(models) {
166
+ const entries = models.map((m) => typeof m === 'string'
167
+ ? { id: m, available: true }
168
+ : { id: m.id, available: m.aipay?.availability?.status !== 'unavailable' });
169
+ const pool = entries.filter((e) => e.available);
170
+ const ids = (pool.length ? pool : entries).map((e) => e.id);
158
171
  if (!ids.length)
159
172
  return null;
160
173
  const cheap = ids.find((id) => /mini|flash|haiku|nano|small|8b|7b/i.test(id));
@@ -61,7 +61,7 @@ export function stripEnvKeys(content, keys) {
61
61
  const set = new Set(keys);
62
62
  const lines = content.split(/\r?\n/);
63
63
  const kept = lines.filter((line) => {
64
- if (line.startsWith('# AI-Pay (written by `aipay init`'))
64
+ if (line.startsWith('# AI Pay (written by `aipay init`'))
65
65
  return false;
66
66
  const m = /^\s*(?:export\s+)?([A-Z0-9_]+)\s*=/.exec(line);
67
67
  return !(m && set.has(m[1]));
@@ -35,7 +35,7 @@ export async function openDeveloperApi(store) {
35
35
  if (isEmpty404(res.status, text))
36
36
  throw new CliError('empty_404', EMPTY_404_HINT, EXIT.remote);
37
37
  if (res.status === 401 && opts.retryUnauthorized !== false)
38
- throw new CliError('unauthorized', 'the API rejected the developer token — run `aipay login` again', EXIT.remote);
38
+ throw new CliError('unauthorized', 'the API rejected the developer token — run `aipay login` again (if you just did, the developer account may not be invited yet: during the invitation-only beta only invited users can use the developer API — see the product overview at /about)', EXIT.remote);
39
39
  let body = null;
40
40
  try {
41
41
  body = text ? JSON.parse(text) : null;
@@ -46,7 +46,7 @@ export async function openDeveloperApi(store) {
46
46
  // 0074 hard gate: the developer API is closed until region + current Terms are on file.
47
47
  // `aipay region …` talks to the exempt endpoints, so this never traps the fix itself.
48
48
  if (res.status === 403 && errorCodeOf(body) === 'region_required')
49
- throw new CliError('region_required', 'AI-Pay needs your country/region and your acceptance of the current Terms of Service before the developer API can be used — run `aipay region set --country <ISO 3166-1> [--state US-XX] --accept-terms` (`aipay region` shows the version and terms URL)', EXIT.problem);
49
+ throw new CliError('region_required', 'AI Pay needs your country/region and your acceptance of the current Terms of Service before the developer API can be used — run `aipay region set --country <ISO 3166-1> [--state US-XX] --accept-terms` (`aipay region` shows the version and terms URL)', EXIT.problem);
50
50
  return { status: res.status, body: body };
51
51
  },
52
52
  };
package/dist/device.js CHANGED
@@ -29,7 +29,7 @@ export async function requestDeviceCode(cfg, fetchImpl = fetch) {
29
29
  if (!res.ok) {
30
30
  const err = parseOAuthError(text);
31
31
  if (err?.error === 'invalid_grant' || err?.error === 'unauthorized_client')
32
- throw new CliError('device_unsupported', 'this AI-Pay does not allow device sign-in for the CLI yet — use `aipay login` on a machine with a browser', EXIT.remote);
32
+ throw new CliError('device_unsupported', 'this AI Pay does not allow device sign-in for the CLI yet — use `aipay login` on a machine with a browser', EXIT.remote);
33
33
  throw new CliError('remote', `device authorization failed: HTTP ${res.status} ${err?.error ?? ''} ${err?.error_description ?? ''}`.trim(), EXIT.remote);
34
34
  }
35
35
  const j = JSON.parse(text);
package/dist/loopback.js CHANGED
@@ -86,7 +86,7 @@ export function startLoopback(target, opts = {}) {
86
86
  });
87
87
  }
88
88
  function defaultPage(ok) {
89
- const title = ok ? 'AI-Pay: signed in' : 'AI-Pay: authorization failed';
89
+ const title = ok ? 'AI Pay: signed in' : 'AI Pay: authorization failed';
90
90
  const body = ok
91
91
  ? 'You can close this tab and return to the terminal.'
92
92
  : 'The terminal shows the error. You can close this tab.';
package/dist/main.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export declare const HELP = "aipay \u2014 AI-Pay CLI\n\nUsage\n aipay login [--api <base>] [--device] [--json] developer sign-in for the CLI itself\n aipay whoami [--json] \u00B7 aipay logout [--json]\n aipay region [--json] your country/region + Terms of Service status\n aipay region set --country <CC> [--state US-XX --line1 <street> [--line2 <apt>] --city <city> --zip <ZIP>]\n [--accept-terms] [--json] US accounts need the full address (sales-tax jurisdiction)\n aipay apps list [--json]\n aipay apps create --name <name> [--callback <url>] [--json]\n aipay apps callbacks list [--app <client_id>] [--dir <path>] [--json]\n aipay apps callbacks add|remove --callback <url> [--app <client_id>] [--dir <path>] [--json]\n aipay init --app <client_id> [--auth <origin>] [--api <base>] [--callback <url>] [--name <app name>]\n [--framework next|express|fastify|hono|vite|node] override detection\n [--dir <path>] [--dry-run] [--no-install] [--json]\n aipay init --create <app name> [--api <base>] ... create the app (needs login) and link it\n aipay test [--model <id>] [--callback <registered-loopback-url>] [--port <n>] [--no-open] [--timeout <seconds>] [--dir <path>] [--json]\n aipay doctor [--offline] [--dir <path>] [--json]\n aipay status [--dir <path>] [--json]\n aipay unlink [--dry-run] [--dir <path>] [--json]\n\nlogin sign in as a developer (loopback PKCE, audience aipay-developer-api); tokens go to the\n OS keychain or a 0600 file \u2014 never into the project\nregion the developer API stays closed (403 region_required) until your account has a country/region\n (US: a state) and has accepted the current Terms of Service \u2014 \"region set\" does both; the\n version to accept and the terms URL are printed by \"aipay region\"\napps list/create your apps; callbacks list/add/remove manages registered redirects\n callback changes preserve other URLs and reject concurrent edits\ninit link this project to an app: .aipay/project.json, .env.local, .gitignore,\n a callback route for your framework, aipay-agent.md, and the SDK install\n (--auth/--api are optional once you are signed in; --create makes the app first)\ntest real sign-in via a loopback callback (any free port on 127.0.0.1) + one chat completion \u2192 receipt\ndoctor check the link, files, SDK, and that AI-Pay is reachable\nstatus what this directory is linked to\nunlink forget the link (keeps your code)\n\nExit codes: 0 ok \u00B7 1 problem you can fix \u00B7 2 usage \u00B7 3 network/auth\n";
1
+ export declare const HELP = "aipay \u2014 AI Pay CLI\n\nUsage\n aipay login [--api <base>] [--device] [--json] developer sign-in for the CLI itself\n aipay whoami [--json] \u00B7 aipay logout [--json]\n aipay region [--json] your country/region + Terms of Service status\n aipay region set --country <CC> [--state US-XX --line1 <street> [--line2 <apt>] --city <city> --zip <ZIP>]\n [--accept-terms] [--json] US accounts need the full address (sales-tax jurisdiction)\n aipay apps list [--json]\n aipay apps create --name <name> [--callback <url>] [--json]\n aipay apps callbacks list [--app <client_id>] [--dir <path>] [--json]\n aipay apps callbacks add|remove --callback <url> [--app <client_id>] [--dir <path>] [--json]\n aipay init --app <client_id> [--auth <origin>] [--api <base>] [--callback <url>] [--name <app name>]\n [--framework next|express|fastify|hono|vite|node] override detection\n [--dir <path>] [--dry-run] [--no-install] [--json]\n aipay init --create <app name> [--api <base>] ... create the app (needs login) and link it\n aipay test [--model <id>] [--callback <registered-loopback-url>] [--port <n>] [--no-open] [--timeout <seconds>] [--dir <path>] [--json]\n aipay doctor [--offline] [--dir <path>] [--json]\n aipay status [--dir <path>] [--json]\n aipay unlink [--dry-run] [--dir <path>] [--json]\n\nlogin sign in as a developer (loopback PKCE, audience aipay-developer-api); tokens go to the\n OS keychain or a 0600 file \u2014 never into the project\nregion the developer API stays closed (403 region_required) until your account has a country/region\n (US: a state) and has accepted the current Terms of Service \u2014 \"region set\" does both; the\n version to accept and the terms URL are printed by \"aipay region\"\napps list/create your apps; callbacks list/add/remove manages registered redirects\n callback changes preserve other URLs and reject concurrent edits\ninit link this project to an app: .aipay/project.json, .env.local, .gitignore,\n a callback route for your framework, aipay-agent.md, and the SDK install\n (--auth/--api are optional once you are signed in; --create makes the app first)\ntest real sign-in via a loopback callback (any free port on 127.0.0.1) + one chat completion \u2192 receipt\ndoctor check the link, files, SDK, and that AI Pay is reachable\nstatus what this directory is linked to\nunlink forget the link (keeps your code)\n\nExit codes: 0 ok \u00B7 1 problem you can fix \u00B7 2 usage \u00B7 3 network/auth\n";
2
2
  export declare function main(argv: string[], io?: {
3
3
  stdout?: (s: string) => void;
4
4
  stderr?: (s: string) => void;
package/dist/main.js CHANGED
@@ -10,7 +10,7 @@ import { runTest } from './commands/test.js';
10
10
  import { runUnlink } from './commands/unlink.js';
11
11
  import { CliError, createReporter, EXIT } from './output.js';
12
12
  import { cliVersion } from './version.js';
13
- export const HELP = `aipay — AI-Pay CLI
13
+ export const HELP = `aipay — AI Pay CLI
14
14
 
15
15
  Usage
16
16
  aipay login [--api <base>] [--device] [--json] developer sign-in for the CLI itself
@@ -42,7 +42,7 @@ init link this project to an app: .aipay/project.json, .env.local, .gitignore
42
42
  a callback route for your framework, aipay-agent.md, and the SDK install
43
43
  (--auth/--api are optional once you are signed in; --create makes the app first)
44
44
  test real sign-in via a loopback callback (any free port on 127.0.0.1) + one chat completion → receipt
45
- doctor check the link, files, SDK, and that AI-Pay is reachable
45
+ doctor check the link, files, SDK, and that AI Pay is reachable
46
46
  status what this directory is linked to
47
47
  unlink forget the link (keeps your code)
48
48
 
package/dist/network.d.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  /** Describe the observed response without inferring its network or server-side cause. */
2
2
  export declare function isEmpty404(status: number, bodyText: string): boolean;
3
- export declare const EMPTY_404_HINT = "AI-Pay answered 404 with an empty body. Check the endpoint URL and network connectivity, then retry. An empty 404 alone does not identify the cause.";
3
+ export declare const EMPTY_404_HINT = "AI Pay answered 404 with an empty body. Check the endpoint URL and network connectivity, then retry. An empty 404 alone does not identify the cause.";
package/dist/network.js CHANGED
@@ -2,4 +2,4 @@
2
2
  export function isEmpty404(status, bodyText) {
3
3
  return status === 404 && bodyText.trim() === '';
4
4
  }
5
- export const EMPTY_404_HINT = 'AI-Pay answered 404 with an empty body. Check the endpoint URL and network connectivity, then retry. An empty 404 alone does not identify the cause.';
5
+ export const EMPTY_404_HINT = 'AI Pay answered 404 with an empty body. Check the endpoint URL and network connectivity, then retry. An empty 404 alone does not identify the cause.';
package/dist/output.d.ts CHANGED
@@ -26,7 +26,7 @@ export declare const EXIT: {
26
26
  readonly problem: 1;
27
27
  /** Bad invocation (unknown command/flag, missing required flag). */
28
28
  readonly usage: 2;
29
- /** Network/auth failure talking to AI-Pay. */
29
+ /** Network/auth failure talking to AI Pay. */
30
30
  readonly remote: 3;
31
31
  };
32
32
  export declare class CliError extends Error {
package/dist/output.js CHANGED
@@ -37,7 +37,7 @@ export const EXIT = {
37
37
  problem: 1,
38
38
  /** Bad invocation (unknown command/flag, missing required flag). */
39
39
  usage: 2,
40
- /** Network/auth failure talking to AI-Pay. */
40
+ /** Network/auth failure talking to AI Pay. */
41
41
  remote: 3,
42
42
  };
43
43
  export class CliError extends Error {
package/dist/project.js CHANGED
@@ -33,7 +33,7 @@ export function readProject(dir) {
33
33
  const raw = readFileSync(p, 'utf8');
34
34
  const parsed = JSON.parse(raw);
35
35
  if (!isProjectConfig(parsed))
36
- throw new Error(`${p} is not a valid AI-Pay project file`);
36
+ throw new Error(`${p} is not a valid AI Pay project file`);
37
37
  return parsed;
38
38
  }
39
39
  export function writeProject(dir, cfg) {
@@ -98,7 +98,7 @@ export function mergeEnvFile(existing, values) {
98
98
  if (missing.length) {
99
99
  if (out.length)
100
100
  out.push('');
101
- out.push('# AI-Pay (written by `aipay init`; public values, safe to keep local)');
101
+ out.push('# AI Pay (written by `aipay init`; public values, safe to keep local)');
102
102
  for (const k of missing) {
103
103
  out.push(`${k}=${values[k]}`);
104
104
  changed.push(k);
@@ -121,6 +121,6 @@ export function mergeGitignore(existing, entries) {
121
121
  if (!added.length)
122
122
  return { content: existing ?? '', added };
123
123
  const base = existing ? (existing.endsWith('\n') ? existing : `${existing}\n`) : '';
124
- const block = `${base}${base ? '\n' : ''}# AI-Pay local files (never commit)\n${added.join('\n')}\n`;
124
+ const block = `${base}${base ? '\n' : ''}# AI Pay local files (never commit)\n${added.join('\n')}\n`;
125
125
  return { content: block, added };
126
126
  }
package/dist/remote.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Everything that talks to AI-Pay over the network, in one place so the commands stay
2
+ * Everything that talks to AI Pay over the network, in one place so the commands stay
3
3
  * readable and tests can stub it.
4
4
  */
5
5
  import { EMPTY_404_HINT } from './network.js';
package/dist/remote.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Everything that talks to AI-Pay over the network, in one place so the commands stay
2
+ * Everything that talks to AI Pay over the network, in one place so the commands stay
3
3
  * readable and tests can stub it.
4
4
  */
5
5
  import { EMPTY_404_HINT, isEmpty404 } from './network.js';
package/dist/templates.js CHANGED
@@ -82,7 +82,7 @@ const apiBase = process.env.AIPAY_API_BASE${t(' as string', '')}
82
82
  const pendingFlows = new Map${t('<string, { codeVerifier: string; expires: number }>', '')}()
83
83
  const sessions = new Map${t('<string, TokenSet>', '')}()
84
84
 
85
- /** Step 1 — build the AI-Pay sign-in URL; remember the PKCE verifier under the state. */
85
+ /** Step 1 — build the AI Pay sign-in URL; remember the PKCE verifier under the state. */
86
86
  export async function beginSignIn()${t(': Promise<string>', '')} {
87
87
  const { url, state, codeVerifier } = await createConnectUrl(cfg)
88
88
  pendingFlows.set(state, { codeVerifier, expires: Date.now() + 10 * 60_000 })
@@ -239,7 +239,7 @@ export async function handleAIPay(req${ts ? ': IncomingMessage' : ''}, res${ts ?
239
239
  function browserModule(input) {
240
240
  const ts = input.typescript;
241
241
  const t = (typed, plain) => (ts ? typed : plain);
242
- return `${ts ? '/// <reference types="vite/client" />\n' : ''}// Browser (Vite) build of the AI-Pay helper. Reads the VITE_AIPAY_* values \`aipay init\`
242
+ return `${ts ? '/// <reference types="vite/client" />\n' : ''}// Browser (Vite) build of the AI Pay helper. Reads the VITE_AIPAY_* values \`aipay init\`
243
243
  // wrote to .env.local (Vite exposes only VITE_-prefixed values to the page). No secret
244
244
  // exists: the app is a public PKCE client and the token endpoint accepts browser calls.
245
245
  import {
@@ -258,10 +258,10 @@ const apiBase = import.meta.env.VITE_AIPAY_API_BASE${t(' as string', '')}
258
258
  /** Path part of the registered callback — the page that must call completeSignInIfCallback(). */
259
259
  export const CALLBACK_PATH = ${JSON.stringify(input.callbackPath)}
260
260
 
261
- const PENDING_KEY = 'aipay:pending' // { state, codeVerifier } while the user is at AI-Pay
261
+ const PENDING_KEY = 'aipay:pending' // { state, codeVerifier } while the user is at AI Pay
262
262
  const TOKENS_KEY = 'aipay:tokens' // TokenSet for this tab (sessionStorage: cleared when the tab closes)
263
263
 
264
- /** Step 1 — send the user to AI-Pay. The PKCE verifier is kept under the state for the callback. */
264
+ /** Step 1 — send the user to AI Pay. The PKCE verifier is kept under the state for the callback. */
265
265
  export async function beginSignIn()${t(': Promise<void>', '')} {
266
266
  const { url, state, codeVerifier } = await createConnectUrl(cfg)
267
267
  sessionStorage.setItem(PENDING_KEY, JSON.stringify({ state, codeVerifier }))
@@ -313,7 +313,7 @@ function viteBoot(input) {
313
313
  const ts = input.typescript;
314
314
  const from = ts ? './aipay' : './aipay.js';
315
315
  return `// Call bootAIPay() once when your app starts (top of main.${ts ? 'ts' : 'js'} / before rendering).
316
- // It completes the sign-in when the page is the AI-Pay callback (${input.callbackPath}) and
316
+ // It completes the sign-in when the page is the AI Pay callback (${input.callbackPath}) and
317
317
  // otherwise does nothing. Vite's dev server serves index.html for that path (SPA fallback),
318
318
  // so no route configuration is needed; with a client-side router, keep the path unrouted.
319
319
  import { beginSignIn, completeSignInIfCallback, currentTokens, firstCompletion } from '${from}'
@@ -323,7 +323,7 @@ export async function bootAIPay() {
323
323
  const signedIn = justSignedIn !== null || currentTokens() !== null
324
324
  return {
325
325
  signedIn,
326
- /** Wire this to your "Sign in with AI-Pay" button. */
326
+ /** Wire this to your "Sign in with AI Pay" button. */
327
327
  beginSignIn,
328
328
  /** After sign-in: one model call; the receipt (cost, request id) is on the result. */
329
329
  firstCompletion,
package/package.json CHANGED
@@ -1,7 +1,8 @@
1
1
  {
2
2
  "name": "@coswic/aipay",
3
- "version": "0.7.2",
4
- "description": "AI-Pay CLI — developer sign-in, App and callback management, project integration, diagnostics, and real sign-in + AI receipt verification.",
3
+ "version": "0.8.0",
4
+ "description": "AI Pay CLI — developer sign-in, App and callback management, project integration, diagnostics, and real sign-in + AI receipt verification.",
5
+ "author": "Coswic Labs (https://coswic.ai)",
5
6
  "license": "MIT",
6
7
  "homepage": "https://ai-pay.coswic.ai/docs?lang=en",
7
8
  "type": "module",
@@ -26,7 +27,7 @@
26
27
  "node": ">=20"
27
28
  },
28
29
  "dependencies": {
29
- "@coswic/aipay-sdk": "^0.4.2"
30
+ "@coswic/aipay-sdk": "^0.5.0"
30
31
  },
31
32
  "devDependencies": {
32
33
  "@types/node": "^26.1.1",