@tangle-network/tcloud 0.3.0 → 0.4.1

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
@@ -62,6 +62,40 @@ const answer = await client.ask('What is Tangle Network?') // string
62
62
  console.log(answer)
63
63
  ```
64
64
 
65
+ ### Quick Start — direct cli-bridge (subscription-backed coding harness)
66
+
67
+ When you have your own [cli-bridge](https://github.com/drewstone/cli-bridge) running (locally or on your own VPS), point the SDK straight at it. cli-bridge is OpenAI-compatible (`/v1/chat/completions`) so chat / ask / askStream work unchanged — and your CLI subscriptions on the bridge box pay for the LLM tokens directly (no router, no per-token billing).
68
+
69
+ ```bash
70
+ # 1. clone + run cli-bridge (one terminal)
71
+ gh repo clone drewstone/cli-bridge && cd cli-bridge
72
+ echo "BRIDGE_BEARER=$(openssl rand -hex 32)" >> .env.local
73
+ echo "BRIDGE_BACKENDS=claude,passthrough" >> .env.local
74
+ export $(grep -v '^#' .env.local | xargs) && pnpm exec tsx src/server.ts
75
+
76
+ # 2. authenticate your harness CLI
77
+ claude /login # or: kimi login, codex login, opencode auth login
78
+ ```
79
+
80
+ ```ts
81
+ import { TCloudClient } from '@tangle-network/tcloud'
82
+
83
+ const client = TCloudClient.fromCliBridge({
84
+ url: 'http://127.0.0.1:3344', // or any reachable URL
85
+ bearer: process.env.CLI_BRIDGE_BEARER!, // value of BRIDGE_BEARER from .env.local
86
+ })
87
+
88
+ // model id = `<harness>/<model>` — no `bridge/` prefix in direct mode
89
+ const reply = await client.ask('reply with OK', 'claude-code/sonnet')
90
+
91
+ // streaming + full chat work the same
92
+ for await (const chunk of client.askStream('write a haiku', 'kimi-code/kimi-for-coding')) {
93
+ process.stdout.write(chunk)
94
+ }
95
+ ```
96
+
97
+ See [`examples/14-direct-cli-bridge.ts`](./examples/14-direct-cli-bridge.ts) for the full pattern. For session-resumable agentic dispatches (file edits, multi-turn coding), see [`examples/12-bridge-sessions.ts`](./examples/12-bridge-sessions.ts) which uses the router-mediated `tcloud.bridge({...})` API.
98
+
65
99
  ### Model Selection
66
100
 
67
101
  Model is set at client creation. Override per-request when needed:
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  createShieldedClient,
3
3
  generateWallet
4
- } from "./chunk-ADGH2R2R.js";
4
+ } from "./chunk-A7AEPV2G.js";
5
5
  import {
6
6
  TCloudClient
7
- } from "./chunk-LN7XX5KG.js";
7
+ } from "./chunk-B22AH4JH.js";
8
8
 
9
9
  // src/index.ts
10
10
  var TCloud = class _TCloud extends TCloudClient {
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  TCloudClient
3
- } from "./chunk-LN7XX5KG.js";
3
+ } from "./chunk-B22AH4JH.js";
4
4
 
5
5
  // src/shielded.ts
6
6
  import { privateKeyToAccount } from "viem/accounts";
@@ -213,6 +213,7 @@ var PrivateRouter = class {
213
213
 
214
214
  // src/client.ts
215
215
  var DEFAULT_BASE_URL = "https://router.tangle.tools/v1";
216
+ var SDK_VERSION = "0.4.0";
216
217
  async function proxiedFetch(privacy, url, init, streaming) {
217
218
  if (!privacy || privacy.mode === "direct") {
218
219
  return fetch(url, init);
@@ -277,6 +278,37 @@ var TCloudClient = class _TCloudClient {
277
278
  _cachedOperators = [];
278
279
  _operatorsCachedAt = 0;
279
280
  static OPERATORS_TTL_MS = 5 * 60 * 1e3;
281
+ /**
282
+ * Build a client pointed directly at a cli-bridge instance — skips the
283
+ * Tangle Router entirely. cli-bridge serves the OpenAI-compatible
284
+ * `/v1/chat/completions` endpoint natively, so chat() / ask() /
285
+ * chatStream() work as-is against any local or remote bridge.
286
+ *
287
+ * Use this when you have your own cli-bridge running (locally or on
288
+ * your own VPS) and don't need router-side gating, billing, or
289
+ * observability — your CLI subscriptions on the bridge box pay for
290
+ * the LLM tokens directly.
291
+ *
292
+ * Wire form: model id is `<harness>/<model>` (e.g. `claude-code/sonnet`,
293
+ * `kimi-code/kimi-for-coding`) — no `bridge/` prefix needed in direct
294
+ * mode; cli-bridge accepts the harness id as the first path segment.
295
+ *
296
+ * ```ts
297
+ * const client = TCloudClient.fromCliBridge({
298
+ * url: 'http://127.0.0.1:3344',
299
+ * bearer: process.env.CLI_BRIDGE_BEARER!,
300
+ * })
301
+ * const reply = await client.ask('explain X', 'claude-code/sonnet')
302
+ * ```
303
+ *
304
+ * For session-resumable agentic dispatches (file edits, multi-turn
305
+ * coding), use the router-mediated `tcloud.bridge({...})` API instead
306
+ * (or POST to cli-bridge directly with `session_id` in the body).
307
+ */
308
+ static fromCliBridge(opts) {
309
+ const baseURL = opts.url.replace(/\/+$/, "") + "/v1";
310
+ return new _TCloudClient({ ...opts.config ?? {}, apiKey: opts.bearer, baseURL });
311
+ }
280
312
  constructor(config = {}) {
281
313
  this.baseURL = (config.baseURL || DEFAULT_BASE_URL).replace(/\/$/, "");
282
314
  this.platformURL = (config.platformURL || DEFAULT_PLATFORM_URL).replace(/\/$/, "");
@@ -288,7 +320,7 @@ var TCloudClient = class _TCloudClient {
288
320
  this.timeoutMs = config.timeout ?? DEFAULT_TIMEOUT_MS;
289
321
  this.headers = {
290
322
  "Content-Type": "application/json",
291
- "X-Tangle-Client": "tcloud-sdk/0.2.0"
323
+ "X-Tangle-Client": `tcloud-sdk/${SDK_VERSION}`
292
324
  };
293
325
  if (this.apiKey) {
294
326
  this.headers["Authorization"] = `Bearer ${this.apiKey}`;
@@ -585,7 +617,7 @@ var TCloudClient = class _TCloudClient {
585
617
  * call.
586
618
  *
587
619
  * ```ts
