@tangle-network/cli-agent-registry 0.14.0 → 0.15.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 (35) hide show
  1. package/README.md +30 -0
  2. package/dist/{backend-types-CREj4iOY.mjs → backend-types-CNo_Zj_K.mjs} +3 -12
  3. package/dist/{backend-types-CJH-wHS3.d.mts → backend-types-DRmLR1e0.d.mts} +4 -13
  4. package/dist/backend-types.d.mts +1 -1
  5. package/dist/backend-types.mjs +1 -1
  6. package/dist/cli-auth-bundle-C6DtK7GX.mjs +95 -0
  7. package/dist/cli-auth-bundle-CwAaH0Ap.d.mts +51 -0
  8. package/dist/cli-auth-bundle.d.mts +2 -49
  9. package/dist/cli-auth-bundle.mjs +1 -91
  10. package/dist/cli-auth-placeholder.d.mts +1 -1
  11. package/dist/cli-auth-placeholder.mjs +2 -2
  12. package/dist/cli-backend-auth-env.mjs +3 -3
  13. package/dist/default-backend.d.mts +1 -1
  14. package/dist/default-backend.mjs +2 -2
  15. package/dist/{harness-DIdVNSwl.mjs → harness-D1fTxnDD.mjs} +66 -34
  16. package/dist/{native-session-contracts-DWFzgoye.mjs → harness-contracts-BZoECCMc.mjs} +87 -173
  17. package/dist/host-contracts.d.mts +30 -0
  18. package/dist/host-contracts.json +422 -0
  19. package/dist/host-contracts.mjs +63 -0
  20. package/dist/index.d.mts +117 -120
  21. package/dist/index.mjs +17 -12
  22. package/dist/local-cli-auth.d.mts +1 -1
  23. package/dist/local-cli-auth.mjs +1 -1
  24. package/dist/native-session-contracts.d.mts +57 -62
  25. package/dist/native-session-contracts.mjs +40 -2
  26. package/dist/servable-models.d.mts +5 -6
  27. package/dist/servable-models.mjs +6 -22
  28. package/dist/{session-contract-BC75JdnA.d.mts → session-contract-BhzcbPRW.d.mts} +10 -44
  29. package/dist/session-contract.d.mts +1 -1
  30. package/dist/session-contract.mjs +14 -62
  31. package/dist/{specs-BSELpX1h.d.mts → spec-CcvTM7-j.d.mts} +22 -91
  32. package/dist/{specs-Bbiay_8K.mjs → specs-BBF55TnM.mjs} +125 -94
  33. package/dist/specs.d.mts +72 -3
  34. package/dist/specs.mjs +2 -2
  35. package/package.json +15 -9
@@ -1,12 +1,12 @@
1
- import { t as HarnessSessionContract } from "./session-contract-BC75JdnA.mjs";
2
- import { SdkProviderAdapter, WellKnownInteractionKind, agentProfileSchema } from "@tangle-network/agent-interface";
1
+ import { t as HarnessSessionContract } from "./session-contract-BhzcbPRW.mjs";
2
+ import { SdkProviderAdapter, WellKnownInteractionKind } from "@tangle-network/agent-interface";
3
3
  import { HarnessModelSupport, HarnessModelSupportOptions } from "@tangle-network/agent-interface/harness-capabilities";
4
4
 
5
5
  //#region src/cli-dir-layout.d.ts
6
6
  /**
7
7
  * How a parked export reads a CLI's own directory (`.codex`, `.claude`, …)
8
8
  * beyond the session stores its contract declares. Globs are relative to that
9
- * directory, in the session-contract glob syntax (`*`, `**`).
9
+ * directory except `homeSessionData`, in session-contract glob syntax (`*`, `**`).
10
10
  *
11
11
  * - `sessionData`: what holds a user's session, to be exported as a
12
12
  * transcript is. Until the export carries it, it is missing, and the box is
@@ -24,8 +24,13 @@ import { HarnessModelSupport, HarnessModelSupportOptions } from "@tangle-network
24
24
  * version adds holds the box until it is classified here.
25
25
  */
26
26
  interface CliDirLayout {
27
+ /** Auxiliary session files relative to the owning runtime HOME, outside its CLI directory. */
28
+ homeSessionData: readonly string[];
27
29
  sessionData: readonly string[];
28
- configAllow: readonly string[];
30
+ configAllow: readonly (string | {
31
+ path: string;
32
+ kind: "symlink";
33
+ })[];
29
34
  credential: readonly string[];
30
35
  }
31
36
  /** What every CLI's directory is read with; a spec adds its own entries. */
@@ -155,8 +160,8 @@ declare function canonicalModelSlug(model: string | {
155
160
  } | undefined): string | undefined;
156
161
  /**
157
162
  * Whether a harness can run a model, read from the one capability table in
158
- * `@tangle-network/agent-interface`: vendor locks (kimi-code runs Moonshot
159
- * models) and pairs measured to fail on production. A refused pair is refused
163
+ * `@tangle-network/agent-interface`: pairs measured to fail on production
164
+ * (and any vendor lock it declares). A refused pair is refused
160
165
  * where it is chosen (create, run, an authored workflow action) with the
161
166
  * returned message, rather than provisioning a box whose first model call
162
167
  * fails. An absent model is the harness's own default and is always supported.
@@ -223,13 +228,11 @@ interface CliAgentRuntimeSpec {
223
228
  * (`input.disableTools`). Execution fails loudly for harnesses without it.
224
229
  */
225
230
  supportsToolDisabledTurns?: boolean;
