aweshare 0.2.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 (69) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +246 -0
  3. package/apps/agent/dist/adapters.d.ts +15 -0
  4. package/apps/agent/dist/adapters.js +25 -0
  5. package/apps/agent/dist/adapters.js.map +1 -0
  6. package/apps/agent/dist/cli.d.ts +2 -0
  7. package/apps/agent/dist/cli.js +175 -0
  8. package/apps/agent/dist/cli.js.map +1 -0
  9. package/apps/agent/dist/config.d.ts +38 -0
  10. package/apps/agent/dist/config.js +150 -0
  11. package/apps/agent/dist/config.js.map +1 -0
  12. package/apps/agent/dist/connection.d.ts +40 -0
  13. package/apps/agent/dist/connection.js +359 -0
  14. package/apps/agent/dist/connection.js.map +1 -0
  15. package/apps/agent/dist/doctor.d.ts +14 -0
  16. package/apps/agent/dist/doctor.js +125 -0
  17. package/apps/agent/dist/doctor.js.map +1 -0
  18. package/apps/agent/dist/health.d.ts +15 -0
  19. package/apps/agent/dist/health.js +45 -0
  20. package/apps/agent/dist/health.js.map +1 -0
  21. package/apps/agent/dist/index.d.ts +5 -0
  22. package/apps/agent/dist/index.js +6 -0
  23. package/apps/agent/dist/index.js.map +1 -0
  24. package/apps/agent/package.json +20 -0
  25. package/apps/hub/dist/admin.d.ts +10 -0
  26. package/apps/hub/dist/admin.js +208 -0
  27. package/apps/hub/dist/admin.js.map +1 -0
  28. package/apps/hub/dist/auth.d.ts +17 -0
  29. package/apps/hub/dist/auth.js +28 -0
  30. package/apps/hub/dist/auth.js.map +1 -0
  31. package/apps/hub/dist/cli.d.ts +2 -0
  32. package/apps/hub/dist/cli.js +243 -0
  33. package/apps/hub/dist/cli.js.map +1 -0
  34. package/apps/hub/dist/config.d.ts +25 -0
  35. package/apps/hub/dist/config.js +53 -0
  36. package/apps/hub/dist/config.js.map +1 -0
  37. package/apps/hub/dist/consumer.d.ts +18 -0
  38. package/apps/hub/dist/consumer.js +157 -0
  39. package/apps/hub/dist/consumer.js.map +1 -0
  40. package/apps/hub/dist/db.d.ts +91 -0
  41. package/apps/hub/dist/db.js +236 -0
  42. package/apps/hub/dist/db.js.map +1 -0
  43. package/apps/hub/dist/http.d.ts +31 -0
  44. package/apps/hub/dist/http.js +118 -0
  45. package/apps/hub/dist/http.js.map +1 -0
  46. package/apps/hub/dist/limiter.d.ts +35 -0
  47. package/apps/hub/dist/limiter.js +78 -0
  48. package/apps/hub/dist/limiter.js.map +1 -0
  49. package/apps/hub/dist/limits.d.ts +30 -0
  50. package/apps/hub/dist/limits.js +52 -0
  51. package/apps/hub/dist/limits.js.map +1 -0
  52. package/apps/hub/dist/meter.d.ts +25 -0
  53. package/apps/hub/dist/meter.js +135 -0
  54. package/apps/hub/dist/meter.js.map +1 -0
  55. package/apps/hub/dist/sanitize.d.ts +3 -0
  56. package/apps/hub/dist/sanitize.js +56 -0
  57. package/apps/hub/dist/sanitize.js.map +1 -0
  58. package/apps/hub/dist/server.d.ts +25 -0
  59. package/apps/hub/dist/server.js +77 -0
  60. package/apps/hub/dist/server.js.map +1 -0
  61. package/apps/hub/dist/tokens.d.ts +9 -0
  62. package/apps/hub/dist/tokens.js +35 -0
  63. package/apps/hub/dist/tokens.js.map +1 -0
  64. package/apps/hub/dist/tunnel.d.ts +108 -0
  65. package/apps/hub/dist/tunnel.js +424 -0
  66. package/apps/hub/dist/tunnel.js.map +1 -0
  67. package/apps/hub/package.json +21 -0
  68. package/bin/aweshare.mjs +43 -0
  69. package/package.json +47 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 aweshare contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,246 @@