588
- * const kimi = tcloud.bridge({ harness: 'kimi', model: 'kimi-for-coding', unlock: UNLOCK, resume: 'pr-42' })
620
+ * const kimi = tcloud.bridge({ harness: 'kimi-code', model: 'kimi-for-coding', unlock: UNLOCK, resume: 'pr-42' })
589
621
  * await kimi.ask('review this diff…')
590
622
  * for await (const chunk of kimi.stream('continue…')) process.stdout.write(chunk)
591
623
  * ```
package/dist/cli.cjs CHANGED
@@ -241,6 +241,7 @@ var PrivateRouter = class {
241
241
 
242
242
  // src/client.ts
243
243
  var DEFAULT_BASE_URL = "https://router.tangle.tools/v1";
244
+ var SDK_VERSION = "0.4.0";
244
245
  async function proxiedFetch(privacy, url, init, streaming) {
245
246
  if (!privacy || privacy.mode === "direct") {
246
247
  return fetch(url, init);
@@ -305,6 +306,37 @@ var TCloudClient = class _TCloudClient {
305
306
  _cachedOperators = [];
306
307
  _operatorsCachedAt = 0;
307
308
  static OPERATORS_TTL_MS = 5 * 60 * 1e3;
309
+ /**
310
+ * Build a client pointed directly at a cli-bridge instance — skips the
311
+ * Tangle Router entirely. cli-bridge serves the OpenAI-compatible
312
+ * `/v1/chat/completions` endpoint natively, so chat() / ask() /
313
+ * chatStream() work as-is against any local or remote bridge.
314
+ *
315
+ * Use this when you have your own cli-bridge running (locally or on
316
+ * your own VPS) and don't need router-side gating, billing, or
317
+ * observability — your CLI subscriptions on the bridge box pay for
318
+ * the LLM tokens directly.
319
+ *
320
+ * Wire form: model id is `<harness>/<model>` (e.g. `claude-code/sonnet`,
321
+ * `kimi-code/kimi-for-coding`) — no `bridge/` prefix needed in direct
322
+ * mode; cli-bridge accepts the harness id as the first path segment.
323
+ *
324
+ * ```ts
325
+ * const client = TCloudClient.fromCliBridge({
326
+ * url: 'http://127.0.0.1:3344',
327
+ * bearer: process.env.CLI_BRIDGE_BEARER!,
328
+ * })
329
+ * const reply = await client.ask('explain X', 'claude-code/sonnet')
330
+ * ```
331
+ *
332
+ * For session-resumable agentic dispatches (file edits, multi-turn
333
+ * coding), use the router-mediated `tcloud.bridge({...})` API instead
334
+ * (or POST to cli-bridge directly with `session_id` in the body).
335
+ */
336
+ static fromCliBridge(opts) {
337
+ const baseURL = opts.url.replace(/\/+$/, "") + "/v1";
338
+ return new _TCloudClient({ ...opts.config ?? {}, apiKey: opts.bearer, baseURL });
339
+ }
308
340
  constructor(config = {}) {
309
341
  this.baseURL = (config.baseURL || DEFAULT_BASE_URL).replace(/\/$/, "");
310
342
  this.platformURL = (config.platformURL || DEFAULT_PLATFORM_URL).replace(/\/$/, "");
@@ -316,7 +348,7 @@ var TCloudClient = class _TCloudClient {
316
348
  this.timeoutMs = config.timeout ?? DEFAULT_TIMEOUT_MS;
317
349
  this.headers = {
318
350
  "Content-Type": "application/json",
319
- "X-Tangle-Client": "tcloud-sdk/0.2.0"
351
+ "X-Tangle-Client": `tcloud-sdk/${SDK_VERSION}`
320
352
  };
321
353
  if (this.apiKey) {
322
354
  this.headers["Authorization"] = `Bearer ${this.apiKey}`;
@@ -613,7 +645,7 @@ var TCloudClient = class _TCloudClient {
613
645
  * call.
614
646
  *
615
647
  * ```ts
