@gitterm/sdk 0.0.6 → 0.0.8

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
@@ -203,6 +203,56 @@ const next = await client.runs.create({
203
203
  });
204
204
  ```
205
205
 
206
+ ### Model provider credentials
207
+
208
+ Workspaces can receive model credentials two ways, and they compose:
209
+
210
+ **Dashboard credentials** — list the account's credential metadata, choose one active credential
211
+ per provider, and pass the IDs when creating a workspace. The SDK never returns credential
212
+ secrets.
213
+
214
+ ```ts
215
+ const credentials = await client.credentials.list();
216
+ const selected = credentials.filter(
217
+ (credential) =>
218
+ credential.isActive && ["anthropic", "openai"].includes(credential.logicalProviderKey),
219
+ );
220
+
221
+ const { workspace } = await client.workspaces.create({
222
+ repo: "https://github.com/acme/product",
223
+ modelCredentialIds: selected.map((credential) => credential.id),
224
+ });
225
+ ```
226
+
227
+ **Inline credentials** — pass API keys directly for this workspace only. They are injected into
228
+ the provisioned agent and never stored in the dashboard. Use
229
+ `client.credentials.listProviders()` for valid provider names; OAuth providers (e.g. GitHub
230
+ Copilot) can only be connected through the dashboard.
231
+
232
+ ```ts
233
+ const { workspace } = await client.workspaces.create({
234
+ repo: "https://github.com/acme/product",
235
+ modelCredentials: [{ providerName: "anthropic", apiKey: process.env.ANTHROPIC_API_KEY! }],
236
+ });
237
+
238
+ const run = await client.runs.create({
239
+ workspaceId: workspace.workspaceId,
240
+ model: "anthropic/claude-sonnet-4-20250514",
241
+ prompt: "Record before/after videos of the changes in PR #42",
242
+ });
243
+ ```
244
+
245
+ Rules and errors:
246
+
247
+ - Omit both fields to inject the dashboard defaults.
248
+ - One credential per logical provider. An inline credential always overrides the dashboard
249
+ credential (default or selected) for the same provider; two credentials for the same provider
250
+ within one field throw `MODEL_CREDENTIAL_DUPLICATE_PROVIDER`.
251
+ - Unknown providers or inline keys for OAuth-only providers throw `MODEL_CREDENTIAL_INVALID`;
252
+ missing, inactive, or unowned dashboard selections throw `MODEL_CREDENTIAL_UNAVAILABLE`.
253
+ - A run that requests a credential-backed `provider/model` not available in its workspace throws
254
+ `MODEL_CREDENTIAL_REQUIRED` before the prompt is submitted.
255
+
206
256
  Use `client.runs.cancel(workspaceId, runId)` to abort the current run. GitTerm keeps the
207
257
  underlying OpenCode session private. For native session control, use
208
258
  `workspaces.getRuntimeAccess()` and connect with the official OpenCode SDK.
package/dist/client.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { AgentType, AgentRun, AgentRunCreateInput, AgentRunMessage, AuthStatus, CloudProvider, Workspace, WorkspaceCreateInput, WorkspaceCreateResult, WorkspaceEnsureRunningResult, WorkspaceListOptions, WorkspaceListResult, WorkspaceRestartResult, WorkspaceRuntimeAccess, WorkspacePauseResult, WorkspaceTerminateResult, WorkspaceCatalog, WorkspaceSetupStatus } from "./types.js";
1
+ import type { AgentType, AgentRun, AgentRunCreateInput, AgentRunMessage, AuthStatus, CloudProvider, Workspace, WorkspaceCreateInput, WorkspaceCreateResult, WorkspaceEnsureRunningResult, WorkspaceListOptions, WorkspaceListResult, WorkspaceRestartResult, WorkspaceRuntimeAccess, WorkspacePauseResult, WorkspaceTerminateResult, WorkspaceCatalog, WorkspaceSetupStatus, ModelCredential, ModelProviderInfo } from "./types.js";
2
2
  export type GittermClientOptions = {
3
3
  serverUrl?: string;
4
4
  token?: string;
@@ -52,5 +52,9 @@ export type GittermClient = {
52
52
  }): Promise<CloudProvider[]>;
53
53
  workspaceOptions(): Promise<WorkspaceCatalog>;
54
54
  };
55
+ credentials: {
56
+ list(): Promise<ModelCredential[]>;
57
+ listProviders(): Promise<ModelProviderInfo[]>;
58
+ };
55
59
  };
56
60
  export declare function createGittermClient(options?: GittermClientOptions): GittermClient;
package/dist/errors.d.ts CHANGED
@@ -1,4 +1,5 @@
1
- export type GittermErrorCode = "NOT_LOGGED_IN" | "UNAUTHORIZED" | "NOT_FOUND" | "FORBIDDEN" | "BAD_REQUEST" | "CONFLICT" | "SERVER_ERROR" | "NETWORK" | WorkspaceLifecycleErrorCode;
1
+ export type GittermErrorCode = "NOT_LOGGED_IN" | "UNAUTHORIZED" | "NOT_FOUND" | "FORBIDDEN" | "BAD_REQUEST" | "CONFLICT" | "SERVER_ERROR" | "NETWORK" | CredentialErrorCode | WorkspaceLifecycleErrorCode;
2
+ export type CredentialErrorCode = "MODEL_CREDENTIAL_UNAVAILABLE" | "MODEL_CREDENTIAL_DUPLICATE_PROVIDER" | "MODEL_CREDENTIAL_INVALID" | "MODEL_CREDENTIAL_REQUIRED";
2
3
  export type WorkspaceLifecycleErrorCode = "WORKSPACE_TERMINATED" | "WORKSPACE_NON_RECOVERABLE" | "WORKSPACE_START_TIMEOUT" | "WORKSPACE_RESTART_FAILED";
3
4
  export declare class GittermError extends Error {
4
5
  readonly code: GittermErrorCode;
package/dist/index.d.ts CHANGED
@@ -5,5 +5,5 @@ export { loginWithDeviceCode } from "./device-login.js";
5
5
  export type { DeviceCodeInfo, LoginWithDeviceCodeOptions } from "./device-login.js";
6
6
  export { GittermError, WorkspaceLifecycleError } from "./errors.js";
7
7
  export { createGittermWorkspaceClient, getWorkspaceEnvironment, type GittermWorkspaceClient, type WorkspaceClientOptions, type WorkspaceEnvironment, type WorkspacePort, type WorkspaceSelf, } from "./workspace-client.js";
8
- export type { GittermErrorCode, WorkspaceLifecycleErrorCode } from "./errors.js";
9
- export type { AgentRun, AgentRunCreateInput, AgentRunMessage, AgentRunStatus, AgentType, AgentKey, AuthStatus, BuiltInAgentKey, CloudProvider, ProviderKey, Workspace, WorkspaceCreateInput, WorkspaceCreateResult, WorkspaceCatalog, WorkspaceEnsureRunningResult, WorkspaceHostingType, WorkspaceListOptions, WorkspaceListResult, WorkspaceRestartResult, WorkspaceRuntimeAccess, WorkspaceStatus, WorkspaceSetupStatus, WorkspacePauseResult, WorkspaceTerminateResult, WorkspaceProviderSelection, } from "./types.js";
8
+ export type { CredentialErrorCode, GittermErrorCode, WorkspaceLifecycleErrorCode, } from "./errors.js";
9
+ export type { AgentRun, AgentRunCreateInput, AgentRunMessage, AgentRunStatus, AgentType, AgentKey, AuthStatus, BuiltInAgentKey, CloudProvider, ProviderKey, Workspace, WorkspaceCreateInput, WorkspaceCreateResult, WorkspaceCatalog, WorkspaceEnsureRunningResult, WorkspaceHostingType, WorkspaceListOptions, WorkspaceListResult, WorkspaceRestartResult, WorkspaceRuntimeAccess, WorkspaceStatus, WorkspaceSetupStatus, ModelCredential, ModelProviderInfo, WorkspaceModelCredentialInput, WorkspacePauseResult, WorkspaceTerminateResult, WorkspaceProviderSelection, } from "./types.js";
package/dist/index.js CHANGED
@@ -197,6 +197,10 @@ function mapTrpcCode(code) {
197
197
  return "SERVER_ERROR";
198
198
  }
199
199
  }
200
+ function credentialErrorCode(message) {
201
+ const match = /^(MODEL_CREDENTIAL_(?:UNAVAILABLE|DUPLICATE_PROVIDER|INVALID|REQUIRED)):\s*/.exec(message);
202
+ return match?.[1];
203
+ }
200
204
  async function runWithServer(serverUrl, operation) {
201
205
  try {
202
206
  return await operation();
@@ -211,6 +215,9 @@ async function runWithServer(serverUrl, operation) {
211
215
  });
212
216
  }
213
217
  const code = mapTrpcCode(trpcCode);
218
+ const credentialCode = credentialErrorCode(error.message);
219
+ if (credentialCode)
220
+ throw new GittermError(credentialCode, error.message, { cause: error });
214
221
  if (/WORKSPACE_TERMINATED/.test(error.message)) {
215
222
  throw new WorkspaceLifecycleError("WORKSPACE_TERMINATED", error.message, { cause: error });
216
223
  }
@@ -283,7 +290,9 @@ function createGittermClient(options = {}) {
283
290
  ${log}` : ""}`);
284
291
  }
285
292
  if (Date.now() >= deadline) {
286
- throw new GittermError("NETWORK", `Timed out waiting for workspace ${workspaceId} setup`);
293
+ const log = result.log?.trim();
294
+ throw new GittermError("NETWORK", `Timed out waiting for workspace ${workspaceId} setup (last status: ${result.status})${log ? `
295
+ ${log}` : ""}`);
287
296
  }
288
297
  await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
289
298
  }
@@ -385,6 +394,28 @@ ${log}` : ""}`);
385
394
  return result.cloudProviders;
386
395
  }),
387
396
  workspaceOptions: () => run(async () => trpc.workspace.getWorkspaceCatalog.query())
397
+ },
398
+ credentials: {
399
+ list: () => run(async () => {
400
+ const result = await trpc.modelCredentials.listMyCredentials.query();
401
+ return result.credentials.map((credential) => ({
402
+ ...credential,
403
+ lastUsedAt: toIso(credential.lastUsedAt),
404
+ oauthExpiresAt: toIso(credential.oauthExpiresAt),
405
+ createdAt: toIso(credential.createdAt),
406
+ updatedAt: toIso(credential.updatedAt)
407
+ }));
408
+ }),
409
+ listProviders: () => run(async () => {
410
+ const result = await trpc.modelCredentials.listProviders.query();
411
+ return result.providers.map((provider) => ({
412
+ id: provider.id,
413
+ name: provider.name,
414
+ displayName: provider.displayName,
415
+ authType: provider.authType,
416
+ isRecommended: provider.isRecommended
417
+ }));
418
+ })
388
419
  }
389
420
  };
390
421
  }
package/dist/types.d.ts CHANGED
@@ -115,6 +115,11 @@ type ExeDevResources = {
115
115
  memory?: string;
116
116
  disk?: string;
117
117
  };
118
+ /** E2B fixes CPU/RAM per template, so resources select a template build. */
119
+ type E2bResources = {
120
+ templateId?: string;
121
+ sshTemplateId?: string;
122
+ };
118
123
  export type WorkspaceProviderSelection = {
119
124
  type: "railway";
120
125
  providerId?: string;
@@ -137,7 +142,11 @@ export type WorkspaceProviderSelection = {
137
142
  } & Omit<ProviderSelectionBase, "machine"> & {
138
143
  machine?: FlexibleMachine<ExeDevResources>;
139
144
  }) | ({
140
- type: "e2b" | "ascii";
145
+ type: "e2b";
146
+ } & Omit<ProviderSelectionBase, "machine"> & {
147
+ machine?: FlexibleMachine<E2bResources>;
148
+ }) | ({
149
+ type: "ascii";
141
150
  } & ProviderSelectionBase) | {
142
151
  type: "cloudflare";
143
152
  providerId?: string;
@@ -149,7 +158,9 @@ export type WorkspaceCreateInput = {
149
158
  name?: string;
150
159
  repo: string;
151
160
  branch?: string;
161
+ /** Commit SHA to pin the checkout to after cloning `branch`/`checkoutRef`. */
152
162
  baseCommit?: string;
163
+ /** Branch or tag to clone when distinct from the display `branch`. Not a commit SHA — use `baseCommit` to pin a revision. */
153
164
  checkoutRef?: string;
154
165
  subdomain?: string;
155
166
  /** Stable agent key. Defaults to `opencode`. */
@@ -160,7 +171,15 @@ export type WorkspaceCreateInput = {
160
171
  /** Defaults from the selected provider. */
161
172
  persistent?: boolean;
162
173
  workspaceProfile?: "standard" | "ssh-enabled";
174
+ /** Credential IDs from client.credentials.list(). Omit to inject dashboard defaults. */
163
175
  modelCredentialIds?: string[];
176
+ /**
177
+ * Inline API keys for this workspace only — injected at provision time and
178
+ * never stored in the dashboard. An inline key overrides any dashboard
179
+ * credential for the same provider. OAuth providers can't be supplied
180
+ * inline; connect those in the dashboard.
181
+ */
182
+ modelCredentials?: WorkspaceModelCredentialInput[];
164
183
  /**
165
184
  * Ordered commands launched in the repository after the agent server starts.
166
185
  * They do not block workspace readiness; inspect ~/.gitterm/setup for status
@@ -175,6 +194,12 @@ export type WorkspaceCreateInput = {
175
194
  }>;
176
195
  /** NPM package specs or plugin paths accepted by OpenCode. Pin versions for repeatable runs. */
177
196
  plugins?: string[];
197
+ /**
198
+ * OpenCode config (opencode.json keys) merged over your saved config for
199
+ * this workspace only. e.g. { permission: { edit: "allow", bash: "allow",
200
+ * webfetch: "allow" } } disables tool approval prompts in headless runs.
201
+ */
202
+ config?: Record<string, unknown>;
178
203
  };
179
204
  };
180
205
  export type WorkspaceRestartResult = {
@@ -224,6 +249,7 @@ export type AgentRunCreateInput = {
224
249
  };
225
250
  /** Wait for workspace setup commands before submitting the prompt. */
226
251
  waitForSetup?: boolean;
252
+ /** How long to wait for setup, in ms. Server maximum is 600000 (10 minutes). */
227
253
  setupTimeoutMs?: number;
228
254
  };
229
255
  export type AgentRunMessage = {
@@ -241,6 +267,44 @@ export type WorkspaceSetupStatus = {
241
267
  finishedAt: string | null;
242
268
  log: string | null;
243
269
  };
270
+ /**
271
+ * A model provider from the Gitterm registry. `name` is what credential
272
+ * inputs reference; `authType` tells you whether it accepts inline API keys
273
+ * ("api_key") or requires the dashboard OAuth flow ("oauth").
274
+ */
275
+ export type ModelProviderInfo = {
276
+ id: string;
277
+ name: string;
278
+ displayName: string;
279
+ authType: string;
280
+ isRecommended: boolean;
281
+ };
282
+ /**
283
+ * An API key passed directly to workspaces.create(). `providerName` must be an
284
+ * API-key provider from credentials.listProviders(), e.g. "anthropic" or
285
+ * "openai"; unknown or OAuth-only providers throw MODEL_CREDENTIAL_INVALID.
286
+ */
287
+ export type WorkspaceModelCredentialInput = {
288
+ providerName: string;
289
+ apiKey: string;
290
+ };
291
+ /** Safe dashboard credential metadata. Secret material is never returned by the SDK. */
292
+ export type ModelCredential = {
293
+ id: string;
294
+ providerId: string;
295
+ providerName: string;
296
+ providerDisplayName: string;
297
+ logicalProviderKey: string;
298
+ authType: string;
299
+ label: string | null;
300
+ keyHash: string;
301
+ isActive: boolean;
302
+ isDefault: boolean;
303
+ lastUsedAt: string | null;
304
+ oauthExpiresAt: string | null;
305
+ createdAt: string;
306
+ updatedAt: string;
307
+ };
244
308
  export type AgentType = {
245
309
  id: string;
246
310
  key: string;
@@ -292,6 +356,13 @@ export type WorkspaceCatalog = {
292
356
  }>;
293
357
  agentKeys: string[];
294
358
  ssh: boolean;
359
+ /**
360
+ * Whether workspaces on this provider can call the gitterm API from
361
+ * inside the sandbox (scoped CLI, setup push reports, credential
362
+ * refresh). False for e.g. Daytona Tier 1/2 organizations, where setup
363
+ * status is reconciled by server-side polling instead.
364
+ */
365
+ workspaceApiAccess: boolean;
295
366
  }>;
296
367
  };
297
368
  export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gitterm/sdk",
3
- "version": "0.0.6",
3
+ "version": "0.0.8",
4
4
  "files": [
5
5
  "dist"
6
6
  ],