bizrouter 0.3.1 → 0.3.3

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/AGENT_MANUAL.md CHANGED
@@ -152,6 +152,7 @@ Why did requests fail this morning?
152
152
 
153
153
  ```
154
154
  bizrouter audit list --status error --from 2026-09-06 --limit 20
155
+ bizrouter audit list --user kim@example.com # one person's requests (email or name, partial match)
155
156
  bizrouter audit show <log_id>
156
157
  ```
157
158
 
@@ -313,7 +313,9 @@ export async function billingCommand(argv) {
313
313
  return emit(parsed, { credits, monthly }, () => {
314
314
  const type = credits.payment_type === 'prepaid' ? '선불(크레딧)' : credits.payment_type === 'postpaid' ? '후불' : credits.payment_type;
315
315
  print(c.bold(`결제 방식 ${type}${credits.has_contract ? ' · 계약 고객' : ''}${credits.auto_card_billing ? ' · 카드 자동 충전' : ''}`));
316
- print(` 현재 크레딧 ${formatKrw(Number(credits.current_credits))} · 누적 사용 ${formatKrw(Number(credits.used_credits))}${credits.monthly_limit != null ? ` · 월 한도 ${formatKrw(Number(credits.monthly_limit))}` : ''}`);
316
+ const effectiveLimit = credits.effective_monthly_limit !== undefined ? credits.effective_monthly_limit : credits.monthly_limit;
317
+ const hardCap = credits.admin_monthly_hard_cap;
318
+ print(` 현재 크레딧 ${formatKrw(Number(credits.current_credits))} · 누적 사용 ${formatKrw(Number(credits.used_credits))}${effectiveLimit != null ? ` · 월 한도 ${formatKrw(Number(effectiveLimit))}` : ''}${hardCap != null ? ` (운영자 상한 ${formatKrw(Number(hardCap))})` : ''}`);
317
319
  print(` 이번 달 사용 ${formatKrw(monthly.current_month_amount_krw)}${monthly.current_available_amount_krw != null ? ` · 사용 가능 ${formatKrw(monthly.current_available_amount_krw)}` : ''}`);
318
320
  print();
319
321
  table(['월', '상태', 'API 사용', '청구 합계', '요청 수'], monthly.items.map((m) => [m.month, `${m.status}${m.payment_status ? `/${m.payment_status}` : ''}`, formatKrw(m.api_usage_krw), formatKrw(m.total_amount_krw), m.request_count.toLocaleString('ko-KR')]));
@@ -380,7 +382,7 @@ export async function orgCommand(argv) {
380
382
  }
381
383
  }
382
384
  const AUDIT_USAGE = [
383
- 'bizrouter audit list [--status success|error|blocked] [--model ID] [--key 이름] [--from YYYY-MM-DD] [--to YYYY-MM-DD] [--search 텍스트] [--limit N] [--cursor C] [--json]',
385
+ 'bizrouter audit list [--status success|error|blocked] [--model ID] [--key 이름] [--app 이름] [--user 이메일|이름] [--from YYYY-MM-DD] [--to YYYY-MM-DD] [--search 텍스트] [--limit N] [--cursor C] [--json]',
384
386
  'bizrouter audit show <log_id> [--json]',
385
387
  'bizrouter audit stats [--json]',
386
388
  ].join('\n');
@@ -397,6 +399,8 @@ export async function auditCommand(argv) {
397
399
  model: flagString(parsed, 'model'),
398
400
  api_key: flagString(parsed, 'key'),
399
401
  app_name: flagString(parsed, 'app'),
402
+ // Partial, case-insensitive match on the requesting user's email or name.
403
+ user: flagString(parsed, 'user'),
400
404
  search: flagString(parsed, 'search'),
401
405
  start_date: from ? `${from}T00:00:00` : undefined,
402
406
  end_date: to ? `${to}T23:59:59` : undefined,
@@ -408,13 +412,14 @@ export async function auditCommand(argv) {
408
412
  print('조건에 맞는 요청 기록이 없습니다.');
409
413
  return;
410
414
  }
411
- table(['시각', '모델', '상태', '토큰(입/출)', '비용', '앱', '요청 미리보기', 'id'], data.items.map((i) => [
415
+ table(['시각', '모델', '상태', '토큰(입/출)', '비용', '앱', '사용자', '요청 미리보기', 'id'], data.items.map((i) => [
412
416
  shortDate(i.created_at),
413
417
  i.model ?? '-',
414
418
  i.status,
415
419
  `${i.input_tokens ?? 0}/${i.output_tokens ?? 0}`,
416
420
  i.cost_krw == null ? '-' : formatKrw(i.cost_krw),
417
421
  i.app_name ?? '-',
422
+ i.user_email ?? '-',
418
423
  (i.request_prompt_preview ?? '').replace(/\s+/g, ' ').slice(0, 40),
419
424
  i.id,
420
425
  ]));
@@ -2,7 +2,7 @@ import { spawn } from 'node:child_process';
2
2
  import { ENV_KEY_NAME } from '../config.js';
3
3
  import { c, info, print } from '../ui.js';
4
4
  import { requireApiKey } from './shared.js';
5
- export const VERSION = '0.3.1';
5
+ export const VERSION = '0.3.3';
6
6
  /** `eval "$(bizrouter env)"` exports the saved key for tools configured by `bizrouter setup`. */
7
7
  export function envCommand() {
8
8
  const key = requireApiKey();
@@ -1,4 +1,4 @@
1
- import { copyFileSync, existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
1
+ import { chmodSync, copyFileSync, existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
2
2
  import { homedir } from 'node:os';
3
3
  import { dirname, join } from 'node:path';
4
4
  import { fetchCatalog } from '../api.js';
@@ -29,7 +29,15 @@ function backup(path) {
29
29
  }
30
30
  function writeText(path, text) {
31
31
  mkdirSync(dirname(path), { recursive: true });
32
- writeFileSync(path, text);
32
+ // These files carry the API key: owner-only, and tighten an existing file
33
+ // that was created with the default umask.
34
+ writeFileSync(path, text, { mode: 0o600 });
35
+ try {
36
+ chmodSync(path, 0o600);
37
+ }
38
+ catch {
39
+ // Windows/ACL filesystems: best effort.
40
+ }
33
41
  }
34
42
  /** Merge BizRouter's env block into a Claude Code settings.json object. */
35
43
  export function mergeClaudeSettings(existing, env) {
@@ -30,6 +30,13 @@ export function codexOverrides(options) {
30
30
  }
31
31
  if (options.resetServiceTier)
32
32
  overrides.push(`service_tier=${tomlString('default')}`);
33
+ // Codex 0.144+ ships the OpenAI-hosted `web_search` tool on every turn. BizRouter has no
34
+ // pricing contract for that hosted tool and answers 400 ("No reviewed pricing contract is
35
+ // available for hosted tool web_search"), which kills the very first turn. Turn it off for
36
+ // this launch; BizRouter Search stays available through the `bizrouter_search` MCP tool.
37
+ if (!(options.passthrough ?? []).some((arg, i) => /^web_search\s*=/.test(arg) || ((options.passthrough ?? [])[i - 1] === '-c' && /^web_search\s*=/.test(arg)))) {
38
+ overrides.push(`web_search=${tomlString('disabled')}`);
39
+ }
33
40
  return overrides.flatMap((o) => ['-c', o]);
34
41
  }
35
42
  export function buildCodexPlan(options) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bizrouter",
3
- "version": "0.3.1",
3
+ "version": "0.3.3",
4
4
  "description": "BizRouter CLI - run Claude Code, Codex, OpenCode, and Hermes through BizRouter, operate the BizRouter console (API keys, usage, policies, audit logs) from the terminal or as an MCP server, and ask BizRouter Search for answers grounded in 50+ live data sources",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",