616
- * const kimi = tcloud.bridge({ harness: 'kimi', model: 'kimi-for-coding', unlock: UNLOCK, resume: 'pr-42' })
648
+ * const kimi = tcloud.bridge({ harness: 'kimi-code', model: 'kimi-for-coding', unlock: UNLOCK, resume: 'pr-42' })
617
649
  * await kimi.ask('review this diff…')
618
650
  * for await (const chunk of kimi.stream('continue…')) process.stdout.write(chunk)
619
651
  * ```
package/dist/cli.js CHANGED
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  TCloud
4
- } from "./chunk-W7PUZZRE.js";
4
+ } from "./chunk-577KIKFA.js";
5
5
  import {
6
6
  generateWallet
7
- } from "./chunk-ADGH2R2R.js";
8
- import "./chunk-LN7XX5KG.js";
7
+ } from "./chunk-A7AEPV2G.js";
8
+ import "./chunk-B22AH4JH.js";
9
9
 
10
10
  // src/cli.ts
11
11
  import { Command } from "commander";
@@ -335,7 +335,7 @@ interface GatewayOptions {
335
335
  */
336
336
  interface BridgeOptions {
337
337
  /** Which harness to drive. Picks the backend on the bridge. */
338
- harness: 'claude' | 'claudish' | 'codex' | 'opencode' | 'kimi' | 'openai' | 'anthropic' | 'moonshot' | 'zai';
338
+ harness: 'claude-code' | 'claudish' | 'codex' | 'opencode' | 'kimi-code' | 'openai' | 'anthropic' | 'moonshot' | 'zai';
339
339
  /** Model id inside the harness (e.g. `sonnet`, `kimi-for-coding`, `gpt-5-codex`). Omit for harness default. */
340
340
  model?: string;
341
341
  /** Router-issued unlock token. Required unless operator has disabled the gate. */
@@ -640,6 +640,41 @@ declare class TCloudClient {
640
640
  private _cachedOperators;
641
641
  private _operatorsCachedAt;
642
642
  private static readonly OPERATORS_TTL_MS;
643
+ /**
644
+ * Build a client pointed directly at a cli-bridge instance — skips the
645
+ * Tangle Router entirely. cli-bridge serves the OpenAI-compatible
646
+ * `/v1/chat/completions` endpoint natively, so chat() / ask() /
647
+ * chatStream() work as-is against any local or remote bridge.
648
+ *
649
+ * Use this when you have your own cli-bridge running (locally or on
650
+ * your own VPS) and don't need router-side gating, billing, or
651
+ * observability — your CLI subscriptions on the bridge box pay for
652
+ * the LLM tokens directly.
653
+ *
654
+ * Wire form: model id is `<harness>/<model>` (e.g. `claude-code/sonnet`,
655
+ * `kimi-code/kimi-for-coding`) — no `bridge/` prefix needed in direct
656
+ * mode; cli-bridge accepts the harness id as the first path segment.
657
+ *
658
+ * ```ts
659
+ * const client = TCloudClient.fromCliBridge({
660
+ * url: 'http://127.0.0.1:3344',
661
+ * bearer: process.env.CLI_BRIDGE_BEARER!,
662
+ * })
663
+ * const reply = await client.ask('explain X', 'claude-code/sonnet')
664
+ * ```
665
+ *
666
+ * For session-resumable agentic dispatches (file edits, multi-turn
667
+ * coding), use the router-mediated `tcloud.bridge({...})` API instead
668
+ * (or POST to cli-bridge directly with `session_id` in the body).
669
+ */
670
+ static fromCliBridge(opts: {
671
+ /** cli-bridge base URL — `http://127.0.0.1:3344` for default local; can be any reachable URL. */
672
+ url: string;
673
+ /** BRIDGE_BEARER from the cli-bridge's `.env.local`. */
674
+ bearer: string;
675
+ /** Optional config passthrough (timeout, retry, etc). */
676
+ config?: Omit<TCloudConfig, 'apiKey' | 'baseURL'>;
677
+ }): TCloudClient;
643
678
  constructor(config?: TCloudConfig);
644
679
  /** Set the SpendAuth signer for private mode */
645
680
  setSpendAuthSigner(fn: () => Promise<SpendAuth>): void;
