Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ Wilson 의 **디자인 기둥 중 하나** — 결정적인 도구 (read/write/e
| **noun-verb 패밀리** | `wilson pool <list\|propose\|on\|probe\|mount\|doctor\|mesh>` → `pool_*` (plugins/pool/) |
| | `wilson task <add\|list\|done\|in_progress\|reset\|delete\|clear>` → `task_*` (+ tasks.jsonl) |
| | `wilson endpoint <list\|show\|test\|resolve>` → `endpoint_*` + `~/.wilson/providers.json` |
| | `wilson quota <status\|list\|add\|show\|help>` → `quota_*` (plugins/quota/ · Claude 5h/7d limits + multi-account registry · opt-in `wilson build --with quota`) |
| | `wilson web <fetch\|search>` → `web_fetch` / `web_search` |
| | `wilson image <info>` → `image_info` |
| **단일 도구 shortcut** | `wilson git/gh <subcmd> [args] [--cwd D]` → bridge-git / bridge-gh |
Expand Down
2 changes: 2 additions & 0 deletions core/loader.hexa
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,7 @@ pub fn plugin_family(id: string) -> string {
if id == "mcp" { return "integration" }
if id == "slash-core" { return "ux" }
if id == "inbox" { return "policy" }
if id == "quota" { return "infra" }
if id == "bridge-hexa" { return "io" }
if id == "bridge-git" { return "io" }
if id == "bridge-gh" { return "io" }
Expand Down Expand Up @@ -293,6 +294,7 @@ pub fn plugin_category(id: string) -> string {
if id == "mcp" { return "protocol" }
if id == "slash-core" { return "slashes" }
if id == "inbox" { return "knowledge" }
if id == "quota" { return "accounts" }
if id == "bridge-hexa" { return "bridge" }
if id == "bridge-git" { return "bridge" }
if id == "bridge-gh" { return "bridge" }
Expand Down
46 changes: 46 additions & 0 deletions core/main.hexa
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ fn _run(orig_argv: [string]) -> int {
if arg1 == "domain" { return _cmd_domain(_rest(argv, 2)) } // list | show <NAME> — governance #4 root .md inventory (cost-routing)
if arg1 == "endpoint" { return _cmd_endpoint(_rest(argv, 2)) } // list | show <id> | test <id> | resolve <id> — ~/.wilson/providers.json (cost-routing)
if arg1 == "inbox" { return _cmd_inbox(_rest(argv, 2)) } // add <kind> <slug> [--to <repo>] — cross-project handoff scaffolder (g7 cross-project-handoff-via-inbox)
if arg1 == "quota" { return _cmd_quota(_rest(argv, 2)) } // status | list | add | show | help — Claude account 5h/7d limits + registry (g10; plugins/quota/, opt-in --with quota)
if arg1 == "colors" { return _cmd_colors(_rest(argv, 2)) } // print the wilson TUI palette as ANSI swatches to stdout
if arg1 == "test" { return _cmd_test(_rest(argv, 2)) } // headless smoke — boot + invariants + /help dispatch; exit 0=pass, 1=fail
if arg1 == "--test" { return _cmd_test(_rest(argv, 2)) } // alias of `wilson test` for the `--<flag>` muscle memory
Expand Down Expand Up @@ -2033,6 +2034,51 @@ fn _cmd_inbox(rest: [string]) -> int {
return 2
}

// ── wilson quota <status|list|add|show|help> (cost-routing shortcut) ──
// LLM-bypass — mirrors the in-TUI `/quota` slash. Boots the host, dispatches
// into the `quota` plugin via host_plugin_call(host, "quota", "cli:<verb>", …).
// Phase 1 = read-only: current account + LIVE 5h/7d (OAuth usage endpoint) +
// wilson-owned registry. Not in the default bundle — `wilson build --with
// quota`. Design: plugins/quota/RESEARCH.md + RESEARCH.tape (g10; g9).
fn _cmd_quota(rest: [string]) -> int {
let sub = _at(rest, 0, "")
let host = _boot_full()
if _is_err(host) { return 3 }
if has_key(host.registry.tools, "quota") == false {
eprintln("[wilson] quota plugin not bundled in this build — rebuild with `wilson build --with quota`")
return 3
}
if sub == "" || sub == "status" { return _quota_emit(host, "cli:status") }
if sub == "show" { return _quota_emit(host, "cli:show") }
if sub == "list" || sub == "ls" { return _quota_emit(host, "cli:list") }
if sub == "help" || sub == "--help" || sub == "-h" { return _quota_emit(host, "cli:help") }
if sub == "add" {
let r = host_plugin_call(host, "quota", "cli:add", #{})
if _quota_env_ok(r) { println("✓ " + str(r["text"])) ; return 0 }
eprintln("[wilson] quota add failed: " + _quota_env_err(r))
return 1
}
if sub == "switch" {
eprintln("[wilson] quota switch: not_implemented:phase3 — live cred switch + seamless failover (recipe: plugins/quota/RESEARCH.md §c3)")
return 2
}
eprintln("[wilson] unknown `quota` subcommand: " + sub + " (status | list | add | show | help)")
return 2
}
fn _quota_emit(host: any, op: string) -> int {
let r = host_plugin_call(host, "quota", op, #{})
if _quota_env_ok(r) { println(str(r["text"])) ; return 0 }
eprintln("[wilson] quota " + op + " failed: " + _quota_env_err(r))
return 1
}
fn _quota_env_ok(r: any) -> bool {
return type_of(r) == "map" && has_key(r, "ok") && r["ok"] == true
}
fn _quota_env_err(r: any) -> string {
if type_of(r) == "map" && has_key(r, "error") { return str(r["error"]) }
return "unknown error"
}

fn _inbox_envelope_ok(r: any) -> bool {
return type_of(r) == "map" && has_key(r, "ok") && r["ok"] == true
}
Expand Down
74 changes: 74 additions & 0 deletions docs/sessions/2026-05-16-quota-plugin-scaffold.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# 2026-05-16 — `quota` plugin scaffold (multi-account Claude limits)

## What this session did

1. **Web deep-research** — landscape of multi-account Claude limit-tracking +
account-switching + failover tooling.
2. **Prior-art clone + exhaustive survey** — 12 repos cloned to
`~/core/reference/claude-multi-account/` (OUT of the wilson git tree, no
nested `.git`). 3 parallel Explore passes (cred-store · limit-read ·
failover). `cux` flagged GPL-3.0 (study/clean-room only).
3. **ToS correction** — user flagged "밴조건 폐기됨"; verified via 1P Claude
Code legal docs: the 2026 OpenClaw ban was *reinstated/restructured*, not
abolished — from **2026-06-15** `claude -p`/Agent SDK on subscriptions
draws a separate metered monthly **Agent SDK credit**. Constraint moved
prohibition → metering; `@F f1` rescoped (not deleted).
4. **`quota` plugin Phase-1 scaffold** built + verified.

## Files (uncommitted — no commit requested)

- `plugins/quota/RESEARCH.md` · `RESEARCH.tape` — prior-art SSOT + locked
constants + phased design (`@D d_phase1`) + ToS timeline + Agent-SDK gap.
- `plugins/quota/plugin.hexa` — manifest (id=quota, kind command+tool,
cap exec, `/quota`, opt-out `WILSON_NO_QUOTA`) + `quota_dispatch`.
- `plugins/quota/main.hexa` — current account (`~/.claude.json` oauthAccount)
· token (linux file ∨ mac keychain) · **live 5h/7d via OAuth usage
endpoint** (curl through `exec_with_status`; g2/g4) · wilson-owned registry
· `quota_summary` · Phase-3 switch/failover fail-loud (g3).
- `plugins/quota/test_quota.hexa` — fake_host selftest (network-free; public
dispatch surface), matches the test_hello/test_inbox convention.
- `core/main.hexa` — `wilson quota` CLI (g10): argv route + `_cmd_quota`
(mirrors `_cmd_inbox`) + `_quota_env_ok/_err`. **core owns its argv
dispatch — not a g8 plugin-patch** (inbox/pool precedent).
- `core/loader.hexa` — `plugin_family("quota")="infra"` /
`plugin_category="accounts"` (taxonomy registry; silences loader warn).
- `AGENTS.md` — cost-routing table row for `wilson quota` (g10 in-sync).

## Verification (real gates — bare `hexa run` of any plugin selftest is NOT a
gate; canonical `test_hello`/`test_inbox` also fail bare → run via full build)

- `wilson build --with quota` → **OK, 30 plugins incl. quota, exit 0**. The
two `codegen_c2 ... to_upper_case` lines are **pre-existing harness-cli
`chip_cap`** (n19: has a fallback, harmless) — **not** from quota; no
quota `error:`/HX####.
- `wilson test` (full boot incl. quota) → **PASS 23 · FAIL 0 · 3s** (no
regression).
- n19 runtime CODEGEN check (`echo /quota help | wilson-custom`) → **no new
codegen error from quota**.
- `wilson quota help` / `list` → exit 0, correct output.
- `wilson quota status` → **live OAuth data path proven** against the real
account: `Account: mkgt3rs@proton.me`, `5h util=45.0
resets=…`, `7d util=6.0 resets=…`, Agent-SDK honest stub, exit 0.

## Findings / deferred (cite artifact)

- **OAuth usage `utilization` scale is 0–100, not 0–1** (empirically:
`util=45.0`). Survey (claude-swap reading) had assumed 0–1. Scaffold
displays the **raw** value faithfully (correct for P1). Normalization to
`NN%` + reset countdown = **Phase 2** (`RESEARCH.tape d_phase1.phase2`).
- **Agent SDK monthly credit** — no source in any of 12 repos (too new);
fail-loud `not_implemented:agent-sdk-credit`. Recheck after **2026-06-15**
(`RESEARCH.tape n_agentsdk_gap`).
- **Phase 3** (live credential SWITCH + seamless `--resume` failover) —
contracted fail-loud; recipe locked in `RESEARCH.md §c3` /
`RESEARCH.tape n_failover_recipe` (clean-room from cux GPL-3). Warrants its
own step-by-step gate (governance #7).
- `quota` is **opt-in** (not in `plugins/_bundle`, g9) — ships via
`wilson build --with quota`.

## Repo state

Branch `main`. Working tree dirty: `plugins/quota/*` (new),
`core/main.hexa`, `core/loader.hexa`, `AGENTS.md`, `docs/sessions/` (this),
`plugins/pool/main.hexa` (pre-existing, untouched this session). No commit
made (none requested). Rebuild after the loader taxonomy fix in flight.
Loading
Loading