1
+ <div align="center">
2
+
3
+ <img src="logo/logo.webp" alt="aweshare" width="860">
4
+
5
+ # aweshare
6
+
7
+ **Open-source, local-first AI capability relay**
8
+
9
+ **English** · [简体中文](./README_cn.md)
10
+
11
+ </div>
12
+
13
+ Producers run a lightweight agent on their own machine and share local Ollama/vLLM or **authorized** OpenAI/Anthropic backends. Upstream API keys live only on the producer's device and are injected by the local agent at forwarding time. Consumers point a standard OpenAI/Anthropic SDK at the hub and call models by `namespace/alias` — exactly like using any other model vendor.
14
+
15
+ ```
16
+ Consumer (standard SDK, zero changes) Producer side
17
+ ┌───────────────────────┐ ┌────────────────────────────┐
18
+ │ Claude Code │ │ aweshare agent (Node CLI) │
19
+ │ ANTHROPIC_BASE_URL ──┼──► HTTPS ──┤ ~/.aweshare/config.toml │
20
+ │ OpenAI SDK / Codex │ │ ~/.aweshare/secrets.json │
21
+ └───────────────────────┘ │ │ upstream key injection │
22
+ │ /v1/messages │ ▼ (the only place it happens)
23
+ │ /v1/chat/completions │ Ollama / vLLM / OpenAI / Anthropic
24
+ ▼ │
25
+ ┌─────────────────────────────┐ │
26
+ │ aweshare hub (public, 1 node)│◄───── WSS reverse tunnel (agent dials out)
27
+ │ auth / grants / route / meter│ no public IP, no port forwarding needed
28
+ └─────────────────────────────┘
29
+ ```
30
+
31
+ - **Grant-based trust**: consumers can only use aliases explicitly granted to them. No payments, no marketplace.
32
+ - **Namespaced aliases**: `peng/gpt-4o` is globally unique with one owner — routing is a deterministic lookup.
33
+ - v1 relays **native transparent SSE** for OpenAI↔OpenAI (chat completions and Responses), Anthropic↔Anthropic. No cross-protocol conversion, no smart routing, no web console.
34
+
35
+ ## Trust boundary (read this first)
36
+
37
+ - To route and meter, **consumer prompts and model responses transit the hub in plaintext — this is not end-to-end encryption**. The hub persists no request/response content, but the hub operator can technically see it. Only use a hub instance you trust — which is why the hub is open source and self-hostable.
38
+ - Upstream API keys never leave the producer's device and are never sent to consumers; the hub database stores only SHA-256 hashes of tokens.
39
+
40
+ ### Compliance and disclaimer
41
+
42
+ - aweshare is relay software: it cannot and does not judge whether you are allowed to share a given upstream key or subscription — that question is between you and the upstream provider. Being able to call an API yourself does not mean you may resell or re-provide it to third parties.
43
+ - Before sharing anything, read the upstream's terms (account rules, subscription and seat limits, forwarding, commercial-use clauses). Sharing a personal-subscription key — coding plans included — with third parties likely violates those terms; self-hosted open models have no such issue. **When in doubt, don't share.**
44
+ - The producer bears the consequences of sharing (key revocation, account suspension or termination by the upstream). The hub operator is responsible for operating the hub lawfully and for informing consumers of the plaintext-transit boundary above.
45
+ - The software is provided "as is" under the [MIT license](./LICENSE), without warranty of any kind. The authors and contributors are not liable for how aweshare is used or for any damage arising from sharing access through it.
46
+
47
+ ## Quickstart
48
+
49
+ Published as [`aweshare`](https://www.npmjs.com/package/aweshare) on npm (requires Node ≥ 22) and as a Docker image (`ghcr.io/mugpeng/aweshare`). No clone needed.
50
+
51
+ ### 1. Start the hub (operator, one VPS)
52
+
53
+ **npm** (simplest):
54
+
55
+ ```bash
56
+ npm install -g aweshare
57
+ aweshare hub init # data in ~/.aweshare-hub; prints the admin token — save it
58
+ aweshare hub serve # listens on :8787 (put Caddy/nginx TLS in front)
59
+ ```
60
+
61
+ **docker**:
62
+
63
+ ```bash
64
+ docker run -d --name aweshare-hub --restart unless-stopped \
65
+ -p 127.0.0.1:8787:8787 -v "$PWD/data:/data" ghcr.io/mugpeng/aweshare:latest
66
+ docker exec aweshare-hub node apps/hub/dist/cli.js init # first run: prints the admin token, save it
67
+ ```
68
+
69
+ Then issue tokens (admin token in hand):
70
+
71
+ ```bash
72
+ aweshare hub token issue --role producer --name peng # → asp_..., give to the producer
73
+ aweshare hub token issue --role consumer --name alice # → asc_..., give to the consumer
74
+ ```
75
+
76
+ The producer's `name` becomes their alias namespace (the `peng/` in `peng/gpt-4o`).
77
+
78
+ ### 2. Producer first run (in this order)
79
+
80
+ ```bash
81
+ npm install -g aweshare # ⓪ once, on the producer machine (Node ≥ 22)
82
+
83
+ # ① init: writes ~/.aweshare/config.toml + secrets.json (0600)
84
+ aweshare agent init --hub https://hub.example.com --token asp_...
85
+
86
+ # ② Edit the config (see below); put upstream keys in secrets.json — they never leave this machine
87
+
88
+ # ③ doctor: pre-flight checks, ordered to find the first failing link
89
+ aweshare agent doctor
90
+
91
+ # ④ Grant a consumer
92
+ aweshare agent grant --alias peng/qwen2.5.7b --consumer alice
93
+ # time-limited trial: add --expires-in 7d (re-granting refreshes the expiry)
94
+
95
+ # ⑤ Start (long-running; when it stops, aliases go offline and consumers get 503)
96
+ aweshare agent start
97
+ ```
98
+
99
+ ### 3. Consumer first run (in this order)
100
+
101
+ ```bash
102
+ # ① one small curl to prove the path
103
+ curl https://hub.example.com/v1/chat/completions \
104
+ -H "Authorization: Bearer asc_..." -H "content-type: application/json" \
105
+ -d '{"model":"peng/qwen2.5.7b","messages":[{"role":"user","content":"ping"}]}'
106
+
107
+ # ② configure your tool (below) → run one minimal task
108
+ # ③ check usage: aweshare hub usage --alias peng/qwen2.5.7b
109
+ # ④ only then move to real workloads
110
+ ```
111
+
112
+ ## Consumer tool configuration
113
+
114
+ **OpenAI SDK / any OpenAI-compatible tool**
115
+
116
+ ```ts
117
+ const client = new OpenAI({ baseURL: 'https://hub.example.com/v1', apiKey: 'asc_...' })
118
+ await client.chat.completions.create({ model: 'peng/gpt-4o', messages: [...] })
119
+ ```
120
+
121
+ **Claude Code** (the key is the `asc_` consumer key — **not** any upstream x-api-key)
122
+
123
+ ```bash
124
+ export ANTHROPIC_BASE_URL=https://hub.example.com
125
+ export ANTHROPIC_API_KEY=asc_...
126
+ claude --model peng/sonnet
127
+ ```
128
+
129
+ If Claude Code has a stale OAuth login it overrides env config — switch with `/login` or clean stored credentials.
130
+
131
+ **Codex** (the default Responses wire protocol works — the alias must be backed by a `responses`-protocol offering; `wire_api = "chat"` against an `openai`-protocol offering also works)
132
+
133
+ ```toml
134
+ [model_providers.aweshare]
135
+ base_url = "https://hub.example.com/v1"
136
+ ```
137
+
138
+ **Discovering models**: `GET /v1/models` (OpenAI SDK `client.models.list()`) returns every alias granted to the key, with online status.
139
+
140
+ ## Producer config reference (~/.aweshare/config.toml)
141
+
142
+ ```toml
143
+ hubUrl = "https://hub.example.com"
144
+ token = "asp_..."
145
+
146
+ [[backends]]
147
+ id = "ollama"
148
+ protocol = "openai" # openai-style baseUrl includes /v1 (SDK convention)
149
+ baseUrl = "http://127.0.0.1:11434/v1"
150
+
151
+ [[backends]]
152
+ id = "anthropic-main"
153
+ protocol = "anthropic" # anthropic-style baseUrl excludes /v1 (agent adds it)
154
+ baseUrl = "https://api.anthropic.com"
155
+ keyRef = "anthropic-key" # key lives in secrets.json under this name
156
+
157
+ [[backends]]
158
+ id = "glm-responses"
159
+ protocol = "responses" # responses-style baseUrl includes the version path
160
+ baseUrl = "https://open.bigmodel.cn/api/v1"
161
+ keyRef = "glm-key" # e.g. a GLM coding-plan key (Codex-ready)
162
+
163
+ [[offerings]]
164
+ alias = "peng/qwen2.5.7b" # namespace must be your producer name
165
+ backend = "ollama"
166
+ upstreamModel = "qwen2.5:7b" # the real backend id (full tag from `ollama list`)
167
+ maxConcurrency = 1 # start at 1 for local models; raise for cloud APIs
168
+ ```
169
+
170
+ Key hygiene: use dedicated, least-privilege, revocable keys with budget alerts; keep `secrets.json` at 0600 and out of git/screenshots; rotate on suspected leaks. Before sharing, check the upstream's terms: account rules, subscription limits, forwarding and commercial-use constraints.
171
+
172
+ ## Consumer limits (hub-wide defaults + per-consumer overrides)
173
+
174
+ Every consumer gets the hub-wide defaults (`AWESHARE_CONSUMER_RPS` / `BURST` / `CONCURRENCY`, see Operations). On top of that, the hub admin can set **sparse per-consumer overrides** — only the keys you set take effect, everything else keeps the defaults:
175
+
176
+ ```bash
177
+ aweshare hub consumer limits --name alice # show current overrides
178
+ aweshare hub consumer limits --name alice --tpm 60000 --max-total-tokens 5000000
179
+ aweshare hub consumer limits --name alice --rps 2 # later calls merge, not replace
180
+ aweshare hub consumer limits --name alice --clear # back to hub-wide defaults
181
+ ```
182
+
183
+ | Key | Meaning | Enforcement |
184
+ |---|---|---|
185
+ | `rps` / `burst` / `maxConcurrent` | override the hub-wide rate/inflight defaults for this consumer | 429 `RATE_LIMITED` |
186
+ | `tpm` | max tokens (prompt + completion) in any sliding 60s window | 429 `RATE_LIMITED` (in-memory window, like the RPS bucket) |
187
+ | `maxTotalTokens` | lifetime token budget for this consumer | 429 `QUOTA_EXCEEDED` (sums `usage_events`) |
188
+
189
+ Grants can also carry an expiry: `aweshare hub grant add --alias peng/gpt-4o --consumer alice --expires-in 7d` (or `aweshare agent grant … --expires-in 7d` on the producer side). An expired grant returns `403 GRANT_EXPIRED`; re-granting refreshes the expiry.
190
+
191
+ Honest limits: token-based caps count what upstreams report — Ollama streams report no usage, so they contribute 0. TPM is best-effort (concurrent requests that all pass before any finishes can overshoot); the lifetime budget is exact because it sums persisted rows.
192
+
193
+ ## Endpoints and errors
194
+
195
+ | Endpoint | Purpose |
196
+ |---|---|
197
+ | `POST /v1/chat/completions` · `POST /v1/messages` · `POST /v1/responses` | inference (Bearer or `x-api-key`) |
198
+ | `GET /v1/models` | aliases visible to this key, with status |
199
+ | `GET /healthz` | liveness |
200
+ | `/admin/v1/*` | token/grant/usage management (admin or producer token) · consumer limit overrides: `GET`/`PUT`/`DELETE /admin/v1/consumers/{name}/limits` (admin only) |
201
+
202
+ Error semantics: `401` invalid key · `403` not granted or `GRANT_EXPIRED` · `404` unknown alias · `400 PROTOCOL_MISMATCH` protocol/alias mismatch · `429` rate limit, TPM or producer concurrency cap (`QUOTA_EXCEEDED` = lifetime token budget hit) · `502` upstream/tunnel failure (upstream 4xx/5xx passes through verbatim) · `503` producer offline / backend degraded · `504` timeout. Errors carry `{error:{code,message,requestId}}`; the requestId spans both sides' logs.
203
+
204
+ Usage metering: one row per request (alias, real model, status, duration, byte counts, best-effort token counts), **zero content stored**. Producers list grants with `aweshare agent list`; query usage with `aweshare hub usage`.
205
+
206
+ ## Operations
207
+
208
+ | Env var | Default | Purpose |
209
+ |---|---|---|
210
+ | `AWESHARE_HUB_DATA_DIR` | `~/.aweshare-hub` | data dir (SQLite/pepper/admin token; volume-mount = backup) |
211
+ | `AWESHARE_HUB_PORT` / `HOST` | 8787 / 0.0.0.0 | listen address |
212
+ | `AWESHARE_CONSUMER_RPS` / `BURST` / `CONCURRENCY` | 10 / 20 / 8 | per-consumer limits |
213
+ | `AWESHARE_HEAD_TIMEOUT_MS` / `IDLE_TIMEOUT_MS` | 120000 / 300000 | response-head timeout / stream idle timeout |
214
+ | `AWESHARE_MAX_BODY_BYTES` | 32MB | request body cap |
215
+
216
+ Health: agent heartbeats every 15s, silent 45s = dead; backends with 2 consecutive AUTH/QUOTA failures auto-degrade (alias shows `degraded`, dispatch stops), 30s probes recover. A new connection with the same producer token replaces the old one (latest-wins).
217
+
218
+ ## Development
219
+
220
+ ```bash
221
+ pnpm install
222
+ pnpm test # 98 tests: protocol / hub contract (fake agent vs real hub) / agent unit / e2e (real SDKs)
223
+ pnpm build # tsc -b, whole monorepo
224
+ pnpm check # biome
225
+ ```
226
+
227
+ To run the CLIs from a source checkout without `node apps/.../dist/cli.js`, link them once after building:
228
+
229
+ ```bash
230
+ npm link # or: pnpm link --global — exposes the single `aweshare` bin
231
+ aweshare hub serve
232
+ aweshare agent doctor
233
+ ```
234
+
235
+ Releasing: push a `v*` tag with a matching `## [x.y.z]` section in `docs/CHANGELOG.md`; CI publishes `aweshare-protocol` + `aweshare` to npm (needs the `NPM_TOKEN` secret) and the Docker image to `ghcr.io/mugpeng/aweshare`.
236
+
237
+ Layout: `packages/protocol` (shared wire protocol) · `apps/hub` (HTTP+WS+SQLite+CLI) · `apps/agent` (CLI). Design docs live in `docs/specs/`; the changelog in `docs/CHANGELOG.md`; contribution scope in [CONTRIBUTING.md](./CONTRIBUTING.md).
238
+
239
+ ## Known limitations (v1)
240
+
241
+ - No cross-protocol conversion: an alias speaks exactly one wire (openai chat, anthropic messages, or openai responses).
242
+ - Ollama streams carry no usage → token counts recorded as NULL (best effort by design).
243
+ - Single hub instance + SQLite; no horizontal scaling.
244
+ - Corporate proxies may block the WebSocket tunnel (environmental limit).
245
+
246
+ MIT License.
@@ -0,0 +1,15 @@
1
+ import type { RequestStartMessage } from 'aweshare-protocol';
2
+ import type { Backend } from './config.js';
3
+ export interface ResolvedBackend extends Backend {
4
+ apiKey?: string;
5
+ }
6
+ export interface UpstreamRequest {
7
+ url: string;
8
+ headers: Record<string, string>;
9
+ }
10
+ /**
11
+ * Rebuild the upstream request from the tunnel message.
12
+ * The hub already stripped consumer credentials; the upstream key is
13
+ * injected here and nowhere else.
14
+ */
15
+ export declare function buildUpstreamRequest(backend: ResolvedBackend, msg: RequestStartMessage): UpstreamRequest;
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Rebuild the upstream request from the tunnel message.
3
+ * The hub already stripped consumer credentials; the upstream key is
4
+ * injected here and nowhere else.
5
+ */
6
+ export function buildUpstreamRequest(backend, msg) {
7
+ const base = backend.baseUrl.replace(/\/+$/, '');
8
+ // anthropic baseUrl excludes /v1 (SDK convention); openai/responses baseUrl already has it
9
+ const prefix = backend.protocol === 'anthropic' ? '/v1' : '';
10
+ const url = new URL(base + prefix + msg.path);
11
+ for (const [key, value] of Object.entries(msg.query ?? {})) {
12
+ url.searchParams.set(key, value);
13
+ }
14
+ const headers = { ...msg.headers };
15
+ if (backend.protocol === 'anthropic') {
16
+ if (backend.apiKey)
17
+ headers['x-api-key'] = backend.apiKey;
18
+ headers['anthropic-version'] = headers['anthropic-version'] ?? '2023-06-01';
19
+ }
20
+ else if (backend.apiKey) {
21
+ headers.authorization = `Bearer ${backend.apiKey}`;
22
+ }
23
+ return { url: url.toString(), headers };
24
+ }
25
+ //# sourceMappingURL=adapters.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapters.js","sourceRoot":"","sources":["../src/adapters.ts"],"names":[],"mappings":"AAYA;;;;GAIG;AACH,MAAM,UAAU,oBAAoB,CAClC,OAAwB,EACxB,GAAwB;IAExB,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAA;IAChD,2FAA2F;IAC3F,MAAM,MAAM,GAAG,OAAO,CAAC,QAAQ,KAAK,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAA;IAC5D,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,IAAI,GAAG,MAAM,GAAG,GAAG,CAAC,IAAI,CAAC,CAAA;IAC7C,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,IAAI,EAAE,CAAC,EAAE,CAAC;QAC3D,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAA;IAClC,CAAC;IAED,MAAM,OAAO,GAA2B,EAAE,GAAG,GAAG,CAAC,OAAO,EAAE,CAAA;IAC1D,IAAI,OAAO,CAAC,QAAQ,KAAK,WAAW,EAAE,CAAC;QACrC,IAAI,OAAO,CAAC,MAAM;YAAE,OAAO,CAAC,WAAW,CAAC,GAAG,OAAO,CAAC,MAAM,CAAA;QACzD,OAAO,CAAC,mBAAmB,CAAC,GAAG,OAAO,CAAC,mBAAmB,CAAC,IAAI,YAAY,CAAA;IAC7E,CAAC;SAAM,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;QAC1B,OAAO,CAAC,aAAa,GAAG,UAAU,OAAO,CAAC,MAAM,EAAE,CAAA;IACpD,CAAC;IACD,OAAO,EAAE,GAAG,EAAE,GAAG,CAAC,QAAQ,EAAE,EAAE,OAAO,EAAE,CAAA;AACzC,CAAC"}
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
@@ -0,0 +1,175 @@
1
+ #!/usr/bin/env node
2
+ import { existsSync, readFileSync } from 'node:fs';
3
+ import { join } from 'node:path';
4
+ import pino from 'pino';
5
+ import { agentDir, CONFIG_TEMPLATE, loadAgentConfig, SECRETS_TEMPLATE, writeFileAtomic, } from './config.js';
6
+ import { AgentConnection } from './connection.js';
7
+ import { runDoctor } from './doctor.js';
8
+ const VERSION = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8')).version;
9
+ const USAGE = `aweshare agent — share local/authorized AI capacity through an aweshare hub
10
+
11
+ Usage:
12
+ aweshare agent init [--hub URL] [--token asp_...] write config template + empty secrets
13
+ aweshare agent start connect, register offerings, relay
14
+ aweshare agent doctor pre-flight checks (direct replay first, hub last)
15
+ aweshare agent grant --alias ALIAS --consumer NAME [--expires-in 7d|12h|30m|90s]
16
+ aweshare agent revoke --alias ALIAS --consumer NAME
17
+ aweshare agent list list grants for your namespace
18
+
19
+ Environment:
20
+ AWESHARE_AGENT_DIR config directory (default ~/.aweshare)`;
21
+ function parseFlags(argv) {
22
+ const positional = [];
23
+ const flags = new Map();
24
+ for (let i = 0; i < argv.length; i++) {
25
+ const a = argv[i];
26
+ if (a.startsWith('--')) {
27
+ const eq = a.indexOf('=');
28
+ if (eq >= 0) {
29
+ flags.set(a.slice(2, eq), a.slice(eq + 1));
30
+ }
31
+ else if (i + 1 < argv.length && !argv[i + 1].startsWith('--')) {
32
+ flags.set(a.slice(2), argv[++i]);
33
+ }
34
+ else {
35
+ flags.set(a.slice(2), 'true');
36
+ }
37
+ }
38
+ else {
39
+ positional.push(a);
40
+ }
41
+ }
42
+ return { positional, flags };
43
+ }
44
+ function fail(message) {
45
+ console.error(`error: ${message}`);
46
+ process.exit(1);
47
+ }
48
+ /** Node fetch reports "fetch failed" without the reason; surface the cause. */
49
+ function errorMessage(err) {
50
+ if (err instanceof Error) {
51
+ const cause = err.cause;
52
+ return cause ? `${err.message} (${cause.code ?? cause.message})` : err.message;
53
+ }
54
+ return String(err);
55
+ }
56
+ /** Parse a human duration like 90s, 30m, 12h, 7d into milliseconds. */
57
+ function parseDuration(raw) {
58
+ const m = /^(\d+)([smhd])$/.exec(raw);
59
+ if (!m)
60
+ fail(`--expires-in must look like 90s, 30m, 12h or 7d, got '${raw}'`);
61
+ const unit = { s: 1000, m: 60_000, h: 3_600_000, d: 86_400_000 }[m[2]];
62
+ return Number(m[1]) * unit;
63
+ }
64
+ async function main() {
65
+ const [cmd, ...rest] = process.argv.slice(2);
66
+ const { flags } = parseFlags(rest);
67
+ if (cmd === '-v' || cmd === '--version') {
68
+ console.log(`aweshare agent ${VERSION}`);
69
+ return;
70
+ }
71
+ if (!cmd || cmd === 'help' || cmd === '--help' || cmd === '-h' || flags.get('help') === 'true') {
72
+ console.log(USAGE);
73
+ return;
74
+ }
75
+ const dir = agentDir();
76
+ switch (cmd) {
77
+ case 'init': {
78
+ const configPath = join(dir, 'config.toml');
79
+ const secretsPath = join(dir, 'secrets.json');
80
+ if (!existsSync(configPath)) {
81
+ let template = CONFIG_TEMPLATE;
82
+ if (flags.get('hub')) {
83
+ template = template.replace('hubUrl = "http://127.0.0.1:8787"', `hubUrl = "${flags.get('hub')}"`);
84
+ }
85
+ if (flags.get('token')) {
86
+ template = template.replace('token = "asp_PASTE_PRODUCER_TOKEN"', `token = "${flags.get('token')}"`);
87
+ }
88
+ writeFileAtomic(configPath, template, 0o600);
89
+ console.log(`wrote ${configPath}`);
90
+ }
91
+ else {
92
+ console.log(`exists, kept: ${configPath}`);
93
+ }
94
+ if (!existsSync(secretsPath)) {
95
+ writeFileAtomic(secretsPath, SECRETS_TEMPLATE, 0o600);
96
+ console.log(`wrote ${secretsPath}`);
97
+ }
98
+ else {
99
+ console.log(`exists, kept: ${secretsPath}`);
100
+ }
101
+ console.log('\nnext steps:');
102
+ console.log(' 1. edit config.toml: backends + offerings (namespace must be your producer name)');
103
+ console.log(' 2. put upstream keys in secrets.json (they never leave this machine)');
104
+ console.log(' 3. aweshare agent doctor # find the first failing link');
105
+ console.log(' 4. aweshare agent grant --alias YOU/model --consumer NAME');
106
+ console.log(' 5. aweshare agent start');
107
+ return;
108
+ }
109
+ case 'doctor': {
110
+ const report = await runDoctor(dir);
111
+ for (const check of report.checks) {
112
+ console.log(`${check.ok ? ' ok ' : 'FAIL '} ${check.name}: ${check.detail}`);
113
+ }
114
+ console.log(report.ok ? '\ndoctor: all green' : '\ndoctor: fix the first FAIL above, then re-run');
115
+ process.exitCode = report.ok ? 0 : 1;
116
+ return;
117
+ }
118
+ case 'start': {
119
+ const { config, secrets } = loadAgentConfig(dir);
120
+ const connection = new AgentConnection({
121
+ config,
122
+ secrets,
123
+ log: pino({ level: process.env.AWESHARE_LOG ?? 'info' }),
124
+ });
125
+ const shutdown = () => {
126
+ console.error('\nshutting down…');
127
+ void connection.stop().then(() => process.exit(0));
128
+ };
129
+ process.on('SIGINT', shutdown);
130
+ process.on('SIGTERM', shutdown);
131
+ await connection.start();
132
+ return;
133
+ }
134
+ case 'grant':
135
+ case 'revoke':
136
+ case 'list': {
137
+ const { config } = loadAgentConfig(dir);
138
+ const base = config.hubUrl;
139
+ const auth = { authorization: `Bearer ${config.token}`, 'content-type': 'application/json' };
140
+ if (cmd === 'grant' || cmd === 'revoke') {
141
+ const alias = flags.get('alias');
142
+ const consumer = flags.get('consumer');
143
+ if (!alias || !consumer)
144
+ fail('--alias and --consumer are required');
145
+ const body = { alias, consumer };
146
+ const expiresIn = flags.get('expires-in');
147
+ if (cmd === 'grant' && expiresIn) {
148
+ body.expiresAt = new Date(Date.now() + parseDuration(expiresIn)).toISOString();
149
+ }
150
+ const res = cmd === 'grant'
151
+ ? await fetch(`${base}/admin/v1/grants`, {
152
+ method: 'PUT',
153
+ headers: auth,
154
+ body: JSON.stringify(body),
155
+ })
156
+ : await fetch(`${base}/admin/v1/grants?alias=${encodeURIComponent(alias)}&consumer=${encodeURIComponent(consumer)}`, { method: 'DELETE', headers: auth });
157
+ const data = (await res.json().catch(() => ({})));
158
+ if (!res.ok)
159
+ fail(`${res.status} ${data.error?.message ?? res.statusText}`);
160
+ console.log(JSON.stringify(data));
161
+ return;
162
+ }
163
+ const res = await fetch(`${base}/admin/v1/grants`, { headers: auth });
164
+ const data = (await res.json().catch(() => ({})));
165
+ if (!res.ok)
166
+ fail(`${res.status} ${data.error?.message ?? res.statusText}`);
167
+ console.log(JSON.stringify(data, null, 2));
168
+ return;
169
+ }
170
+ default:
171
+ fail(`unknown command: ${cmd}\n\n${USAGE}`);
172
+ }
173
+ }
174
+ main().catch((err) => fail(errorMessage(err)));
175
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ import { type Protocol } from 'aweshare-protocol';
2
+ export interface Backend {
3
+ id: string;
4
+ protocol: Protocol;
5
+ /**
6
+ * Follows the SDK convention of the protocol:
7
+ * openai-style includes /v1 (e.g. http://127.0.0.1:11434/v1); anthropic-style
8
+ * excludes it (the agent appends /v1 itself); responses follows the openai
9
+ * convention (e.g. https://open.bigmodel.cn/api/v1).
10
+ */
11
+ baseUrl: string;
12
+ keyRef?: string;
13
+ }
14
+ export interface AgentOffering {
15
+ alias: string;
16
+ backend: string;
17
+ upstreamModel: string;
18
+ maxConcurrency: number;
19
+ }
20
+ export interface AgentConfig {
21
+ hubUrl: string;
22
+ token: string;
23
+ backends: Backend[];
24
+ offerings: AgentOffering[];
25
+ }
26
+ export declare function agentDir(env?: NodeJS.ProcessEnv): string;
27
+ export declare class ConfigError extends Error {
28
+ readonly problems: string[];
29
+ constructor(message: string, problems: string[]);
30
+ }
31
+ export declare function loadAgentConfig(dir: string): {
32
+ config: AgentConfig;
33
+ secrets: Record<string, string>;
34
+ };
35
+ /** tmp+rename atomic write with owner-only permissions. */
36
+ export declare function writeFileAtomic(path: string, content: string, mode?: number): void;
37
+ export declare const CONFIG_TEMPLATE = "# aweshare agent configuration (~/.aweshare/config.toml)\n# Secrets live in ~/.aweshare/secrets.json and never leave this machine.\n\nhubUrl = \"http://127.0.0.1:8787\"\ntoken = \"asp_PASTE_PRODUCER_TOKEN\"\n\n# Backends hold the upstream API. baseUrl follows the SDK convention:\n# openai-style (OpenAI/Ollama/vLLM/LM Studio) includes /v1, e.g. http://127.0.0.1:11434/v1\n# anthropic-style excludes /v1, e.g. https://api.anthropic.com\n# responses-style includes the version path, e.g. https://open.bigmodel.cn/api/v1\n[[backends]]\nid = \"ollama\"\nprotocol = \"openai\"\nbaseUrl = \"http://127.0.0.1:11434/v1\"\n# keyRef = \"ollama-key\" # optional; keys live in secrets.json\n\n[[backends]]\nid = \"openai\"\nprotocol = \"openai\"\nbaseUrl = \"https://api.openai.com/v1\"\nkeyRef = \"openai-key\"\n\n# Offerings map a public alias (namespace/name) to a backend model.\n# The namespace must match your producer name on the hub.\n[[offerings]]\nalias = \"YOUR_NAME/qwen2.5.7b\"\nbackend = \"ollama\"\nupstreamModel = \"qwen2.5:7b\" # must match 'ollama list' exactly, including the tag\nmaxConcurrency = 1 # start at 1 for local models\n\n[[offerings]]\nalias = \"YOUR_NAME/gpt-4o\"\nbackend = \"openai\"\nupstreamModel = \"gpt-4o-2024-11-20\"\nmaxConcurrency = 4\n";
38
+ export declare const SECRETS_TEMPLATE = "{\n \"openai-key\": \"sk-PASTE_YOUR_KEY\"\n}\n";