226
- /**
227
- * The adapter accepts a host-env redaction hook and the sidecar MUST wire
228
- * its sanitizer into the adapter constructor so the agent process only
229
- * inherits sandbox-public vars, never internal platform secrets. The
230
- * binding fails closed if this declaration ever drifts off.
231
- */
231
+ /** Adapter accepts host-env redaction; Sidecar must bind its sanitizer,
232
+ * admitting sandbox-public vars only and failing closed if this drifts off. */
232
233
  redactsHostEnv?: boolean;
234
+ /** Native launch and MCP custody implement secret-profile UID/HOME isolation. */
235
+ secretProfileIsolation?: boolean;
233
236
  }
234
237
  /**
235
238
  * A tool the harness ships built in, surfaced verbatim on the sidecar's
@@ -322,6 +325,11 @@ interface CliAgentSpec {
322
325
  * starts on the Router when the caller brings no credential of its own.
323
326
  */
324
327
  callerCredentialOnly?: boolean;
328
+ /** A capability the harness needs and Tangle sandboxes lack: creates are refused. */
329
+ unavailable?: {
330
+ capability: "docker";
331
+ reason: string;
332
+ };
325
333
  }
326
334
  type AdapterFactory = (logger: ProviderLogger) => SdkProviderAdapter;
327
335
  /** Bounded provider startup spans, timed by the operation's owner. */
@@ -334,82 +342,5 @@ type ProviderLogger = {
334
342
  observePhase?: (phase: ProviderPhase, durationMs: number, scope?: "turn" | "prewarm") => void;
335
343
  };
336
344
  //#endregion
337
- //#region src/specs.d.ts
338
- /**
339
- * Env var naming a sandbox's selected backend. Stamped into every create env
340
- * by the orchestrator (`buildSidecarContainerConfig`); read by the sidecar's
341
- * backend resolution (`resolveConfiguredBackend`) and by the host-agent's
342
- * warm-claim env selection to pick which spec's env vars the rebind delivers.
343
- */
344
- declare const AGENT_BACKEND_ENV_VAR = "AGENT_BACKEND";
345
- /**
346
- * The managed-router model-key channel every backend shares: the box-side
347
- * value is always the salted proxy dummy (`proxy-model-token.<salt>`), which
348
- * the per-sandbox egress proxy swaps for the real budget-scoped key at the
349
- * network boundary. The opencode-derived NAME is pinned naming debt: FC
350
- * shared-snapshot salt recovery, resume re-key, and the egress proxy swap map
351
- * all key on this literal, so renaming it bricks managed-model auth
352
- * fleet-wide. Kept equal to the opencode spec's own apiKey declaration
353
- * (enforced by a registry test).
354
- */
355
- declare const MANAGED_MODEL_KEY_ENV_VAR = "OPENCODE_MODEL_API_KEY";
356
- /**
357
- * Caller-owned auth by reference: the NAME of the box env var (a stored
358
- * secret) that holds the provider's key. The orchestrator sets it only when it
359
- * injected no managed key; the sidecar composes the named provider on that
360
- * credential. A variable name, never a secret, so it may ride every channel a
361
- * create's env takes to the guest — the kernel cmdline and a warm-claim rebind.
362
- */
363
- declare const MANAGED_MODEL_KEY_NAME_ENV_VAR = "OPENCODE_MODEL_API_KEY_ENV";
364
- /**
365
- * Env var names declared across ALL registered harness specs, grouped by
366
- * their `CliAgentEnvVars` role. The ONE derivation every allowlist that must
367
- * track "what env names can a backend legitimately use" builds from — the
368
- * FC kernel-cmdline whitelist, the egress secret handling, the sidecar
369
- * terminal scrub, the SSH env forward, and the rebind union below. Deriving
370
- * from roles (not one flat set) lets each consumer apply its own security
371
- * policy per role: apiKey and oauthToken names are secret channels.
372
- * Native subscription tokens stay out of warm-claim delivery.
373
- */
374
- declare function cliAgentEnvVarNamesByRole(): {
375
- apiKey: ReadonlySet<string>;
376
- oauthToken: ReadonlySet<string>;
377
- model: ReadonlySet<string>;
378
- baseUrl: ReadonlySet<string>;
379
- authMode: ReadonlySet<string>;
380
- authFiles: ReadonlySet<string>;
381
- extras: ReadonlySet<string>;
382
- };
383
- /**
384
- * Union of every spec's `hostPassthroughEnvVars` — the operator tuning names
385
- * a host process (orchestrator system env, host-agent process env) may
386
- * forward into containers. Request/caller env always keeps precedence at the
387
- * host-agent boundary; the orchestrator system-env channel stays
388
- * operator-authoritative. Replaces the old `OPENCODE_*` prefix forward,
389
- * which leaked ANY stray host var with that prefix (model tuple and key
390
- * included) into every tenant.
391
- */
392
- declare function cliAgentHostPassthroughEnvVarNames(): ReadonlySet<string>;
393
- /**
394
- * Union of every env var name a warm-claim rebind may deliver, across all
395
- * registered harnesses. The ONE source both sides of the rebind derive from:
396
- * the host-agent selects its delivery from it and the sidecar rebind route
397
- * carves it out of the loader-control rejection, so the two can never drift
398
- * into "host delivers a name the sidecar 400s" — which silently cold-paths
399
- * every warm claim of that backend. Includes each spec's apiKey name because
400
- * acceptance is a superset of delivery: the HOST decides which key names are
401
- * safe to send (egress proxy-swap-covered only), while the sidecar must not
402
- * reject a name a valid host may deliver.
403
- */
404
- declare function claimDeliverableEnvVarNames(): ReadonlySet<string>;
405
- declare const CLI_AGENT_SPECS: readonly CliAgentSpec[];
406
- declare function getSpec(name: string): CliAgentSpec | undefined;
407
- /**
408
- * The directory, relative to a session's storage path, where a backend's
409
- * message log lives: the one value adapters, the sidecar and the parked
410
- * export read. Throws for a backend whose spec names none.
411
- */
412
- declare function messageStorageDirOf(name: string): string;
413
- //#endregion
414
- export { CliDirLayout as A, ProviderPhase as C, harnessModelSupportFor as D, cliAgentEnvRoleName as E, DEFAULT_CLI_DIR_LAYOUT as M, mergeCliDirLayout as N, harnessModelWire as O, ProviderLogger as S, cliAgentClaimEnvVarNames as T, CliAgentModelWire as _, agentProfileSchema as a, CliAuthHome as b, cliAgentHostPassthroughEnvVarNames as c, AdapterFactory as d, CliAgentBuiltinTool as f, CliAgentEnvVars as g, CliAgentEnvExtraRole as h, MANAGED_MODEL_KEY_NAME_ENV_VAR as i, CliDirLayoutAdditions as j, SYNTHETIC_ROUTER_MODEL as k, getSpec as l, CliAgentEnvExtraParser as m, CLI_AGENT_SPECS as n, claimDeliverableEnvVarNames as o, CliAgentEnvExtra as p, MANAGED_MODEL_KEY_ENV_VAR as r, cliAgentEnvVarNamesByRole as s, AGENT_BACKEND_ENV_VAR as t, messageStorageDirOf as u, CliAgentRuntimeSpec as v, canonicalModelSlug as w, HarnessSpecCapabilities as x, CliAgentSpec as y };
415
- //# sourceMappingURL=specs-BSELpX1h.d.mts.map
345
+ export { mergeCliDirLayout as C, DEFAULT_CLI_DIR_LAYOUT as S, harnessModelSupportFor as _, CliAgentEnvExtraRole as a, CliDirLayout as b, CliAgentRuntimeSpec as c, HarnessSpecCapabilities as d, ProviderLogger as f, cliAgentEnvRoleName as g, cliAgentClaimEnvVarNames as h, CliAgentEnvExtraParser as i, CliAgentSpec as l, canonicalModelSlug as m, CliAgentBuiltinTool as n, CliAgentEnvVars as o, ProviderPhase as p, CliAgentEnvExtra as r, CliAgentModelWire as s, AdapterFactory as t, CliAuthHome as u, harnessModelWire as v, CliDirLayoutAdditions as x, SYNTHETIC_ROUTER_MODEL as y };
346
+ //# sourceMappingURL=spec-CcvTM7-j.d.mts.map
@@ -1,5 +1,6 @@
1
- import { a as HARNESSES, r as NATIVE_SESSION_CONTRACTS } from "./native-session-contracts-DWFzgoye.mjs";
2
- import { n as BACKEND_TYPE } from "./backend-types-CREj4iOY.mjs";
1
+ import { t as HARNESSES } from "./harness-contracts-BZoECCMc.mjs";
2
+ import { NATIVE_SESSION_CONTRACTS } from "./native-session-contracts.mjs";
3
+ import { n as BACKEND_TYPE } from "./backend-types-CNo_Zj_K.mjs";
3
4
  import { agentProfileJsonSchema, agentProfileSchema } from "@tangle-network/agent-interface";
