@gitterm/sdk 0.0.5 → 0.0.7

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
@@ -160,7 +160,15 @@ export type WorkspaceCreateInput = {
160
160
  /** Defaults from the selected provider. */
161
161
  persistent?: boolean;
162
162
  workspaceProfile?: "standard" | "ssh-enabled";
163
+ /** Credential IDs from client.credentials.list(). Omit to inject dashboard defaults. */
163
164
  modelCredentialIds?: string[];
165
+ /**
166
+ * Inline API keys for this workspace only — injected at provision time and
167
+ * never stored in the dashboard. An inline key overrides any dashboard
168
+ * credential for the same provider. OAuth providers can't be supplied
169
+ * inline; connect those in the dashboard.
170
+ */
171
+ modelCredentials?: WorkspaceModelCredentialInput[];
164
172
  /**
165
173
  * Ordered commands launched in the repository after the agent server starts.
166
174
  * They do not block workspace readiness; inspect ~/.gitterm/setup for status
@@ -241,6 +249,44 @@ export type WorkspaceSetupStatus = {
241
249
  finishedAt: string | null;
242
250
  log: string | null;
243
251
  };
252
+ /**
253
+ * A model provider from the Gitterm registry. `name` is what credential
254
+ * inputs reference; `authType` tells you whether it accepts inline API keys
255
+ * ("api_key") or requires the dashboard OAuth flow ("oauth").
256
+ */
257
+ export type ModelProviderInfo = {
258
+ id: string;
259
+ name: string;
260
+ displayName: string;
261
+ authType: string;
262
+ isRecommended: boolean;
263
+ };
264
+ /**
265
+ * An API key passed directly to workspaces.create(). `providerName` must be an
266
+ * API-key provider from credentials.listProviders(), e.g. "anthropic" or
267
+ * "openai"; unknown or OAuth-only providers throw MODEL_CREDENTIAL_INVALID.
268
+ */
269
+ export type WorkspaceModelCredentialInput = {
270
+ providerName: string;
271
+ apiKey: string;
272
+ };
273
+ /** Safe dashboard credential metadata. Secret material is never returned by the SDK. */
274
+ export type ModelCredential = {
275
+ id: string;
276
+ providerId: string;
277
+ providerName: string;
278
+ providerDisplayName: string;
279
+ logicalProviderKey: string;
280
+ authType: string;
281
+ label: string | null;
282
+ keyHash: string;
283
+ isActive: boolean;
284
+ isDefault: boolean;
285
+ lastUsedAt: string | null;
286
+ oauthExpiresAt: string | null;
287
+ createdAt: string;
288
+ updatedAt: string;
289
+ };
244
290
  export type AgentType = {
245
291
  id: string;
246
292
  key: string;
@@ -292,6 +338,13 @@ export type WorkspaceCatalog = {
292
338
  }>;
293
339
  agentKeys: string[];
294
340
  ssh: boolean;
341
+ /**
342
+ * Whether workspaces on this provider can call the gitterm API from
343
+ * inside the sandbox (scoped CLI, setup push reports, credential
344
+ * refresh). False for e.g. Daytona Tier 1/2 organizations, where setup
345
+ * status is reconciled by server-side polling instead.
346
+ */
347
+ workspaceApiAccess: boolean;
295
348
  }>;
296
349
  };
297
350
  export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gitterm/sdk",
3
- "version": "0.0.5",
3
+ "version": "0.0.7",
4
4
  "files": [
5
5
  "dist"
6
6
  ],