@gitterm/sdk 0.8.0 → 0.10.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.
package/README.md CHANGED
@@ -12,8 +12,8 @@ bun add @gitterm/sdk
12
12
  npm install @gitterm/sdk
13
13
  ```
14
14
 
15
- Requires Node 22.12+ or Bun. Create an API token in the dashboard under
16
- **Settings → Account → API tokens**, or with `gitterm login`.
15
+ Requires Node 22.12+ or Bun. Create an API token under **API tokens** in the dashboard, or with
16
+ `gitterm login`.
17
17
 
18
18
  ## Quick start
19
19
 
@@ -23,12 +23,10 @@ Create a workspace, run a prompt, and get the final result:
23
23
  import { createGittermClient } from "@gitterm/sdk";
24
24
 
25
25
  const client = createGittermClient({ token: process.env.GITTERM_API_TOKEN });
26
- const [github] = await client.integrations.connections.list({ integration: "github" });
27
- if (!github) throw new Error("Connect GitHub in the Gitterm dashboard first");
28
26
 
29
27
  const { workspace } = await client.workspaces.create({
30
28
  repo: "https://github.com/acme/product",
31
- connections: [github.id],
29
+ connections: ["github"], // the GitHub connection that covers acme
32
30
  autoTerminateAfterMs: 2 * 60 * 60 * 1000,
33
31
  });
34
32
 
@@ -48,19 +46,24 @@ try {
48
46
  ```
49
47
 
50
48
  Every integration you can attach, personal or admin-provided, is a **connection** with one shape.
51
- Attach any number by id (at most one per integration):
49
+ Reference each one the way you remember it:
52
50
 
53
51
  ```ts
54
- const connections = await client.integrations.connections.list();
55
- const github = connections.find((c) => c.integration === "github");
56
- const google = connections.find((c) => c.integration === "google");
57
-
58
52
  await client.workspaces.create({
59
53
  repo: "https://github.com/acme/product",
60
- connections: [github!.id, google!.id],
54
+ connections: [
55
+ "github", // integration key: the GitHub connection that covers acme, or the shared one
56
+ "Linear", // a connection name, as shown under Integrations (case-insensitive)
57
+ "3f7d0c2e-…", // or an id from connections.list()
58
+ ],
61
59
  });
62
60
  ```
63
61
 
62
+ An integration key works when it is unambiguous: `github` picks by the repository's owner;
63
+ `google`, `mcp`, and `executor` need exactly one connection of that kind. Names are not unique, so
64
+ a name shared by two connections is rejected with both ids; use the id or rename one. At most one
65
+ GitHub and one Google connection can be attached; MCP and Executor connections are unlimited.
66
+
64
67
  GitHub tokens and Google workload credentials are issued inside the workspace; the SDK caller does
65
68
  not receive or forward them.
66
69
 
@@ -168,6 +171,7 @@ client.credentials.listProviders();
168
171
  client.integrations.catalog(); // integrations the admin enabled: key, category, personal/shared
169
172
  client.integrations.connections.list(filter?); // what you can attach; personal + shared, one shape
170
173
  client.integrations.connections.get(id);
174
+ client.integrations.connections.resolve(references, { repo }); // what ids/keys/names attach
171
175
  client.integrations.connections.create(input); // integrations:write; may return a browser step
172
176
  client.integrations.connections.remove(id);
173
177
  client.integrations.connections.waitFor({ integration, since }); // after a `pending` create
@@ -300,6 +304,11 @@ running `gh auth login`:
300
304
  - Without repository credentials or an integration, GitTerm leaves CLI authentication
301
305
  to the environment or the CLI's existing configuration.
302
306
 
307
+ Commit attribution is separate from these push credentials. By default the workspace owner
308
+ is the author (their GitHub noreply address when GitHub is linked) and GitTerm is the
309
+ committer: the GitHub App's bot account when the deployment uses an app. **Settings →
310
+ Account → Commit attribution** makes the owner both instead, for new workspaces.
311
+
303
312
  GitTerm supplies `GH_TOKEN` only to the invoked CLI process, so there is no stale
304
313
  installation token exported into the agent's long-running environment. Explicit
305
314
  `GH_TOKEN` or `GITHUB_TOKEN` environment variables override this CLI authentication;