@@ -712,7 +747,7 @@ declare class TCloudClient {
712
747
  * call.
713
748
  *
714
749
  * ```ts
715
- * const kimi = tcloud.bridge({ harness: 'kimi', model: 'kimi-for-coding', unlock: UNLOCK, resume: 'pr-42' })
750
+ * const kimi = tcloud.bridge({ harness: 'kimi-code', model: 'kimi-for-coding', unlock: UNLOCK, resume: 'pr-42' })
716
751
  * await kimi.ask('review this diff…')
717
752
  * for await (const chunk of kimi.stream('continue…')) process.stdout.write(chunk)
718
753
  * ```
@@ -1048,7 +1083,7 @@ declare class TCloudClient {
1048
1083
  *
1049
1084
  * ```ts
1050
1085
  * const tcloud = new TCloudClient({ apiKey, baseURL: 'https://router.tangle.tools/api' })
1051
- * const kimi = tcloud.bridge({ harness: 'kimi', model: 'kimi-for-coding', unlock: UNLOCK, resume: 'pr-42' })
1086
+ * const kimi = tcloud.bridge({ harness: 'kimi-code', model: 'kimi-for-coding', unlock: UNLOCK, resume: 'pr-42' })
1052
1087
  *
1053
1088
  * // one-shot
1054
1089
  * const reply = await kimi.ask('summarize this diff')
@@ -335,7 +335,7 @@ interface GatewayOptions {
335
335
  */
336
336
  interface BridgeOptions {
337
337
  /** Which harness to drive. Picks the backend on the bridge. */
338
- harness: 'claude' | 'claudish' | 'codex' | 'opencode' | 'kimi' | 'openai' | 'anthropic' | 'moonshot' | 'zai';
338
+ harness: 'claude-code' | 'claudish' | 'codex' | 'opencode' | 'kimi-code' | 'openai' | 'anthropic' | 'moonshot' | 'zai';
339
339
  /** Model id inside the harness (e.g. `sonnet`, `kimi-for-coding`, `gpt-5-codex`). Omit for harness default. */
340
340
  model?: string;
341
341
  /** Router-issued unlock token. Required unless operator has disabled the gate. */
@@ -640,6 +640,41 @@ declare class TCloudClient {
640
640
  private _cachedOperators;
641
641
  private _operatorsCachedAt;
642
642
  private static readonly OPERATORS_TTL_MS;
643
+ /**
644
+ * Build a client pointed directly at a cli-bridge instance — skips the
645
+ * Tangle Router entirely. cli-bridge serves the OpenAI-compatible
646
+ * `/v1/chat/completions` endpoint natively, so chat() / ask() /
647
+ * chatStream() work as-is against any local or remote bridge.
648
+ *
649
+ * Use this when you have your own cli-bridge running (locally or on
650
+ * your own VPS) and don't need router-side gating, billing, or
651
+ * observability — your CLI subscriptions on the bridge box pay for
652
+ * the LLM tokens directly.
653
+ *
654
+ * Wire form: model id is `<harness>/<model>` (e.g. `claude-code/sonnet`,
655
+ * `kimi-code/kimi-for-coding`) — no `bridge/` prefix needed in direct
656
+ * mode; cli-bridge accepts the harness id as the first path segment.
657
+ *
658
+ * ```ts
659
+ * const client = TCloudClient.fromCliBridge({
660
+ * url: 'http://127.0.0.1:3344',
661
+ * bearer: process.env.CLI_BRIDGE_BEARER!,
662
+ * })
663
+ * const reply = await client.ask('explain X', 'claude-code/sonnet')
664
+ * ```
665
+ *
666
+ * For session-resumable agentic dispatches (file edits, multi-turn
667
+ * coding), use the router-mediated `tcloud.bridge({...})` API instead
668
+ * (or POST to cli-bridge directly with `session_id` in the body).
669
+ */
670
+ static fromCliBridge(opts: {
671
+ /** cli-bridge base URL — `http://127.0.0.1:3344` for default local; can be any reachable URL. */
672
+ url: string;
673
+ /** BRIDGE_BEARER from the cli-bridge's `.env.local`. */
674
+ bearer: string;
675
+ /** Optional config passthrough (timeout, retry, etc). */
676
+ config?: Omit<TCloudConfig, 'apiKey' | 'baseURL'>;
677
+ }): TCloudClient;
643
678
  constructor(config?: TCloudConfig);
644
679
  /** Set the SpendAuth signer for private mode */
645
680
  setSpendAuthSigner(fn: () => Promise<SpendAuth>): void;