4
5
  import { z } from "zod";
5
6
  import { harnessModelSupport } from "@tangle-network/agent-interface/harness-capabilities";
@@ -53,8 +54,8 @@ function canonicalModelSlug(model) {
53
54
  }
54
55
  /**
55
56
  * Whether a harness can run a model, read from the one capability table in
56
- * `@tangle-network/agent-interface`: vendor locks (kimi-code runs Moonshot
57
- * models) and pairs measured to fail on production. A refused pair is refused
57
+ * `@tangle-network/agent-interface`: pairs measured to fail on production
58
+ * (and any vendor lock it declares). A refused pair is refused
58
59
  * where it is chosen (create, run, an authored workflow action) with the
59
60
  * returned message, rather than provisioning a box whose first model call
60
61
  * fails. An absent model is the harness's own default and is always supported.
@@ -103,24 +104,9 @@ z.globalRegistry.add(agentProfileSchema, {
103
104
  * warm-claim env selection to pick which spec's env vars the rebind delivers.
104
105
  */
105
106
  const AGENT_BACKEND_ENV_VAR = "AGENT_BACKEND";
106
- /**
107
- * The managed-router model-key channel every backend shares: the box-side
108
- * value is always the salted proxy dummy (`proxy-model-token.<salt>`), which
109
- * the per-sandbox egress proxy swaps for the real budget-scoped key at the
110
- * network boundary. The opencode-derived NAME is pinned naming debt: FC
111
- * shared-snapshot salt recovery, resume re-key, and the egress proxy swap map
112
- * all key on this literal, so renaming it bricks managed-model auth
113
- * fleet-wide. Kept equal to the opencode spec's own apiKey declaration
114
- * (enforced by a registry test).
115
- */
107
+ /** Salted proxy model key. The name OPENCODE_MODEL_API_KEY is load-bearing; do not rename it. */
116
108
  const MANAGED_MODEL_KEY_ENV_VAR = "OPENCODE_MODEL_API_KEY";
117
- /**
118
- * Caller-owned auth by reference: the NAME of the box env var (a stored
119
- * secret) that holds the provider's key. The orchestrator sets it only when it
120
- * injected no managed key; the sidecar composes the named provider on that
121
- * credential. A variable name, never a secret, so it may ride every channel a
122
- * create's env takes to the guest — the kernel cmdline and a warm-claim rebind.
123
- */
109
+ /** Name of the box env var holding a caller-owned provider key. A name, never a secret. */
124
110
  const MANAGED_MODEL_KEY_NAME_ENV_VAR = "OPENCODE_MODEL_API_KEY_ENV";