@@ -482,8 +491,10 @@ await client.workspaces.create({
482
491
 
483
492
  `provider` is a discriminated union, so TypeScript only offers `region` for providers
484
493
  where GitTerm supports caller-selected placement. Machine keys are configured by admins
485
- and returned by `client.catalog.workspaceOptions()`; raw CPU, memory, credentials, and
486
- provider account configuration are never supplied by SDK callers.
494
+ and returned by `client.catalog.workspaceOptions()` with their `vcpus` and `memoryGb`;
495
+ raw CPU, memory, credentials, and provider account configuration are never supplied by SDK
496
+ callers. The catalog lists only the sizes you may use: an admin can pin a provider to its
497
+ default size, and on managed GitTerm the Free plan gets each provider's smallest size.
487
498
 
488
499
  This makes release automation a normal workspace task: create an OpenCode workspace,
489
500
  run UI review or browser capture tools in the sandbox, upload the resulting media, update
@@ -502,7 +513,7 @@ A workspace has one of four statuses:
502
513
  | `terminated` | Gone for good. |
503
514
 
504
515
  Whether `create()` returns `running` or `pending` depends on the provider. Sandbox providers
505
- (E2B, Daytona, Vercel, Ascii, exe.dev, Cloudflare) settle immediately and return `running`.
516
+ (E2B, Daytona, Vercel, boat, exe.dev, Cloudflare) settle immediately and return `running`.
506
517
  Railway settles by webhook and returns `pending` until its deployment reports success, usually
507
518
  within a minute. Code that only ever ran against a sandbox provider will see `pending` for the
508
519
  first time when it moves to Railway.
@@ -726,7 +737,7 @@ const { workspace } = await client.workspaces.create({
726
737
 
727
738
  const run = await client.runs.create({
728
739
  workspace,
729
- model: "anthropic/claude-sonnet-4-20250514",
740
+ model: "anthropic/claude-sonnet-5-5",
730
741
  prompt: "Record before/after videos of the changes in PR #42",
731
742
  });
732
743
  ```
@@ -840,7 +851,7 @@ await saveConfig({
840
851
  ```
841
852
 
842
853
  Device-code logins produce the same revocable `gt_...` API token as the dashboard;
843
- they appear in **Settings → Account → API tokens** and can be revoked there.
854
+ they appear under **API tokens** in the dashboard and can be revoked there.
844
855
 
845
856
  ## Direct provider mode
846
857
 
@@ -853,7 +864,7 @@ All built-in compute providers use the same provisioning plan and workspace/run
853
864
  | E2B | OpenCode-compatible template | Yes | Yes |
854
865
  | Daytona | Public Gitterm OpenCode server image by default | Yes | Yes |
855
866
  | Vercel | Vercel Sandbox project | Yes | Yes |
856
- | Ascii | Box API key | Yes | Yes |
867
+ | boat | boat API key (provider type `ascii`) | Yes | Yes |
857
868
  | exe.dev | Lifecycle token, or an existing VM with `ls,ssh,share,ssh-key` | Yes | No |
858
869
  | Railway | Project/environment and public service domains | With a volume | No |
859
870
 
package/dist/client.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { AgentType, AgentRun, AgentRunCreateInput, AgentRunListOptions, AgentRunListResult, AgentRunMessage, AgentRunReply, AuthStatus, CloudProvider, RunRef, RunWaitOptions, RunWatchOptions, WaitOptions, Workspace, WorkspaceCreateInput, WorkspaceCreateResult, WorkspaceEnsureRunningResult, WorkspaceListOptions, WorkspaceListResult, WorkspaceRef, WorkspaceRestartResult, WorkspaceRuntimeAccess, WorkspacePauseResult, WorkspaceTerminateResult, WorkspaceCatalog, WorkspaceSetupStatus, ModelCredential, ModelProviderInfo, Integration, IntegrationKey, Connection, ConnectionKind, CreateConnectionInput, CreateConnectionResult, GitHubRepository, GitHubBranch, GoogleSetup } from "./types.js";
1
+ import type { AgentType, AgentRun, AgentRunCreateInput, AgentRunListOptions, AgentRunListResult, AgentRunMessage, AgentRunReply, AuthStatus, CloudProvider, RunRef, RunWaitOptions, RunWatchOptions, WaitOptions, Workspace, WorkspaceCreateInput, WorkspaceCreateResult, WorkspaceEnsureRunningResult, WorkspaceListOptions, WorkspaceListResult, WorkspaceRef, WorkspaceRestartResult, WorkspaceRuntimeAccess, WorkspacePauseResult, WorkspaceTerminateResult, WorkspaceCatalog, WorkspaceSetupStatus, ModelCredential, ModelProviderInfo, Integration, IntegrationKey, Connection, SavedBot, ConnectionKind, CreateConnectionInput, CreateConnectionResult, GitHubRepository, GitHubBranch, GoogleSetup, McpConnectionTestResult, UpdateMcpConnectionInput } from "./types.js";
2
2
  import type { AgentRunEvent, AgentRunResult, RunResultOptions, WorkspaceModelAccess } from "./types.js";
3
3
  export type GittermClientOptions = {
4
4
  serverUrl?: string;
@@ -69,6 +69,17 @@ export type GittermClient = {
69
69
  list(): Promise<ModelCredential[]>;
70
70
  listProviders(): Promise<ModelProviderInfo[]>;
71
71
  };
72
+ bots: {
73
+ /** Claims (or renews) the right to run this saved bot; one process at a time. */
74
+ acquireLease(leaseId: string): Promise<{
75
+ success: true;
76
+ }>;
77
+ releaseLease(leaseId: string): Promise<{
78
+ success: true;
79
+ }>;
80
+ /** The settings saved for this client's token in the dashboard; null if it isn't a bot's. */
81
+ self(): Promise<SavedBot | null>;
82
+ };
72
83
  integrations: {
73
84
  /** Integrations the admin has enabled for this deployment. */
74
85
  catalog(): Promise<Integration[]>;
@@ -79,6 +90,14 @@ export type GittermClient = {
79
90
  kind?: ConnectionKind;
80
91
  }): Promise<Connection[]>;
81
92
  get(id: string): Promise<Connection>;
93
+ /**
94
+ * The connections `workspaces.create({ connections })` would attach for these references
95
+ * (ids, integration keys, or names), without creating anything. Rejects with the same
96
+ * message creation would, e.g. for an ambiguous name. Pass `repo` to resolve `"github"`.
97
+ */
98
+ resolve(references: string[], options?: {
99
+ repo?: string;
100
+ }): Promise<Connection[]>;
82
101
  /** Requires the `integrations:write` scope. */
83
102
  create(input: CreateConnectionInput): Promise<CreateConnectionResult>;
84
103
  /** Removes a personal connection. Shared connections are managed by the admin. */
@@ -92,6 +111,7 @@ export type GittermClient = {
92
111
  since?: Date | string;
93
112
  timeoutMs?: number;
94
113
  intervalMs?: number;
114
+ connectionId?: string;
95
115
  }): Promise<Connection>;
96
116
  };
97
117
  github: {
@@ -103,6 +123,10 @@ export type GittermClient = {
103
123
  /** Issuer and attribute mapping to configure the Google provider before connecting. */
104
124
  setup(): Promise<GoogleSetup>;
105
125
  };
126
+ mcp: {
127
+ test(id: string): Promise<McpConnectionTestResult>;
128
+ update(input: UpdateMcpConnectionInput): Promise<Connection>;
129
+ };
106
130
  };
107
131
  };
108
132
  export declare function createGittermClient(options?: GittermClientOptions): GittermClient;
@@ -2177,12 +2177,12 @@ var WORKSPACE_LIFECYCLE_ERROR_CODES = [
2177
2177
 
2178
2178
  class GittermError extends Error {
2179
2179
  code;
2180
- cause;
2180
+ status;
2181
2181
  constructor(code, message, options = {}) {
2182
- super(message);
2182
+ super(message, "cause" in options ? { cause: options.cause } : undefined);
2183
2183
  this.name = "GittermError";
2184
2184
  this.code = code;
2185
- this.cause = options.cause;
2185
+ this.status = options.status;
2186
2186
  }
2187
2187
  }
2188
2188
 
@@ -3341,7 +3341,7 @@ function createAsciiDirectProvider(config) {
3341
3341
  async function deleteBox(boxId) {
3342
3342
  const response = await fetch(`https://ascii.dev/api/box/v1/boxes/${boxId}`, {
3343
3343
  method: "DELETE",
3344
- headers: { Authorization: `Bearer ${config.apiKey}` }
3344
+ headers: { Authorization: `Bearer ${config.apiKey}`, "X-Ascii-Confirm-Delete": boxId }
3345
3345
  });
3346
3346
  if (!response.ok && response.status !== 404) {
3347
3347
  throw new Error(`Ascii Box deletion failed (${response.status})`);
package/dist/errors.d.ts CHANGED
@@ -5,15 +5,18 @@ export type WorkspaceLifecycleErrorCode = "WORKSPACE_NOT_RUNNING" | "WORKSPACE_T
5
5
  export declare const WORKSPACE_LIFECYCLE_ERROR_CODES: readonly WorkspaceLifecycleErrorCode[];
6
6
  export declare class GittermError extends Error {
7
7
  readonly code: GittermErrorCode;
8
- readonly cause?: unknown;
8
+ /** HTTP status of the API response; undefined when the server never answered. */
9
+ readonly status: number | undefined;
9
10
  constructor(code: GittermErrorCode, message: string, options?: {
10
11
  cause?: unknown;
12
+ status?: number;
11
13
  });
12
14
  }
13
15
  export declare class WorkspaceLifecycleError extends GittermError {
14
16
  readonly code: WorkspaceLifecycleErrorCode;
15
17
  constructor(code: WorkspaceLifecycleErrorCode, message: string, options?: {
16
18
  cause?: unknown;
19
+ status?: number;
17
20
  });
18
21
  }
19
22
  /** result() could not produce a successful result. The run remains inspectable. */
package/dist/index.d.ts CHANGED
@@ -6,4 +6,4 @@ export type { DeviceCodeInfo, LoginWithDeviceCodeOptions } from "./device-login.
6
6
  export { AgentRunError, GittermError, WorkspaceLifecycleError } from "./errors.js";
7
7
  export { createGittermWorkspaceClient, getWorkspaceEnvironment, type GittermWorkspaceClient, type WorkspaceClientOptions, type WorkspaceEnvironment, type WorkspacePort, type WorkspacePortVisibility, type WorkspaceSelf, } from "./workspace-client.js";
8
8
  export type { CredentialErrorCode, GittermErrorCode, WorkspaceLifecycleErrorCode, } from "./errors.js";
9
- export type { AgentPermissionRequest, AgentQuestion, AgentQuestionOption, AgentQuestionRequest, AgentRun, AgentRunAttachment, AgentRunCreateInput, AgentRunInputRequest, AgentRunMessage, AgentRunMessagePart, AgentRunReply, AgentRunStatus, AgentRunEvent, AgentRunResult, AgentRunReplyPermission, AgentRunReplyQuestion, RunResultOptions, RunRef, RunWaitOptions, RunWatchOptions, AgentType, AgentKey, AuthStatus, BuiltInAgentKey, CloudProvider, ProviderKey, Workspace, WorkspaceCreateInput, WorkspaceCreateResult, WorkspaceCatalog, WorkspaceEnsureRunningResult, WorkspaceHostingType, WorkspaceListOptions, WorkspaceListResult, WorkspaceRestartResult, WorkspaceRuntimeAccess, WorkspaceStatus, WorkspaceSetupStatus, ModelCredential, ModelProviderInfo, ModelCredentialSource, WorkspaceModelsInput, WorkspaceModelAccess, WorkspacePauseResult, WorkspaceTerminateResult, WorkspaceProviderSelection, Integration, IntegrationKey, IntegrationCategory, Connection, ConnectionKind, ConnectionStatus, ConnectionDetails, GitHubConnectionDetails, GoogleConnectionDetails, CreateConnectionInput, CreateConnectionResult, GitHubRepository, GitHubBranch, GoogleSetup, } from "./types.js";
9
+ export type { AgentPermissionRequest, AgentQuestion, AgentQuestionOption, AgentQuestionRequest, AgentRun, AgentRunAttachment, AgentRunCreateInput, AgentRunInputRequest, AgentRunMessage, AgentRunMessagePart, AgentRunReply, AgentRunStatus, AgentRunEvent, AgentRunResult, AgentRunReplyPermission, AgentRunReplyQuestion, RunResultOptions, RunRef, RunWaitOptions, RunWatchOptions, AgentType, AgentKey, AuthStatus, BuiltInAgentKey, CloudProvider, ProviderKey, Workspace, WorkspaceCreateInput, WorkspaceCreateResult, WorkspaceCatalog, WorkspaceEnsureRunningResult, WorkspaceHostingType, WorkspaceListOptions, WorkspaceListResult, WorkspaceRestartResult, WorkspaceRuntimeAccess, WorkspaceStatus, WorkspaceSetupStatus, ModelCredential, ModelProviderInfo, ModelCredentialSource, WorkspaceModelsInput, WorkspaceModelAccess, WorkspacePauseResult, WorkspaceTerminateResult, WorkspaceProviderSelection, Integration, IntegrationKey, IntegrationCategory, Connection, SavedBot, ConnectionKind, ConnectionStatus, ConnectionDetails, GitHubConnectionDetails, GoogleConnectionDetails, McpConnectionDetails, McpAuthentication, CreateMcpConnectionInput, UpdateMcpConnectionInput, McpConnectionTestResult, CreateConnectionInput, CreateConnectionResult, GitHubRepository, GitHubBranch, GoogleSetup, } from "./types.js";
package/dist/index.js CHANGED
@@ -68,12 +68,12 @@ var WORKSPACE_LIFECYCLE_ERROR_CODES = [
68
68
 
69
69
  class GittermError extends Error {
70
70
  code;
71
- cause;
71
+ status;
72
72
  constructor(code, message, options = {}) {
73
- super(message);
73
+ super(message, "cause" in options ? { cause: options.cause } : undefined);
74
74
  this.name = "GittermError";
75
75
  this.code = code;
76
- this.cause = options.cause;
76
+ this.status = options.status;
77
77
  }
78
78
  }
79
79
 
@@ -288,7 +288,12 @@ function runHelpers(operations) {
288
288
 
289
289
  // src/client.ts
290
290
  function toConnection(connection) {
291
- return { ...connection, connectedAt: toIso(connection.connectedAt) };
291
+ const details = connection.details;
292
+ return {
293
+ ...connection,
294
+ connectedAt: toIso(connection.connectedAt),
295
+ details: "lastCheckedAt" in details ? { ...details, lastCheckedAt: toIso(details.lastCheckedAt) } : details
296
+ };
292
297
  }
293
298
  function envValue(name) {
294
299
  const value = typeof process !== "undefined" ? process.env[name] : undefined;
@@ -421,27 +426,26 @@ function toGittermError(serverUrl, error) {
421
426
  return error;
422
427
  if (error instanceof TRPCClientError) {
423
428
  const data = error.data;
424
- const trpcCode = data?.code;
425
- if (!error.data) {
429
+ if (!data) {
426
430
  return new GittermError("NETWORK", `Could not reach the GitTerm server at ${serverUrl}`, {
427
- cause: error
431
+ cause: error.cause ?? error
428
432
  });
429
433
  }
430
- const code = mapTrpcCode(trpcCode);
431
- const structuredLifecycleCode = WORKSPACE_LIFECYCLE_ERROR_CODES.find((candidate) => candidate === data?.workspaceLifecycleCode);
434
+ const status = { status: data.httpStatus };
435
+ const structuredLifecycleCode = WORKSPACE_LIFECYCLE_ERROR_CODES.find((candidate) => candidate === data.workspaceLifecycleCode);
432
436
  if (structuredLifecycleCode) {
433
- return new WorkspaceLifecycleError(structuredLifecycleCode, error.message, { cause: error });
437
+ return new WorkspaceLifecycleError(structuredLifecycleCode, error.message, status);
434
438
  }
435
439
  if (error.message.startsWith("INPUT_NOT_PENDING:"))
436
- return new GittermError("INPUT_NOT_PENDING", error.message, { cause: error });
440
+ return new GittermError("INPUT_NOT_PENDING", error.message, status);
437
441
  const credentialCode = credentialErrorCode(error.message);
438
442
  if (credentialCode)
439
- return new GittermError(credentialCode, error.message, { cause: error });
443
+ return new GittermError(credentialCode, error.message, status);
440
444
  const lifecycleCode = WORKSPACE_LIFECYCLE_ERROR_CODES.find((candidate) => error.message.startsWith(`${candidate}:`));
441
- if (lifecycleCode) {
442
- return new WorkspaceLifecycleError(lifecycleCode, error.message, { cause: error });
443
- }
444
- return new GittermError(code, code === "UNAUTHORIZED" ? `Authentication failed: ${error.message}. Check that the API token is valid and has not expired.` : error.message, { cause: error });
445
+ if (lifecycleCode)
446
+ return new WorkspaceLifecycleError(lifecycleCode, error.message, status);
447
+ const code = mapTrpcCode(data.code);
448
+ return new GittermError(code, code === "UNAUTHORIZED" ? `${error.message}. Check your GitTerm API token, or create a new one in the dashboard.` : error.message, status);
445
449
  }
446
450
  return new GittermError("NETWORK", error instanceof Error ? error.message : "Network request failed", { cause: error });
447
451
  }
@@ -698,14 +702,27 @@ ${log}` : ""}`);
698
702
  return result.map(toConnection);
699
703
  }),
700
704
  get: (id) => run(async () => toConnection(await trpc.integrations.connections.get.query({ id }))),
705
+ resolve: (references, options) => run(async () => {
706
+ const result = await trpc.integrations.connections.resolve.query({
707
+ references,
708
+ ...options?.repo ? { repo: options.repo } : {}
709
+ });
710
+ return result.map(toConnection);
711
+ }),
701
712
  create: (input) => run(async () => {
702
713
  const result = await trpc.integrations.connections.create.mutate(input);
703
- return result.status === "connected" ? { ...result, connection: toConnection(result.connection) } : result;
714
+ return result.status !== "pending" ? { ...result, connection: toConnection(result.connection) } : result;
704
715
  }),
705
716
  remove: (id) => run(async () => {
706
717
  await trpc.integrations.connections.remove.mutate({ id });
707
718
  }),
708
- waitFor: ({ integration, since, timeoutMs = 5 * 60000, intervalMs = 3000 }) => run(async () => {
719
+ waitFor: ({
720
+ integration,
721
+ since,
722
+ connectionId,
723
+ timeoutMs = 5 * 60000,
724
+ intervalMs = 3000
725
+ }) => run(async () => {
709
726
  const sinceMs = since ? new Date(since).getTime() : 0;
710
727
  const deadline = Date.now() + timeoutMs;
711
728
  while (Date.now() < deadline) {
@@ -713,7 +730,7 @@ ${log}` : ""}`);
713
730
  integration,
714
731
  kind: "personal"
715
732
  });
716
- const match = result.map(toConnection).filter((c) => c.status === "connected" && new Date(c.connectedAt).getTime() >= sinceMs).sort((a, b) => b.connectedAt.localeCompare(a.connectedAt))[0];
733
+ const match = result.map(toConnection).filter((c) => c.status === "connected" && (connectionId ? c.id === connectionId : new Date(c.connectedAt).getTime() >= sinceMs)).sort((a, b) => b.connectedAt.localeCompare(a.connectedAt))[0];
717
734
  if (match)
718
735
  return match;
719
736
  await new Promise((resolve) => setTimeout(resolve, intervalMs));
@@ -727,8 +744,20 @@ ${log}` : ""}`);
727
744
  },
728
745
  google: {
729
746
  setup: () => run(async () => trpc.integrations.google.setup.query())
747
+ },
748
+ mcp: {
749
+ test: (id) => run(async () => {
750
+ const result = await trpc.integrations.mcp.test.mutate({ id });
751
+ return { ...result, connection: toConnection(result.connection) };
752
+ }),
753
+ update: (input) => run(async () => toConnection(await trpc.integrations.mcp.update.mutate(input)))
730
754
  }
731
755
  },
756
+ bots: {
757
+ acquireLease: (leaseId) => run(() => trpc.bots.acquireLease.mutate({ leaseId })),
758
+ releaseLease: (leaseId) => run(() => trpc.bots.releaseLease.mutate({ leaseId })),
759
+ self: () => run(async () => trpc.bots.self.query())
760
+ },
732
761
  credentials: {
733
762
  list: () => run(async () => {
734
763
  const result = await trpc.modelCredentials.listMyCredentials.query();
package/dist/types.d.ts CHANGED
@@ -62,6 +62,7 @@ export type RunRef = {
62
62
  id: string;
63
63
  };
64
64
  export type WaitOptions = {
65
+ /** For `ensureRunning` the server maximum is 240000 (4 minutes). */
65
66
  timeoutMs?: number;
66
67
  pollIntervalMs?: number;
67
68
  /** Abort the wait early; the promise rejects with code `ABORTED`. */
@@ -106,50 +107,12 @@ export type ProviderKey = "railway" | "aws" | "e2b" | "daytona" | "cloudflare" |
106
107
  type ProviderSelectionBase = {
107
108
  /** Select a specific provider installation. Usually omitted. */
108
109
  providerId?: string;
109
- /** An admin-defined profile or flexible resources within the provider's allowed limits. */
110
+ /** An admin-defined machine size, by key. */
110
111
  machine?: {
111
112
  type: "profile";
112
113
  key: string;
113
114
  };
114
115
  };
115
- type FlexibleMachine<T> = {
116
- type: "profile";
117
- key: string;
118
- } | {
119
- type: "custom";
120
- resources: T;
121
- };
122
- type AwsResources = {
123
- cpu?: number;
124
- memory?: number;
125
- ephemeralStorageGiB?: number;
126
- architecture?: "X86_64" | "ARM64";
127
- };
128
- type DaytonaResources = {
129
- resources?: {
130
- cpu?: number;
131
- memory?: number;
132
- disk?: number;
133
- };
134
- editorResources?: {
135
- cpu?: number;
136
- memory?: number;
137
- disk?: number;
138
- };
139
- };
140
- type VercelResources = {
141
- vcpus?: number;
142
- };
143
- type ExeDevResources = {
144
- cpu?: number;
145
- memory?: string;
146
- disk?: string;
147
- };
148
- /** E2B fixes CPU/RAM per template, so resources select a template build. */
149
- type E2bResources = {
150
- templateId?: string;
151
- sshTemplateId?: string;
152
- };
153
116
  export type WorkspaceProviderSelection = {
154
117
  type: "railway";
155
118
  providerId?: string;
@@ -158,26 +121,8 @@ export type WorkspaceProviderSelection = {
158
121
  type: "aws";
159
122
  region?: string;
160
123
  accessProfile?: string;
161
- } & Omit<ProviderSelectionBase, "machine"> & {
162
- machine?: FlexibleMachine<AwsResources>;
163
- }) | ({
164
- type: "daytona";
165
- } & Omit<ProviderSelectionBase, "machine"> & {
166
- machine?: FlexibleMachine<DaytonaResources>;
167
- }) | ({
168
- type: "vercel";
169
- } & Omit<ProviderSelectionBase, "machine"> & {
170
- machine?: FlexibleMachine<VercelResources>;
171
- }) | ({
172
- type: "exedev";
173
- } & Omit<ProviderSelectionBase, "machine"> & {
174
- machine?: FlexibleMachine<ExeDevResources>;
175
- }) | ({
176
- type: "e2b";
177
- } & Omit<ProviderSelectionBase, "machine"> & {
178
- machine?: FlexibleMachine<E2bResources>;
179
- }) | ({
180
- type: "ascii";
124
+ } & ProviderSelectionBase) | ({
125
+ type: "daytona" | "vercel" | "exedev" | "e2b" | "ascii";
181
126
  } & ProviderSelectionBase) | {
182
127
  type: "cloudflare";
183
128
  providerId?: string;
@@ -185,6 +130,7 @@ export type WorkspaceProviderSelection = {
185
130
  export type BuiltInAgentKey = "opencode-ttyd" | "opencode" | "t3code";
186
131
  export type AgentKey = BuiltInAgentKey | (string & {});
187
132
  export type WorkspaceCreateInput = {
133
+ provisioningProfile?: "personal" | "bot";
188
134
  idempotencyKey?: string;
189
135
  name?: string;
190
136
  /**
@@ -225,13 +171,21 @@ export type WorkspaceCreateInput = {
225
171
  token: string;
226
172
  };
227
173
  /**
228
- * Connection ids to attach, from `client.integrations.connections.list()`. At most one per
229
- * integration. A GitHub connection renews Git/gh credentials automatically; a Google connection
230
- * injects keyless ADC/gcloud auth. Cannot be combined with `repositoryCredentials` for GitHub.
174
+ * Connections to attach. Each is a connection id from `client.integrations.connections.list()`,
175
+ * an integration key, or a connection name (case-insensitive; ambiguous names are rejected).
176
+ * `"github"` attaches the connection that covers the repository's owner, or the deployment's
177
+ * shared one. At most one GitHub and one Google connection; any number of MCP/Executor ones.
178
+ * A GitHub connection renews Git/gh credentials automatically; a Google connection injects
179
+ * keyless ADC/gcloud auth. Cannot be combined with `repositoryCredentials` for GitHub.
231
180
  */
232
181
  connections?: string[];
233
182
  /** Defaults from the selected provider. */
234
183
  persistent?: boolean;
184
+ /**
185
+ * Keep the workspace running while idle instead of pausing it. On managed
186
+ * GitTerm this needs a paid plan, and spending limits still pause it.
187
+ */
188
+ alwaysOn?: boolean;
235
189
  workspaceProfile?: "standard" | "ssh-enabled";
236
190
  /** Omit to use dashboard defaults. An explicit block inherits nothing unless requested. */
237
191
  models?: WorkspaceModelsInput;
@@ -283,7 +237,7 @@ export type Integration = {
283
237
  allowShared: boolean;
284
238
  };
285
239
  export type ConnectionKind = "personal" | "shared";
286
- export type ConnectionStatus = "connected" | "suspended";
240
+ export type ConnectionStatus = "connected" | "suspended" | "untested" | "needs_auth" | "error";
287
241
  export type GitHubConnectionDetails = {
288
242
  integration: "github";
289
243
  mode: "app" | "pat";
@@ -305,7 +259,42 @@ export type GoogleConnectionDetails = {
305
259
  attributeMapping: Record<string, string>;
306
260
  };
307
261
  };
308
- export type ConnectionDetails = GitHubConnectionDetails | GoogleConnectionDetails;
262
+ export type McpConnectionDetails = {
263
+ revision?: number;
264
+ integration: "mcp" | "executor";
265
+ url: string;
266
+ authType: "none" | "bearer" | "headers";
267
+ codemode: boolean;
268
+ toolCount: number | null;
269
+ serverInfo: {
270
+ name: string;
271
+ version: string;
272
+ } | null;
273
+ lastCheckedAt: string | null;
274
+ };
275
+ export type McpAuthentication = {
276
+ type: "none";
277
+ } | {
278
+ type: "headers";
279
+ headers: Record<string, string>;
280
+ };
281
+ export type CreateMcpConnectionInput = {
282
+ integration: "mcp" | "executor";
283
+ name: string;
284
+ url: string;
285
+ authentication: McpAuthentication;
286
+ codemode?: boolean;
287
+ };
288
+ export type UpdateMcpConnectionInput = Omit<CreateMcpConnectionInput, "integration" | "authentication"> & {
289
+ id: string;
290
+ authentication?: McpAuthentication;
291
+ };
292
+ export type McpConnectionTestResult = {
293
+ status: "connected" | "needs_auth" | "error";
294
+ message: string;
295
+ connection: Connection;
296
+ };
297
+ export type ConnectionDetails = GitHubConnectionDetails | GoogleConnectionDetails | McpConnectionDetails;
309
298
  /**
310
299
  * Something you can attach to a workspace via `connections: [id]`. Personal connections are
311
300
  * owned by you; shared ones are provided by the admin and have stable ids like `github:shared`.
@@ -328,15 +317,16 @@ export type CreateConnectionInput = {
328
317
  serviceAccountEmail: string;
329
318
  } | {
330
319
  integration: "github";
331
- };
320
+ } | CreateMcpConnectionInput;
332
321
  export type CreateConnectionResult = {
333
- status: "connected";
322
+ status: "connected" | "saved";
334
323
  connection: Connection;
335
324
  /** Commands you still need to run outside GitTerm, e.g. the Google IAM binding. */
336
325
  nextSteps: Array<{
337
326
  label: string;
338
327
  command: string;
339
328
  }>;
329
+ message?: string;
340
330
  } | {
341
331
  /** Finish in a browser at `authorizeUrl`, then `connections.waitFor()` the new connection. */
342
332
  status: "pending";
@@ -440,6 +430,8 @@ export type AgentRunReply = {
440
430
  reject: true;
441
431
  };
442
432
  export type AgentRun = {
433
+ /** A runtime snapshot was read successfully, even if it contained no final text. */
434
+ outputAvailable?: boolean;
443
435
  id: string;
444
436
  workspaceId: string;
445
437
  title: string;
@@ -488,6 +480,8 @@ export type AgentRunAttachment = {
488
480
  data: string;
489
481
  };
490
482
  export type AgentRunCreateInput = {
483
+ /** Absolute execution deadline enforced by the server, even if the client disconnects. */
484
+ deadlineAt?: string;
491
485
  workspace: WorkspaceRef;
492
486
  /**
493
487
  * Stable key used to return the same run when a request is retried.
@@ -730,11 +724,18 @@ export type WorkspaceCatalog = {
730
724
  description: string;
731
725
  roleArn: string;
732
726
  }>;
727
+ /** Where the provider runs workspaces (e.g. "EU", "US"); null when not set. */
728
+ location: string | null;
729
+ /** Sizes you may pick on this provider; `isDefault` is used when none is requested. */
733
730
  machines: Array<{
734
731
  id: string;
735
732
  key: string;
736
733
  name: string;
737
734
  description: string | null;
735
+ vcpus: number | null;
736
+ memoryGb: number | null;
737
+ /** Hourly price in millionths of a dollar on managed GitTerm; null when unpriced. */
738
+ priceMicrosPerHour: number | null;
738
739
  isDefault: boolean;
739
740
  }>;
740
741
  agentKeys: string[];
@@ -748,4 +749,30 @@ export type WorkspaceCatalog = {
748
749
  workspaceApiAccess: boolean;
749
750
  }>;
750
751
  };
752
+ /** A chat bot's settings, saved in the dashboard (Bots). Secrets stay in the bot's .env. */
753
+ export type SavedBot = {
754
+ id: string;
755
+ name: string;
756
+ platform: "slack" | "discord";
757
+ /** Repository URL, with `#branch` when one is picked. */
758
+ repo: string;
759
+ /** OpenCode `provider/model`. */
760
+ model: string;
761
+ /** Saved credential label; null uses the provider's default credential. */
762
+ credential: string | null;
763
+ /** Tool connection references besides GitHub. */
764
+ connections: string[];
765
+ /** Compute provider key; null uses your default. */
766
+ provider: string | null;
767
+ /** "token": the bot brings its own GITTERM_BOT_GITHUB_TOKEN. */
768
+ githubAccess: "connection" | "token";
769
+ /** Channel ids it answers in; empty answers in every channel it's in. */
770
+ channels: string[];
771
+ /** User ids allowed to use it; empty allows everyone in the channel. */
772
+ allowedUsers: string[];
773
+ allowGuests: boolean;
774
+ instructions: string | null;
775
+ /** A command run in the checkout before the agent starts in a new sandbox. */
776
+ setup: string | null;
777
+ };
751
778
  export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gitterm/sdk",
3
- "version": "0.8.0",
3
+ "version": "0.10.0",
4
4
  "files": [
5
5
  "dist"
6
6
  ],