@@ -712,7 +747,7 @@ declare class TCloudClient {
712
747
  * call.
713
748
  *
714
749
  * ```ts
715
- * const kimi = tcloud.bridge({ harness: 'kimi', model: 'kimi-for-coding', unlock: UNLOCK, resume: 'pr-42' })
750
+ * const kimi = tcloud.bridge({ harness: 'kimi-code', model: 'kimi-for-coding', unlock: UNLOCK, resume: 'pr-42' })
716
751
  * await kimi.ask('review this diff…')
717
752
  * for await (const chunk of kimi.stream('continue…')) process.stdout.write(chunk)
718
753
  * ```
@@ -1048,7 +1083,7 @@ declare class TCloudClient {
1048
1083
  *
1049
1084
  * ```ts
1050
1085
  * const tcloud = new TCloudClient({ apiKey, baseURL: 'https://router.tangle.tools/api' })
1051
- * const kimi = tcloud.bridge({ harness: 'kimi', model: 'kimi-for-coding', unlock: UNLOCK, resume: 'pr-42' })
1086
+ * const kimi = tcloud.bridge({ harness: 'kimi-code', model: 'kimi-for-coding', unlock: UNLOCK, resume: 'pr-42' })
1052
1087
  *
1053
1088
  * // one-shot
1054
1089
  * const reply = await kimi.ask('summarize this diff')
package/dist/index.cjs CHANGED
@@ -257,6 +257,7 @@ var PrivateRouter = class {
257
257
 
258
258
  // src/client.ts
259
259
  var DEFAULT_BASE_URL = "https://router.tangle.tools/v1";
260
+ var SDK_VERSION = "0.4.0";
260
261
  async function proxiedFetch(privacy, url, init, streaming) {
261
262
  if (!privacy || privacy.mode === "direct") {
262
263
  return fetch(url, init);
@@ -321,6 +322,37 @@ var TCloudClient = class _TCloudClient {
321
322
  _cachedOperators = [];
322
323
  _operatorsCachedAt = 0;
323
324
  static OPERATORS_TTL_MS = 5 * 60 * 1e3;
325
+ /**
326
+ * Build a client pointed directly at a cli-bridge instance — skips the
327
+ * Tangle Router entirely. cli-bridge serves the OpenAI-compatible
328
+ * `/v1/chat/completions` endpoint natively, so chat() / ask() /
329
+ * chatStream() work as-is against any local or remote bridge.
330
+ *
331
+ * Use this when you have your own cli-bridge running (locally or on
332
+ * your own VPS) and don't need router-side gating, billing, or
333
+ * observability — your CLI subscriptions on the bridge box pay for
334
+ * the LLM tokens directly.
335
+ *
336
+ * Wire form: model id is `<harness>/<model>` (e.g. `claude-code/sonnet`,
337
+ * `kimi-code/kimi-for-coding`) — no `bridge/` prefix needed in direct
338
+ * mode; cli-bridge accepts the harness id as the first path segment.
339
+ *
340
+ * ```ts
341
+ * const client = TCloudClient.fromCliBridge({
342
+ * url: 'http://127.0.0.1:3344',
343
+ * bearer: process.env.CLI_BRIDGE_BEARER!,
344
+ * })
345
+ * const reply = await client.ask('explain X', 'claude-code/sonnet')
346
+ * ```
347
+ *
348
+ * For session-resumable agentic dispatches (file edits, multi-turn
349
+ * coding), use the router-mediated `tcloud.bridge({...})` API instead
350
+ * (or POST to cli-bridge directly with `session_id` in the body).
351
+ */
352
+ static fromCliBridge(opts) {
353
+ const baseURL = opts.url.replace(/\/+$/, "") + "/v1";
354
+ return new _TCloudClient({ ...opts.config ?? {}, apiKey: opts.bearer, baseURL });
355
+ }
324
356
  constructor(config = {}) {
325
357
  this.baseURL = (config.baseURL || DEFAULT_BASE_URL).replace(/\/$/, "");
326
358
  this.platformURL = (config.platformURL || DEFAULT_PLATFORM_URL).replace(/\/$/, "");
@@ -332,7 +364,7 @@ var TCloudClient = class _TCloudClient {
332
364
  this.timeoutMs = config.timeout ?? DEFAULT_TIMEOUT_MS;
333
365
  this.headers = {
334
366
  "Content-Type": "application/json",
335
- "X-Tangle-Client": "tcloud-sdk/0.2.0"
367
+ "X-Tangle-Client": `tcloud-sdk/${SDK_VERSION}`
336
368
  };
337
369
  if (this.apiKey) {
338
370
  this.headers["Authorization"] = `Bearer ${this.apiKey}`;
@@ -629,7 +661,7 @@ var TCloudClient = class _TCloudClient {
629
661
  * call.
630
662
  *
631
663
  * ```ts
632
- * const kimi = tcloud.bridge({ harness: 'kimi', model: 'kimi-for-coding', unlock: UNLOCK, resume: 'pr-42' })
664
+ * const kimi = tcloud.bridge({ harness: 'kimi-code', model: 'kimi-for-coding', unlock: UNLOCK, resume: 'pr-42' })
633
665
  * await kimi.ask('review this diff…')
634
666
  * for await (const chunk of kimi.stream('continue…')) process.stdout.write(chunk)
635
667
  * ```
package/dist/index.d.cts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { ShieldedWallet, generateWallet } from './shielded.cjs';
2
2
  export { createShieldedClient, estimateCost, signSpendAuth } from './shielded.cjs';
3
- import { T as TCloudClient, a as TCloudConfig } from './client-DskWX_BT.cjs';
4
- export { A as ApiKeyInfo, b as AvatarGenerateRequest, c as AvatarGenerateResponse, d as AvatarJobStatus, e as AvatarResult, B as BatchJobResponse, f as BatchRequest, g as BridgeOptions, h as BridgeSession, C as ChatCompletion, i as ChatCompletionChunk, j as ChatMessage, k as ChatOptions, l as CompletionOptions, m as CompletionResponse, n as CreateKeyOptions, o as CreatedKey, p as CreditBalance, E as EmbeddingOptions, q as EmbeddingResponse, F as FineTuningJob, r as FineTuningJobOptions, G as GatewayOptions, I as ImageGenerateOptions, s as ImageResponse, J as JobEvent, M as Model, O as Operator, t as OperatorInfo, P as PricingTier, u as PrivacyConfig, v as PrivateRouter, w as PrivateRouterConfig, R as RerankOptions, x as RerankResponse, y as RetryConfig, z as RoutingConfig, D as RoutingStrategy, S as ShieldedConfig, H as SpendAuth, K as SpendingLimits, L as TCloudError, N as TierConfig, Q as TranscriptionResponse, U as UpdateKeyOptions, V as VideoGenerateOptions, W as VideoResponse, X as WatchJobOptions } from './client-DskWX_BT.cjs';
3
+ import { T as TCloudClient, a as TCloudConfig } from './client-C547pugt.cjs';
4
+ export { A as ApiKeyInfo, b as AvatarGenerateRequest, c as AvatarGenerateResponse, d as AvatarJobStatus, e as AvatarResult, B as BatchJobResponse, f as BatchRequest, g as BridgeOptions, h as BridgeSession, C as ChatCompletion, i as ChatCompletionChunk, j as ChatMessage, k as ChatOptions, l as CompletionOptions, m as CompletionResponse, n as CreateKeyOptions, o as CreatedKey, p as CreditBalance, E as EmbeddingOptions, q as EmbeddingResponse, F as FineTuningJob, r as FineTuningJobOptions, G as GatewayOptions, I as ImageGenerateOptions, s as ImageResponse, J as JobEvent, M as Model, O as Operator, t as OperatorInfo, P as PricingTier, u as PrivacyConfig, v as PrivateRouter, w as PrivateRouterConfig, R as RerankOptions, x as RerankResponse, y as RetryConfig, z as RoutingConfig, D as RoutingStrategy, S as ShieldedConfig, H as SpendAuth, K as SpendingLimits, L as TCloudError, N as TierConfig, Q as TranscriptionResponse, U as UpdateKeyOptions, V as VideoGenerateOptions, W as VideoResponse, X as WatchJobOptions } from './client-C547pugt.cjs';
5
5
  export { AgentProfile, AgentProfileCapabilities, AgentProfileMcpServer, AgentProfileModelHints, AgentProfilePermissionValue, AgentProfilePrompt, AgentProfileResources } from '@tangle-network/sandbox';
6
6
  import 'viem';
7
7
 
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { ShieldedWallet, generateWallet } from './shielded.js';
2
2
  export { createShieldedClient, estimateCost, signSpendAuth } from './shielded.js';
3
- import { T as TCloudClient, a as TCloudConfig } from './client-DskWX_BT.js';
4
- export { A as ApiKeyInfo, b as AvatarGenerateRequest, c as AvatarGenerateResponse, d as AvatarJobStatus, e as AvatarResult, B as BatchJobResponse, f as BatchRequest, g as BridgeOptions, h as BridgeSession, C as ChatCompletion, i as ChatCompletionChunk, j as ChatMessage, k as ChatOptions, l as CompletionOptions, m as CompletionResponse, n as CreateKeyOptions, o as CreatedKey, p as CreditBalance, E as EmbeddingOptions, q as EmbeddingResponse, F as FineTuningJob, r as FineTuningJobOptions, G as GatewayOptions, I as ImageGenerateOptions, s as ImageResponse, J as JobEvent, M as Model, O as Operator, t as OperatorInfo, P as PricingTier, u as PrivacyConfig, v as PrivateRouter, w as PrivateRouterConfig, R as RerankOptions, x as RerankResponse, y as RetryConfig, z as RoutingConfig, D as RoutingStrategy, S as ShieldedConfig, H as SpendAuth, K as SpendingLimits, L as TCloudError, N as TierConfig, Q as TranscriptionResponse, U as UpdateKeyOptions, V as VideoGenerateOptions, W as VideoResponse, X as WatchJobOptions } from './client-DskWX_BT.js';
3
+ import { T as TCloudClient, a as TCloudConfig } from './client-C547pugt.js';
4
+ export { A as ApiKeyInfo, b as AvatarGenerateRequest, c as AvatarGenerateResponse, d as AvatarJobStatus, e as AvatarResult, B as BatchJobResponse, f as BatchRequest, g as BridgeOptions, h as BridgeSession, C as ChatCompletion, i as ChatCompletionChunk, j as ChatMessage, k as ChatOptions, l as CompletionOptions, m as CompletionResponse, n as CreateKeyOptions, o as CreatedKey, p as CreditBalance, E as EmbeddingOptions, q as EmbeddingResponse, F as FineTuningJob, r as FineTuningJobOptions, G as GatewayOptions, I as ImageGenerateOptions, s as ImageResponse, J as JobEvent, M as Model, O as Operator, t as OperatorInfo, P as PricingTier, u as PrivacyConfig, v as PrivateRouter, w as PrivateRouterConfig, R as RerankOptions, x as RerankResponse, y as RetryConfig, z as RoutingConfig, D as RoutingStrategy, S as ShieldedConfig, H as SpendAuth, K as SpendingLimits, L as TCloudError, N as TierConfig, Q as TranscriptionResponse, U as UpdateKeyOptions, V as VideoGenerateOptions, W as VideoResponse, X as WatchJobOptions } from './client-C547pugt.js';
5
5
  export { AgentProfile, AgentProfileCapabilities, AgentProfileMcpServer, AgentProfileModelHints, AgentProfilePermissionValue, AgentProfilePrompt, AgentProfileResources } from '@tangle-network/sandbox';
6
6
  import 'viem';
7
7
 
package/dist/index.js CHANGED
@@ -1,18 +1,18 @@
1
1
  import {
2
2
  TCloud
3
- } from "./chunk-W7PUZZRE.js";
3
+ } from "./chunk-577KIKFA.js";
4
4
  import {
5
5
  createShieldedClient,
6
6
  estimateCost,
7
7
  generateWallet,
8
8
  signSpendAuth
9
- } from "./chunk-ADGH2R2R.js";
9
+ } from "./chunk-A7AEPV2G.js";
10
10
  import {
11
11
  BridgeSession,
12
12
  PrivateRouter,
13
13
  TCloudClient,
14
14
  TCloudError
15
- } from "./chunk-LN7XX5KG.js";
15
+ } from "./chunk-B22AH4JH.js";
16
16
  export {
17
17
  BridgeSession,
18
18
  PrivateRouter,
package/dist/instance.cjs CHANGED
@@ -256,6 +256,7 @@ var PrivateRouter = class {
256
256
 
257
257
  // src/client.ts
258
258
  var DEFAULT_BASE_URL = "https://router.tangle.tools/v1";
259
+ var SDK_VERSION = "0.4.0";
259
260
  async function proxiedFetch(privacy, url, init, streaming) {
260
261
  if (!privacy || privacy.mode === "direct") {
261
262
  return fetch(url, init);
@@ -320,6 +321,37 @@ var TCloudClient = class _TCloudClient {
320
321
  _cachedOperators = [];
321
322
  _operatorsCachedAt = 0;
322
323
  static OPERATORS_TTL_MS = 5 * 60 * 1e3;
324
+ /**
325
+ * Build a client pointed directly at a cli-bridge instance — skips the
326
+ * Tangle Router entirely. cli-bridge serves the OpenAI-compatible
327
+ * `/v1/chat/completions` endpoint natively, so chat() / ask() /
328
+ * chatStream() work as-is against any local or remote bridge.
329
+ *
330
+ * Use this when you have your own cli-bridge running (locally or on
331
+ * your own VPS) and don't need router-side gating, billing, or
332
+ * observability — your CLI subscriptions on the bridge box pay for
333
+ * the LLM tokens directly.
334
+ *
335
+ * Wire form: model id is `<harness>/<model>` (e.g. `claude-code/sonnet`,
336
+ * `kimi-code/kimi-for-coding`) — no `bridge/` prefix needed in direct
337
+ * mode; cli-bridge accepts the harness id as the first path segment.
338
+ *
339
+ * ```ts
340
+ * const client = TCloudClient.fromCliBridge({
341
+ * url: 'http://127.0.0.1:3344',
342
+ * bearer: process.env.CLI_BRIDGE_BEARER!,
343
+ * })
344
+ * const reply = await client.ask('explain X', 'claude-code/sonnet')
345
+ * ```
346
+ *
347
+ * For session-resumable agentic dispatches (file edits, multi-turn
348
+ * coding), use the router-mediated `tcloud.bridge({...})` API instead
349
+ * (or POST to cli-bridge directly with `session_id` in the body).
350
+ */
351
+ static fromCliBridge(opts) {
352
+ const baseURL = opts.url.replace(/\/+$/, "") + "/v1";
353
+ return new _TCloudClient({ ...opts.config ?? {}, apiKey: opts.bearer, baseURL });
354
+ }
323
355
  constructor(config = {}) {
324
356
  this.baseURL = (config.baseURL || DEFAULT_BASE_URL).replace(/\/$/, "");
325
357
  this.platformURL = (config.platformURL || DEFAULT_PLATFORM_URL).replace(/\/$/, "");
@@ -331,7 +363,7 @@ var TCloudClient = class _TCloudClient {
331
363
  this.timeoutMs = config.timeout ?? DEFAULT_TIMEOUT_MS;
332
364
  this.headers = {
333
365
  "Content-Type": "application/json",
334
- "X-Tangle-Client": "tcloud-sdk/0.2.0"
366
+ "X-Tangle-Client": `tcloud-sdk/${SDK_VERSION}`
335
367
  };
336
368
  if (this.apiKey) {
337
369
  this.headers["Authorization"] = `Bearer ${this.apiKey}`;
@@ -628,7 +660,7 @@ var TCloudClient = class _TCloudClient {
628
660
  * call.
629
661
  *
630
662
  * ```ts
631
- * const kimi = tcloud.bridge({ harness: 'kimi', model: 'kimi-for-coding', unlock: UNLOCK, resume: 'pr-42' })
663
+ * const kimi = tcloud.bridge({ harness: 'kimi-code', model: 'kimi-for-coding', unlock: UNLOCK, resume: 'pr-42' })
632
664
  * await kimi.ask('review this diff…')
633
665
  * for await (const chunk of kimi.stream('continue…')) process.stdout.write(chunk)
634
666
  * ```
@@ -1,4 +1,4 @@
1
- import { a as TCloudConfig, T as TCloudClient } from './client-DskWX_BT.cjs';
1
+ import { a as TCloudConfig, T as TCloudClient } from './client-C547pugt.cjs';
2
2
 
3
3
  /**
4
4
  * Instance — programmatic harness for spinning up a local Tangle dev environment.
@@ -1,4 +1,4 @@
1
- import { a as TCloudConfig, T as TCloudClient } from './client-DskWX_BT.js';
1
+ import { a as TCloudConfig, T as TCloudClient } from './client-C547pugt.js';
2
2
 
3
3
  /**
4
4
  * Instance — programmatic harness for spinning up a local Tangle dev environment.
package/dist/instance.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  TCloudClient
3
- } from "./chunk-LN7XX5KG.js";
3
+ } from "./chunk-B22AH4JH.js";
4
4
 
5
5
  // src/instance.ts
6
6
  import { spawn } from "child_process";
package/dist/shielded.cjs CHANGED
@@ -254,6 +254,7 @@ var PrivateRouter = class {
254
254
 
255
255
  // src/client.ts
256
256
  var DEFAULT_BASE_URL = "https://router.tangle.tools/v1";
257
+ var SDK_VERSION = "0.4.0";
257
258
  async function proxiedFetch(privacy, url, init, streaming) {
258
259
  if (!privacy || privacy.mode === "direct") {
259
260
  return fetch(url, init);
@@ -318,6 +319,37 @@ var TCloudClient = class _TCloudClient {
318
319
  _cachedOperators = [];
319
320
  _operatorsCachedAt = 0;
320
321
  static OPERATORS_TTL_MS = 5 * 60 * 1e3;
322
+ /**
323
+ * Build a client pointed directly at a cli-bridge instance — skips the
324
+ * Tangle Router entirely. cli-bridge serves the OpenAI-compatible
325
+ * `/v1/chat/completions` endpoint natively, so chat() / ask() /
326
+ * chatStream() work as-is against any local or remote bridge.
327
+ *
328
+ * Use this when you have your own cli-bridge running (locally or on
329
+ * your own VPS) and don't need router-side gating, billing, or
330
+ * observability — your CLI subscriptions on the bridge box pay for
331
+ * the LLM tokens directly.
332
+ *
333
+ * Wire form: model id is `<harness>/<model>` (e.g. `claude-code/sonnet`,
334
+ * `kimi-code/kimi-for-coding`) — no `bridge/` prefix needed in direct
335
+ * mode; cli-bridge accepts the harness id as the first path segment.
336
+ *
337
+ * ```ts
338
+ * const client = TCloudClient.fromCliBridge({
339
+ * url: 'http://127.0.0.1:3344',
340
+ * bearer: process.env.CLI_BRIDGE_BEARER!,
341
+ * })
342
+ * const reply = await client.ask('explain X', 'claude-code/sonnet')
343
+ * ```
344
+ *
345
+ * For session-resumable agentic dispatches (file edits, multi-turn
346
+ * coding), use the router-mediated `tcloud.bridge({...})` API instead
347
+ * (or POST to cli-bridge directly with `session_id` in the body).
348
+ */
349
+ static fromCliBridge(opts) {
350
+ const baseURL = opts.url.replace(/\/+$/, "") + "/v1";
351
+ return new _TCloudClient({ ...opts.config ?? {}, apiKey: opts.bearer, baseURL });
352
+ }
321
353
  constructor(config = {}) {
322
354
  this.baseURL = (config.baseURL || DEFAULT_BASE_URL).replace(/\/$/, "");
323
355
  this.platformURL = (config.platformURL || DEFAULT_PLATFORM_URL).replace(/\/$/, "");
@@ -329,7 +361,7 @@ var TCloudClient = class _TCloudClient {
329
361
  this.timeoutMs = config.timeout ?? DEFAULT_TIMEOUT_MS;
330
362
  this.headers = {
331
363
  "Content-Type": "application/json",
332
- "X-Tangle-Client": "tcloud-sdk/0.2.0"
364
+ "X-Tangle-Client": `tcloud-sdk/${SDK_VERSION}`
333
365
  };
334
366
  if (this.apiKey) {
335
367
  this.headers["Authorization"] = `Bearer ${this.apiKey}`;
@@ -626,7 +658,7 @@ var TCloudClient = class _TCloudClient {
626
658
  * call.
627
659
  *
628
660
  * ```ts
629
- * const kimi = tcloud.bridge({ harness: 'kimi', model: 'kimi-for-coding', unlock: UNLOCK, resume: 'pr-42' })
661
+ * const kimi = tcloud.bridge({ harness: 'kimi-code', model: 'kimi-for-coding', unlock: UNLOCK, resume: 'pr-42' })
630
662
  * await kimi.ask('review this diff…')
631
663
  * for await (const chunk of kimi.stream('continue…')) process.stdout.write(chunk)
632
664
  * ```
@@ -1,5 +1,5 @@
1
1
  import { Hex } from 'viem';
2
- import { a as TCloudConfig, T as TCloudClient, H as SpendAuth } from './client-DskWX_BT.cjs';
2
+ import { a as TCloudConfig, T as TCloudClient, H as SpendAuth } from './client-C547pugt.cjs';
3
3
 
4
4
  /**
5
5
  * tcloud/shielded — Ephemeral wallet generation, SpendAuth signing, private inference.
@@ -1,5 +1,5 @@
1
1
  import { Hex } from 'viem';
2
- import { a as TCloudConfig, T as TCloudClient, H as SpendAuth } from './client-DskWX_BT.js';
2
+ import { a as TCloudConfig, T as TCloudClient, H as SpendAuth } from './client-C547pugt.js';
3
3
 
4
4
  /**
5
5
  * tcloud/shielded — Ephemeral wallet generation, SpendAuth signing, private inference.
package/dist/shielded.js CHANGED
@@ -3,8 +3,8 @@ import {
3
3
  estimateCost,
4
4
  generateWallet,
5
5
  signSpendAuth
6
- } from "./chunk-ADGH2R2R.js";
7
- import "./chunk-LN7XX5KG.js";
6
+ } from "./chunk-A7AEPV2G.js";
7
+ import "./chunk-B22AH4JH.js";
8
8
  export {
9
9
  createShieldedClient,
10
10
  estimateCost,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tangle-network/tcloud",
3
- "version": "0.3.0",
3
+ "version": "0.4.1",
4
4
  "description": "TypeScript SDK and CLI for Tangle AI Cloud — decentralized LLM inference",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",