125
111
  /**
126
112
  * Env var names declared across ALL registered harness specs, grouped by
@@ -197,22 +183,40 @@ function claimDeliverableEnvVarNames() {
197
183
  ...roles.apiKey
198
184
  ]);
199
185
  }
186
+ const BASE_CAPABILITIES = {
187
+ streaming: true,
188
+ toolUse: true,
189
+ reasoning: true,
190
+ multimodal: false
191
+ };
192
+ /**
193
+ * claude-code is the only provider that demotes uid + forces HOME=/home/agent
194
+ * when the sidecar runs as root. All other CLIs inherit the sidecar HOME.
195
+ */
200
196
  const CLI_AGENT_SPECS = [
201
197
  {
202
198
  name: BACKEND_TYPE.OPENCODE,
203
199
  nativeSession: NATIVE_SESSION_CONTRACTS.opencode,
204
200
  messageStorageDir: ".opencode",
205
201
  cliDirLayout: {
206
- sessionData: ["snapshot/**"],
207
- configAllow: ["bin/**"]
202
+ sessionData: [
203
+ "snapshot/**",
204
+ "agent-system-prompt.md",
205
+ "profile-instructions.md"
206
+ ],
207
+ configAllow: [
208
+ "bin/**",
209
+ ".gitignore",
210
+ "log",
211
+ "log/opencode.log",
212
+ "repos"
213
+ ]
208
214
  },
209
215
  displayName: "OpenCode Agent",
210
216
  description: "OpenCode CLI coding agent with native sessions, profiles, tools, and MCP.",
211
217
  envVars: HARNESSES["opencode"].config.envVars,
212
218
  capabilities: {
213
- streaming: true,
214
- toolUse: true,
215
- reasoning: true,
219
+ ...BASE_CAPABILITIES,
216
220
  multimodal: true,
217
221
  contextWindow: 2e5,
218
222
  mcp: true,
@@ -314,10 +318,12 @@ const CLI_AGENT_SPECS = [
314
318
  runtime: HARNESSES["claude-code"].lifecycle.runtime,
315
319
  messageStorageDir: ".claude-code",
316
320
  cliDirLayout: {
321
+ homeSessionData: [".cache/claude-cli-nodejs/-*/mcp-logs-*/*.jsonl"],
317
322
  sessionData: [
318
323
  "plans/**",
319
324
  "file-history/**",
320
325
  "debug/**",
326
+ "projects/*/memory/**/*.md",
321
327
  "projects/*/*/subagents/**/*.meta.json",
322
328
  "projects/*/*/tool-results/**"
323
329
  ],
@@ -325,6 +331,7 @@ const CLI_AGENT_SPECS = [
325
331
  ".last-cleanup",
326
332
  "policy-limits.json*",
327
333
  "remote-settings.json",
334
+ "remote-settings.json.synced-at",
328
335
  "skills/**"
329
336
  ],
330
337
  credential: [
@@ -339,9 +346,7 @@ const CLI_AGENT_SPECS = [
339
346
  envVars: HARNESSES["claude-code"].config.envVars,
340
347
  modelWire: HARNESSES["claude-code"].config.modelWire,
341
348
  capabilities: {
342
- streaming: true,
343
- toolUse: true,
344
- reasoning: true,
349
+ ...BASE_CAPABILITIES,
345
350
  multimodal: true,
346
351
  contextWindow: 2e5,
347
352
  mcp: true,
@@ -377,13 +382,12 @@ const CLI_AGENT_SPECS = [
377
382
  nativeSession: NATIVE_SESSION_CONTRACTS["kimi-code"],
378
383
  runtime: HARNESSES["kimi-code"].lifecycle.runtime,
379
384
  messageStorageDir: ".kimi-code",
385
+ cliDirLayout: { credential: ["config.json"] },
380
386
  displayName: "Kimi Code",
381
387
  description: "Moonshot AI Kimi Code CLI — headless non-interactive mode via `kimi --print --output-format stream-json --prompt ...`. Defaults to OAuth (Kimi Code subscription) with credentials materialized from the host-managed ~/.kimi/credentials/kimi-code.json; falls back to MOONSHOT_API_KEY when an apiKey is supplied.",
382
388
  envVars: HARNESSES["kimi-code"].config.envVars,
383
389
  capabilities: {
384
- streaming: true,
385
- toolUse: true,
386
- reasoning: true,
390
+ ...BASE_CAPABILITIES,
387
391
  multimodal: true,
388
392
  contextWindow: 262144,
389
393
  mcp: false,
@@ -399,19 +403,56 @@ const CLI_AGENT_SPECS = [
399
403
  {
400
404
  name: BACKEND_TYPE.CODEX,
401
405
  nativeSession: NATIVE_SESSION_CONTRACTS.codex,
406
+ runtime: HARNESSES["codex"].lifecycle.runtime,
402
407
  messageStorageDir: ".codex",
403
- cliDirLayout: { sessionData: [
404
- "logs_*.sqlite*",
405
- "goals_*.sqlite*",
406
- "memories_*.sqlite*"
407
- ] },
408
+ cliDirLayout: {
409
+ sessionData: [
410
+ ...[
411
+ "logs",
412
+ "goals",
413
+ "memories"
414
+ ].map((name) => `${name}_*.sqlite*`),
415
+ ...[
416
+ "state_5",
417
+ "queue_1",
418
+ "thread_history_1"
419
+ ].flatMap((name) => [
420
+ "",
421
+ "-wal",
422
+ "-shm"
423
+ ].map((suffix) => `${name}.sqlite${suffix}`)),
424
+ "skills/**",
425
+ "cache/codex_apps_tools/**",
426
+ "cache/codex_apps_server_info/**",
427
+ "cache/remote_plugin_catalog/**",
428
+ "plugins/cache/**",
429
+ "mcp-oauth-locks/file-store.lock",
430
+ "mcp-oauth-locks/secrets-store.lock",
431
+ "thread-writer-locks/.coordination.lock",
432
+ "thread-writer-locks/*-*-*-*-*.lock",
433
+ "tmp/arg0/codex-arg0*/.lock"
434
+ ],
435
+ configAllow: [
436
+ ".sandbox_migration",
437
+ ".sqlite-maintenance.lock",
438
+ ...[
439
+ "apply_patch",
440
+ "applypatch",
441
+ "codex-execve-wrapper",
442
+ "codex-linux-sandbox"
443
+ ].map((name) => ({
444
+ path: `tmp/arg0/codex-arg0*/${name}`,
445
+ kind: "symlink"
446
+ }))
447
+ ],
448
+ credential: ["shell_snapshots/**"]
449
+ },
408
450
  displayName: "Codex",
409
451
  description: "OpenAI Codex CLI-based agent backend.",
410
452
  envVars: HARNESSES["codex"].config.envVars,
411
453
  modelWire: HARNESSES["codex"].config.modelWire,
412
454
  capabilities: {
413
- streaming: true,
414
- toolUse: true,
455
+ ...BASE_CAPABILITIES,
415
456
  reasoning: false,
416
457
  multimodal: true,
417
458
  contextWindow: 128e3,
@@ -440,10 +481,8 @@ const CLI_AGENT_SPECS = [
440
481
  callerCredentialOnly: true,
441
482
  envVars: HARNESSES["amp"].config.envVars,
442
483
  capabilities: {
443
- streaming: true,
444
- toolUse: true,
484
+ ...BASE_CAPABILITIES,
445
485
  reasoning: false,
446
- multimodal: false,
447
486
  contextWindow: 128e3,
448
487
  mcp: false,
449
488
  sessions: true,
@@ -462,10 +501,8 @@ const CLI_AGENT_SPECS = [
462
501
  description: "Factory Droids CLI-based agent backend. A managed box runs its Tangle Router model as a droid custom model; a caller's FACTORY_API_KEY runs on the caller's Factory account.",
463
502
  envVars: HARNESSES["factory-droids"].config.envVars,
464
503
  capabilities: {
465
- streaming: true,
466
- toolUse: true,
504
+ ...BASE_CAPABILITIES,
467
505
  reasoning: false,
468
- multimodal: false,
469
506
  contextWindow: 128e3,
470
507
  mcp: false,
471
508
  sessions: true,
@@ -485,10 +522,7 @@ const CLI_AGENT_SPECS = [
485
522
  description: "Pi CLI backend. Managed OpenAI-compatible model tuples use one private runtime HOME models.json and the shared Pi model schema.",
486
523
  envVars: HARNESSES["pi"].config.envVars,
487
524
  capabilities: {
488
- streaming: true,
489
- toolUse: true,
490
- reasoning: true,
491
- multimodal: false,
525
+ ...BASE_CAPABILITIES,
492
526
  contextWindow: 128e3,
493
527
  mcp: true,
494
528
  sessions: true,
@@ -510,9 +544,7 @@ const CLI_AGENT_SPECS = [
510
544
  envVars: HARNESSES["prime"].config.envVars,
511
545
  hostPassthroughEnvVars: ["PRIME_AGENT_INSTALL_UV", "PRIME_AGENT_KERNEL_PYTHON"],
512
546
  capabilities: {
513
- streaming: true,
514
- toolUse: true,
515
- reasoning: true,
547
+ ...BASE_CAPABILITIES,
516
548
  multimodal: true,
517
549
  contextWindow: 128e3,
518
550
  mcp: false,
@@ -536,10 +568,9 @@ const CLI_AGENT_SPECS = [
536
568
  description: "Open-source self-improving CLI agent. Persistent memory and skills live in $HERMES_HOME (pinned to the per-session workspace mount, not the read-only in-box $HOME) across same-tenant snapshot resumes — the learning loop is the differentiator. Provider-pluggable; defaults to OpenRouter via Tangle Router.",
537
569
  envVars: HARNESSES["hermes"].config.envVars,
538
570
  capabilities: {
571
+ ...BASE_CAPABILITIES,
539
572
  streaming: false,
540
- toolUse: true,
541
573
  reasoning: false,
542
- multimodal: false,
543
574
  contextWindow: 2e5,
544
575
  mcp: true,
545
576
  sessions: true,
@@ -550,28 +581,6 @@ const CLI_AGENT_SPECS = [
550
581
  cliAuthHome: { kind: "inherit-home" },
551
582
  hasCliAuth: true
552
583
  },
553
- {
554
- name: BACKEND_TYPE.FORGE,
555
- nativeSession: NATIVE_SESSION_CONTRACTS.forge,
556
- messageStorageDir: ".forge-agent",
557
- displayName: "Forge (forgecode.dev)",
558
- description: "Rust-built multi-provider coding agent from tailcallhq/forgecode. Speaks anthropic/openai/openrouter/gemini/deepseek/kimi + local providers (ollama, lm_studio, llama_cpp). Credentials live in ~/.forge/.credentials.json, materialized via the standard authFiles pipeline — no interactive `forge provider login` required.",
559
- envVars: HARNESSES["forge"].config.envVars,
560
- capabilities: {
561
- streaming: false,
562
- toolUse: true,
563
- reasoning: true,
564
- multimodal: false,
565
- contextWindow: 2e5,
566
- mcp: true,
567
- sessions: true,
568
- configurable: true,
569
- interactions: [],
570
- imageInput: false
571
- },
572
- cliAuthHome: { kind: "inherit-home" },
573
- hasCliAuth: true
574
- },
575
584
  {
576
585
  name: BACKEND_TYPE.OPENCLAW,
577
586
  nativeSession: NATIVE_SESSION_CONTRACTS.openclaw,
@@ -581,9 +590,8 @@ const CLI_AGENT_SPECS = [
581
590
  description: "Orchestrator-tier CLI agent that dispatches to underlying coding-agent CLIs (claude-cli, codex-cli, gemini-cli) via its built-in cliBackends plugin model. Use this when you want one entry point that intelligently routes tasks to the right coding harness.",
582
591
  envVars: HARNESSES["openclaw"].config.envVars,
583
592
  capabilities: {
593
+ ...BASE_CAPABILITIES,
584
594
  streaming: false,
585
- toolUse: true,
586
- reasoning: true,
587
595
  multimodal: true,
588
596
  contextWindow: 2e5,
589
597
  mcp: true,
@@ -597,16 +605,14 @@ const CLI_AGENT_SPECS = [
597
605
  },
598
606
  {
599
607
  name: BACKEND_TYPE.NANOCLAW,
600
- nativeSession: null,
608
+ nativeSession: NATIVE_SESSION_CONTRACTS.nanoclaw,
601
609
  messageStorageDir: ".nanoclaw-agent",
602
610
  displayName: "NanoClaw",
603
- description: "NanoClaw local socket bridge. Requires a running NanoClaw install and uses its `pnpm run chat` CLI channel; the adapter does not manage NanoClaw's Docker/service lifecycle.",
611
+ description: "NanoClaw local socket bridge. The daemon persists v2-sessions and the chat bridge prints the session id.",
604
612
  envVars: HARNESSES["nanoclaw"].config.envVars,
605
613
  capabilities: {
614
+ ...BASE_CAPABILITIES,
606
615
  streaming: false,
607
- toolUse: true,
608
- reasoning: true,
609
- multimodal: false,
610
616
  contextWindow: 2e5,
611
617
  mcp: false,
612
618
  sessions: true,
@@ -615,7 +621,11 @@ const CLI_AGENT_SPECS = [
615
621
  imageInput: false
616
622
  },
617
623
  cliAuthHome: { kind: "inherit-home" },
618
- hasCliAuth: false
624
+ hasCliAuth: false,
625
+ unavailable: {
626
+ capability: "docker",
627
+ reason: "NanoClaw runs its agent in Docker, which Tangle sandboxes do not offer. Use another harness, such as opencode."
628
+ }
619
629
  },
620
630
  {
621
631
  name: BACKEND_TYPE.ACP,
@@ -625,10 +635,7 @@ const CLI_AGENT_SPECS = [
625
635
  description: "Generic Agent Client Protocol bridge — fronts any ACP-compliant agent binary (claude-agent-acp, codex-acp, gemini, openclaw acp, hermes acp). Pick the backing agent via config.subAgent; hermes runs on the box's Router model when none is named. One TypeScript adapter, many supported coding harnesses.",
626
636
  envVars: HARNESSES["acp"].config.envVars,
627
637
  capabilities: {
628
- streaming: true,
629
- toolUse: true,
630
- reasoning: true,
631
- multimodal: false,
638
+ ...BASE_CAPABILITIES,
632
639
  contextWindow: 2e5,
633
640
  mcp: false,
634
641
  sessions: true,
@@ -646,12 +653,16 @@ const CLI_AGENT_SPECS = [
646
653
  displayName: "Cursor Agent SDK",
647
654
  description: "Cursor Agent SDK backend. Runs Cursor's local agent against the sandbox workspace via @cursor/sdk, using CURSOR_API_KEY or backend.model.apiKey for authentication.",
648
655
  callerCredentialOnly: true,
649
- egressHosts: ["api2.cursor.sh", "api.cursor.com"],
656
+ egressHosts: [
657
+ "api2.cursor.sh",
658
+ "api2direct.cursor.sh",
659
+ "api.cursor.com",
660
+ "api5.cursor.sh",
661
+ "*.api5.cursor.sh"
662
+ ],
650
663
  envVars: HARNESSES["cursor"].config.envVars,
651
664
  capabilities: {
652
- streaming: true,
653
- toolUse: true,
654
- reasoning: true,
665
+ ...BASE_CAPABILITIES,
655
666
  multimodal: true,
656
667
  contextWindow: 2e5,
657
668
  mcp: true,
@@ -663,6 +674,26 @@ const CLI_AGENT_SPECS = [
663
674
  cliAuthHome: { kind: "inherit-home" },
664
675
  hasCliAuth: false
665
676
  },
677
+ {
678
+ name: BACKEND_TYPE.GROK,
679
+ nativeSession: NATIVE_SESSION_CONTRACTS.grok,
680
+ messageStorageDir: ".grok-sessions",
681
+ displayName: "Grok",
682
+ description: "Grok Build CLI. Headless grok -p against a caller base URL.",
683
+ envVars: HARNESSES.grok.config.envVars,
684
+ capabilities: {
685
+ ...BASE_CAPABILITIES,
686
+ reasoning: false,
687
+ contextWindow: 128e3,
688
+ mcp: false,
689
+ sessions: true,
690
+ configurable: false,
691
+ interactions: [],
692
+ imageInput: false
693
+ },
694
+ cliAuthHome: { kind: "inherit-home" },
695
+ hasCliAuth: false
696
+ },
666
697
  {
667
698
  name: BACKEND_TYPE.CLI_BASE,
668
699
  nativeSession: null,
@@ -670,10 +701,10 @@ const CLI_AGENT_SPECS = [
670
701
  description: "Bare sandbox without an AI agent backend. Use when you want the workspace, tools, and SSH access but no LLM dispatch.",
671
702
  envVars: HARNESSES["cli-base"].config.envVars,
672
703
  capabilities: {
704
+ ...BASE_CAPABILITIES,
673
705
  streaming: false,
674
706
  toolUse: false,
675
707
  reasoning: false,
676
- multimodal: false,
677
708
  contextWindow: 0,
678
709
  mcp: false,
679
710
  sessions: false,
@@ -701,4 +732,4 @@ function messageStorageDirOf(name) {
701
732
  //#endregion
702
733
  export { agentProfileSchema as a, cliAgentHostPassthroughEnvVarNames as c, canonicalModelSlug as d, cliAgentClaimEnvVarNames as f, SYNTHETIC_ROUTER_MODEL as g, harnessModelWire as h, MANAGED_MODEL_KEY_NAME_ENV_VAR as i, getSpec as l, harnessModelSupportFor as m, CLI_AGENT_SPECS as n, claimDeliverableEnvVarNames as o, cliAgentEnvRoleName as p, MANAGED_MODEL_KEY_ENV_VAR as r, cliAgentEnvVarNamesByRole as s, AGENT_BACKEND_ENV_VAR as t, messageStorageDirOf as u };
703
734
 
704
- //# sourceMappingURL=specs-Bbiay_8K.mjs.map
735
+ //# sourceMappingURL=specs-BBF55TnM.mjs.map
package/dist/specs.d.mts CHANGED
@@ -1,3 +1,72 @@
1
- import { a as isBackendType, i as backendTypeSchema, n as BACKEND_TYPE, o as parseBackendType, r as BackendType, t as ALL_BACKEND_TYPES } from "./backend-types-CJH-wHS3.mjs";
2
- import { D as harnessModelSupportFor, O as harnessModelWire, T as cliAgentClaimEnvVarNames, _ as CliAgentModelWire, a as agentProfileSchema, c as cliAgentHostPassthroughEnvVarNames, i as MANAGED_MODEL_KEY_NAME_ENV_VAR, l as getSpec, n as CLI_AGENT_SPECS, o as claimDeliverableEnvVarNames, r as MANAGED_MODEL_KEY_ENV_VAR, s as cliAgentEnvVarNamesByRole, t as AGENT_BACKEND_ENV_VAR, u as messageStorageDirOf, w as canonicalModelSlug, y as CliAgentSpec } from "./specs-BSELpX1h.mjs";
3
- export { AGENT_BACKEND_ENV_VAR, ALL_BACKEND_TYPES, BACKEND_TYPE, BackendType, CLI_AGENT_SPECS, CliAgentModelWire, CliAgentSpec, MANAGED_MODEL_KEY_ENV_VAR, MANAGED_MODEL_KEY_NAME_ENV_VAR, agentProfileSchema, backendTypeSchema, canonicalModelSlug, claimDeliverableEnvVarNames, cliAgentClaimEnvVarNames, cliAgentEnvVarNamesByRole, cliAgentHostPassthroughEnvVarNames, getSpec, harnessModelSupportFor, harnessModelWire, isBackendType, messageStorageDirOf, parseBackendType };
1
+ import { a as isBackendType, i as backendTypeSchema, n as BACKEND_TYPE, o as parseBackendType, r as BackendType, t as ALL_BACKEND_TYPES } from "./backend-types-DRmLR1e0.mjs";
2
+ import { _ as harnessModelSupportFor, h as cliAgentClaimEnvVarNames, l as CliAgentSpec, m as canonicalModelSlug, s as CliAgentModelWire, v as harnessModelWire } from "./spec-CcvTM7-j.mjs";
3
+ import { agentProfileSchema } from "@tangle-network/agent-interface";
4
+
5
+ //#region src/specs.d.ts
6
+ /**
7
+ * Env var naming a sandbox's selected backend. Stamped into every create env
8
+ * by the orchestrator (`buildSidecarContainerConfig`); read by the sidecar's
9
+ * backend resolution (`resolveConfiguredBackend`) and by the host-agent's
10
+ * warm-claim env selection to pick which spec's env vars the rebind delivers.
11
+ */
12
+ declare const AGENT_BACKEND_ENV_VAR = "AGENT_BACKEND";
13
+ /** Salted proxy model key. The name OPENCODE_MODEL_API_KEY is load-bearing; do not rename it. */
14
+ declare const MANAGED_MODEL_KEY_ENV_VAR = "OPENCODE_MODEL_API_KEY";
15
+ /** Name of the box env var holding a caller-owned provider key. A name, never a secret. */
16
+ declare const MANAGED_MODEL_KEY_NAME_ENV_VAR = "OPENCODE_MODEL_API_KEY_ENV";
17
+ /**
18
+ * Env var names declared across ALL registered harness specs, grouped by
19
+ * their `CliAgentEnvVars` role. The ONE derivation every allowlist that must
20
+ * track "what env names can a backend legitimately use" builds from — the
21
+ * FC kernel-cmdline whitelist, the egress secret handling, the sidecar
22
+ * terminal scrub, the SSH env forward, and the rebind union below. Deriving
23
+ * from roles (not one flat set) lets each consumer apply its own security
24
+ * policy per role: apiKey and oauthToken names are secret channels.
25
+ * Native subscription tokens stay out of warm-claim delivery.
26
+ */
27
+ declare function cliAgentEnvVarNamesByRole(): {
28
+ apiKey: ReadonlySet<string>;
29
+ oauthToken: ReadonlySet<string>;
30
+ model: ReadonlySet<string>;
31
+ baseUrl: ReadonlySet<string>;
32
+ authMode: ReadonlySet<string>;
33
+ authFiles: ReadonlySet<string>;
34
+ extras: ReadonlySet<string>;
35
+ };
36
+ /**
37
+ * Union of every spec's `hostPassthroughEnvVars` — the operator tuning names
38
+ * a host process (orchestrator system env, host-agent process env) may
39
+ * forward into containers. Request/caller env always keeps precedence at the
40
+ * host-agent boundary; the orchestrator system-env channel stays
41
+ * operator-authoritative. Replaces the old `OPENCODE_*` prefix forward,
42
+ * which leaked ANY stray host var with that prefix (model tuple and key
43
+ * included) into every tenant.
44
+ */
45
+ declare function cliAgentHostPassthroughEnvVarNames(): ReadonlySet<string>;
46
+ /**
47
+ * Union of every env var name a warm-claim rebind may deliver, across all
48
+ * registered harnesses. The ONE source both sides of the rebind derive from:
49
+ * the host-agent selects its delivery from it and the sidecar rebind route
50
+ * carves it out of the loader-control rejection, so the two can never drift
51
+ * into "host delivers a name the sidecar 400s" — which silently cold-paths
52
+ * every warm claim of that backend. Includes each spec's apiKey name because
53
+ * acceptance is a superset of delivery: the HOST decides which key names are
54
+ * safe to send (egress proxy-swap-covered only), while the sidecar must not
55
+ * reject a name a valid host may deliver.
56
+ */
57
+ declare function claimDeliverableEnvVarNames(): ReadonlySet<string>;
58
+ /**
59
+ * claude-code is the only provider that demotes uid + forces HOME=/home/agent
60
+ * when the sidecar runs as root. All other CLIs inherit the sidecar HOME.
61
+ */
62
+ declare const CLI_AGENT_SPECS: readonly CliAgentSpec[];
63
+ declare function getSpec(name: string): CliAgentSpec | undefined;
64
+ /**
65
+ * The directory, relative to a session's storage path, where a backend's
66
+ * message log lives: the one value adapters, the sidecar and the parked
67
+ * export read. Throws for a backend whose spec names none.
68
+ */
69
+ declare function messageStorageDirOf(name: string): string;
70
+ //#endregion
71
+ export { AGENT_BACKEND_ENV_VAR, ALL_BACKEND_TYPES, BACKEND_TYPE, type BackendType, CLI_AGENT_SPECS, type CliAgentModelWire, type CliAgentSpec, MANAGED_MODEL_KEY_ENV_VAR, MANAGED_MODEL_KEY_NAME_ENV_VAR, agentProfileSchema, backendTypeSchema, canonicalModelSlug, claimDeliverableEnvVarNames, cliAgentClaimEnvVarNames, cliAgentEnvVarNamesByRole, cliAgentHostPassthroughEnvVarNames, getSpec, harnessModelSupportFor, harnessModelWire, isBackendType, messageStorageDirOf, parseBackendType };
72
+ //# sourceMappingURL=specs.d.mts.map
package/dist/specs.mjs CHANGED
@@ -1,3 +1,3 @@
1
- import { a as parseBackendType, i as isBackendType, n as BACKEND_TYPE, r as backendTypeSchema, t as ALL_BACKEND_TYPES } from "./backend-types-CREj4iOY.mjs";
2
- import { a as agentProfileSchema, c as cliAgentHostPassthroughEnvVarNames, d as canonicalModelSlug, f as cliAgentClaimEnvVarNames, h as harnessModelWire, i as MANAGED_MODEL_KEY_NAME_ENV_VAR, l as getSpec, m as harnessModelSupportFor, n as CLI_AGENT_SPECS, o as claimDeliverableEnvVarNames, r as MANAGED_MODEL_KEY_ENV_VAR, s as cliAgentEnvVarNamesByRole, t as AGENT_BACKEND_ENV_VAR, u as messageStorageDirOf } from "./specs-Bbiay_8K.mjs";
1
+ import { a as parseBackendType, i as isBackendType, n as BACKEND_TYPE, r as backendTypeSchema, t as ALL_BACKEND_TYPES } from "./backend-types-CNo_Zj_K.mjs";
2
+ import { a as agentProfileSchema, c as cliAgentHostPassthroughEnvVarNames, d as canonicalModelSlug, f as cliAgentClaimEnvVarNames, h as harnessModelWire, i as MANAGED_MODEL_KEY_NAME_ENV_VAR, l as getSpec, m as harnessModelSupportFor, n as CLI_AGENT_SPECS, o as claimDeliverableEnvVarNames, r as MANAGED_MODEL_KEY_ENV_VAR, s as cliAgentEnvVarNamesByRole, t as AGENT_BACKEND_ENV_VAR, u as messageStorageDirOf } from "./specs-BBF55TnM.mjs";
3
3
  export { AGENT_BACKEND_ENV_VAR, ALL_BACKEND_TYPES, BACKEND_TYPE, CLI_AGENT_SPECS, MANAGED_MODEL_KEY_ENV_VAR, MANAGED_MODEL_KEY_NAME_ENV_VAR, agentProfileSchema, backendTypeSchema, canonicalModelSlug, claimDeliverableEnvVarNames, cliAgentClaimEnvVarNames, cliAgentEnvVarNamesByRole, cliAgentHostPassthroughEnvVarNames, getSpec, harnessModelSupportFor, harnessModelWire, isBackendType, messageStorageDirOf, parseBackendType };