@gitterm/sdk 0.3.0 → 0.6.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.
@@ -1,4 +1,4 @@
1
- import type { AgentRun, AgentRunMessage, OpencodeApi, RunWaitOptions } from "../types.js";
1
+ import type { AgentRun, AgentRunMessage, RunWaitOptions } from "../types.js";
2
2
  export type DirectWorkspaceLifecycle = "ephemeral" | "persistent";
3
3
  export type DirectWorkspaceStatus = "pending" | "running" | "paused" | "failed" | "terminated" | "unknown";
4
4
  export type DirectProviderCapabilities = {
@@ -11,12 +11,16 @@ export type DirectProviderCapabilities = {
11
11
  };
12
12
  export type DirectApiModelCredential = {
13
13
  providerName: string;
14
+ /** Account label shown in OpenCode. Defaults to "Gitterm". */
15
+ label?: string;
14
16
  source: "apiKey";
15
17
  apiKey: string;
16
18
  metadata?: Record<string, string>;
17
19
  };
18
20
  export type DirectOAuthModelCredential = {
19
21
  providerName: string;
22
+ /** Account label shown in OpenCode. Defaults to "Gitterm". */
23
+ label?: string;
20
24
  source: "oauth";
21
25
  refreshToken: string;
22
26
  /** May be omitted when OpenCode should refresh immediately. */
@@ -147,8 +151,6 @@ export type DirectWorkspaceCreateInput = {
147
151
  /** Trusted integration context appended to the generated global AGENTS.md. */
148
152
  additionalAgentInstructions?: string;
149
153
  opencode?: {
150
- /** Defaults to v2. */
151
- api?: OpencodeApi;
152
154
  config?: Record<string, unknown>;
153
155
  plugins?: string[];
154
156
  skills?: Array<{
@@ -170,7 +172,6 @@ export type DirectWorkspace = {
170
172
  status: DirectWorkspaceStatus;
171
173
  lifecycle: DirectWorkspaceLifecycle;
172
174
  runtime: DirectWorkspaceRuntime;
173
- opencodeApi: OpencodeApi;
174
175
  setup: "not_requested" | "before_agent_complete" | "after_agent";
175
176
  createdAt: string;
176
177
  };
package/dist/index.d.ts CHANGED
@@ -4,6 +4,6 @@ export type { CliConfig } from "./config.js";
4
4
  export { loginWithDeviceCode } from "./device-login.js";
5
5
  export type { DeviceCodeInfo, LoginWithDeviceCodeOptions } from "./device-login.js";
6
6
  export { AgentRunError, GittermError, WorkspaceLifecycleError } from "./errors.js";
7
- export { createGittermWorkspaceClient, getWorkspaceEnvironment, type GittermWorkspaceClient, type WorkspaceClientOptions, type WorkspaceEnvironment, type WorkspacePort, type WorkspaceSelf, } from "./workspace-client.js";
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, AgentRunCreateInput, AgentRunInputRequest, AgentRunMessage, AgentRunMessagePart, AgentRunReply, AgentRunStatus, AgentRunEvent, AgentRunResult, AgentRunReplyPermission, AgentRunReplyQuestion, RunResultOptions, RunRef, RunWaitOptions, RunWatchOptions, OpencodeApi, AgentType, AgentKey, AuthStatus, BuiltInAgentKey, CloudProvider, ProviderKey, Workspace, WorkspaceCreateInput, WorkspaceCreateResult, WorkspaceCatalog, WorkspaceEnsureRunningResult, WorkspaceHostingType, WorkspaceListOptions, WorkspaceListResult, WorkspaceRestartResult, WorkspaceRuntimeAccess, WorkspaceStatus, WorkspaceSetupStatus, ModelCredential, ModelProviderInfo, ModelInfo, ModelCredentialSource, WorkspaceModelsInput, WorkspaceModelAccess, WorkspacePauseResult, WorkspaceTerminateResult, WorkspaceProviderSelection, GitHubIntegration, GoogleCloudIntegration, } from "./types.js";
9
+ export type { AgentPermissionRequest, AgentQuestion, AgentQuestionOption, AgentQuestionRequest, AgentRun, 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";
package/dist/index.js CHANGED
@@ -270,6 +270,9 @@ function runHelpers(operations) {
270
270
  }
271
271
 
272
272
  // src/client.ts
273
+ function toConnection(connection) {
274
+ return { ...connection, connectedAt: toIso(connection.connectedAt) };
275
+ }
273
276
  function envValue(name) {
274
277
  const value = typeof process !== "undefined" ? process.env[name] : undefined;
275
278
  return value && value.trim() ? value : undefined;
@@ -351,7 +354,6 @@ function normalizeWorkspace(workspace) {
351
354
  imageId: workspace.image.imageId
352
355
  } : null,
353
356
  metadata: workspace.metadata ?? {},
354
- opencodeApi: workspace.opencodeApi ?? "v1",
355
357
  autoTerminateAt: toIso(workspace.autoTerminateAt),
356
358
  customImage: workspace.customImage ?? null,
357
359
  startedAt: toIso(workspace.startedAt),
@@ -534,7 +536,7 @@ function createGittermClient(options = {}) {
534
536
  const timeoutMs = waitOptions?.timeoutMs ?? 10 * 60000;
535
537
  const pollIntervalMs = waitOptions?.pollIntervalMs ?? 2000;
536
538
  const signal = waitOptions?.signal;
537
- const deadline2 = Date.now() + timeoutMs;
539
+ const deadline = Date.now() + timeoutMs;
538
540
  while (true) {
539
541
  throwIfAborted(signal, "waiting for workspace setup");
540
542
  const result = await trpc.workspace.getSetupStatus.query({ workspaceId }, { signal });
@@ -545,7 +547,7 @@ function createGittermClient(options = {}) {
545
547
  throw new GittermError("BAD_REQUEST", `Workspace setup failed${result.exitCode === null ? "" : ` with exit code ${result.exitCode}`}${log ? `
546
548
  ${log}` : ""}`);
547
549
  }
548
- if (Date.now() >= deadline2) {
550
+ if (Date.now() >= deadline) {
549
551
  const log = result.log?.trim();
550
552
  throw new GittermError("TIMEOUT", `Timed out waiting for workspace ${workspaceId} setup (last status: ${result.status})${log ? `
551
553
  ${log}` : ""}`);
@@ -674,44 +676,43 @@ ${log}` : ""}`);
674
676
  }),
675
677
  workspaceOptions: () => run(async () => trpc.workspace.getWorkspaceCatalog.query())
676
678
  },
677
- models: {
678
- list: (listOptions) => run(async () => {
679
- const result = await trpc.modelCredentials.listModels.query();
680
- return result.models.map((model) => ({
681
- id: model.modelId,
682
- name: model.displayName,
683
- provider: model.modelId.slice(0, model.modelId.indexOf("/")),
684
- isFree: model.isFree,
685
- isRecommended: model.isRecommended
686
- })).filter((model) => !listOptions?.provider || model.provider === listOptions.provider);
687
- })
688
- },
689
679
  integrations: {
690
- github: {
691
- list: () => run(async () => {
692
- const result = await trpc.workspace.listUserInstallations.query();
693
- return result.installations.map(({ git_integration, github_app_installation }) => ({
694
- id: git_integration.id,
695
- accountLogin: git_integration.providerAccountLogin,
696
- accountType: github_app_installation.accountType,
697
- repositorySelection: github_app_installation.repositorySelection,
698
- suspended: github_app_installation.suspended,
699
- connectedAt: toIso(git_integration.connectedAt)
700
- }));
680
+ catalog: () => run(async () => trpc.integrations.catalog.query()),
681
+ connections: {
682
+ list: (filter) => run(async () => {
683
+ const result = await trpc.integrations.connections.list.query(filter);
684
+ return result.map(toConnection);
685
+ }),
686
+ get: (id) => run(async () => toConnection(await trpc.integrations.connections.get.query({ id }))),
687
+ create: (input) => run(async () => {
688
+ const result = await trpc.integrations.connections.create.mutate(input);
689
+ return result.status === "connected" ? { ...result, connection: toConnection(result.connection) } : result;
690
+ }),
691
+ remove: (id) => run(async () => {
692
+ await trpc.integrations.connections.remove.mutate({ id });
693
+ }),
694
+ waitFor: ({ integration, since, timeoutMs = 5 * 60000, intervalMs = 3000 }) => run(async () => {
695
+ const sinceMs = since ? new Date(since).getTime() : 0;
696
+ const deadline = Date.now() + timeoutMs;
697
+ while (Date.now() < deadline) {
698
+ const result = await trpc.integrations.connections.list.query({
699
+ integration,
700
+ kind: "personal"
701
+ });
702
+ 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];
703
+ if (match)
704
+ return match;
705
+ await new Promise((resolve) => setTimeout(resolve, intervalMs));
706
+ }
707
+ throw new Error(`Timed out waiting for a ${integration} connection`);
701
708
  })
702
709
  },
703
- googleCloud: {
704
- list: () => run(async () => {
705
- const result = await trpc.googleCloud.list.query();
706
- return result.map((integration) => ({
707
- id: integration.id,
708
- name: integration.name,
709
- projectId: integration.projectId,
710
- workloadIdentityProvider: integration.workloadIdentityProvider,
711
- serviceAccountEmail: integration.serviceAccountEmail,
712
- connectedAt: toIso(integration.connectedAt)
713
- }));
714
- })
710
+ github: {
711
+ repositories: (connectionId) => run(async () => trpc.integrations.github.repositories.query({ connectionId })),
712
+ branches: (connectionId, owner, repo) => run(async () => trpc.integrations.github.branches.query({ connectionId, owner, repo }))
713
+ },
714
+ google: {
715
+ setup: () => run(async () => trpc.integrations.google.setup.query())
715
716
  }
716
717
  },
717
718
  credentials: {
@@ -760,8 +761,8 @@ async function loginWithDeviceCode(serverUrl, options = {}) {
760
761
  intervalSeconds: codeJson.intervalSeconds,
761
762
  expiresInSeconds: codeJson.expiresInSeconds
762
763
  });
763
- const deadline2 = Date.now() + codeJson.expiresInSeconds * 1000;
764
- while (Date.now() < deadline2) {
764
+ const deadline = Date.now() + codeJson.expiresInSeconds * 1000;
765
+ while (Date.now() < deadline) {
765
766
  const tokenRes = await fetchImpl(new URL("/api/device/token", normalizedServerUrl), {
766
767
  method: "POST",
767
768
  headers: { "content-type": "application/json" },
@@ -840,6 +841,7 @@ function createGittermWorkspaceClient(options = {}) {
840
841
  ports: {
841
842
  list: () => run(() => trpc.workspaceOps.listPorts.query()),
842
843
  open: (port, input) => run(() => trpc.workspaceOps.openPort.mutate({ port, ...input })),
844
+ setVisibility: (port, visibility) => run(() => trpc.workspaceOps.setPortVisibility.mutate({ port, visibility })),
843
845
  close: (port) => run(() => trpc.workspaceOps.closePort.mutate({ port }))
844
846
  }
845
847
  };
package/dist/types.d.ts CHANGED
@@ -42,8 +42,6 @@ export type Workspace = {
42
42
  } | null;
43
43
  /** Caller-owned tags supplied at create time. */
44
44
  metadata: Record<string, string>;
45
- /** OpenCode HTTP API generation the workspace's agent server speaks. */
46
- opencodeApi: OpencodeApi;
47
45
  /** When set, the workspace is terminated at this time regardless of activity. */
48
46
  autoTerminateAt: string | null;
49
47
  /** The caller-supplied image or E2B template this workspace runs, if any. */
@@ -63,8 +61,6 @@ export type RunRef = {
63
61
  workspaceId: string;
64
62
  id: string;
65
63
  };
66
- /** `v1` = OpenCode 1.x (`/event`, `/session/*`); `v2` = OpenCode 2 (`/api/*`) and the default. */
67
- export type OpencodeApi = "v1" | "v2";
68
64
  export type WaitOptions = {
69
65
  timeoutMs?: number;
70
66
  pollIntervalMs?: number;
@@ -223,16 +219,17 @@ export type WorkspaceCreateInput = {
223
219
  agent?: AgentKey;
224
220
  /** Provider intent. Defaults to the user's or deployment's preferred provider. */
225
221
  provider?: WorkspaceProviderSelection;
226
- /** Inline Git credentials for repository validation, cloning, and runtime pull/push. */
227
- /** Runtime Git/gh authentication. Takes precedence over gitIntegrationId; not auto-renewed. */
222
+ /** Inline Git/gh credentials for validation, cloning, and runtime operations. Not auto-renewed. */
228
223
  repositoryCredentials?: {
229
224
  username?: string;
230
225
  token: string;
231
226
  };
232
- /** Dashboard GitHub App integration; runtime Git/gh credentials are renewed automatically. */
233
- gitIntegrationId?: string;
234
- /** Google Workload Identity Federation integration; injects keyless ADC/gcloud auth. */
235
- googleCloudIntegrationId?: string;
227
+ /**
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.
231
+ */
232
+ connections?: string[];
236
233
  /** Defaults from the selected provider. */
237
234
  persistent?: boolean;
238
235
  workspaceProfile?: "standard" | "ssh-enabled";
@@ -271,27 +268,100 @@ export type WorkspaceCreateInput = {
271
268
  * webfetch: "allow" } } disables tool approval prompts in headless runs.
272
269
  */
273
270
  config?: Record<string, unknown>;
274
- /**
275
- * OpenCode API generation served by the image. Defaults to `v2`.
276
- */
277
- api?: OpencodeApi;
278
271
  };
279
272
  };
280
- export type GitHubIntegration = {
281
- id: string;
273
+ export type IntegrationKey = "github" | "google" | "gitlab" | "bitbucket" | "executor" | "mcp";
274
+ export type IntegrationCategory = "git" | "cloud" | "mcp";
275
+ /** An integration the admin has enabled for this deployment. */
276
+ export type Integration = {
277
+ key: IntegrationKey;
278
+ name: string;
279
+ category: IntegrationCategory;
280
+ /** Users may create their own connections (e.g. install the GitHub App). */
281
+ allowPersonal: boolean;
282
+ /** The admin provides a deployment-wide connection with id `<key>:shared`. */
283
+ allowShared: boolean;
284
+ };
285
+ export type ConnectionKind = "personal" | "shared";
286
+ export type ConnectionStatus = "connected" | "suspended";
287
+ export type GitHubConnectionDetails = {
288
+ integration: "github";
289
+ mode: "app" | "pat";
282
290
  accountLogin: string;
283
- accountType: string;
284
- repositorySelection: string;
285
- suspended: boolean;
286
- connectedAt: string;
291
+ accountType?: string;
292
+ repositorySelection?: "all" | "selected";
293
+ installationId?: string;
294
+ patSuffix?: string;
287
295
  };
288
- export type GoogleCloudIntegration = {
296
+ export type GoogleConnectionDetails = {
297
+ integration: "google";
298
+ projectId: string;
299
+ serviceAccountEmail: string;
300
+ workloadIdentityProvider: string;
301
+ setup: {
302
+ issuer: string;
303
+ audience: string;
304
+ principalSet: string;
305
+ attributeMapping: Record<string, string>;
306
+ };
307
+ };
308
+ export type ConnectionDetails = GitHubConnectionDetails | GoogleConnectionDetails;
309
+ /**
310
+ * Something you can attach to a workspace via `connections: [id]`. Personal connections are
311
+ * owned by you; shared ones are provided by the admin and have stable ids like `github:shared`.
312
+ */
313
+ export type Connection = {
289
314
  id: string;
315
+ integration: IntegrationKey;
316
+ kind: ConnectionKind;
317
+ name: string;
318
+ status: ConnectionStatus;
319
+ connectedAt: string;
320
+ details: ConnectionDetails;
321
+ };
322
+ export type CreateConnectionInput = {
323
+ integration: "google";
290
324
  name: string;
291
325
  projectId: string;
326
+ /** projects/<number>/locations/global/workloadIdentityPools/<pool>/providers/<provider> */
292
327
  workloadIdentityProvider: string;
293
328
  serviceAccountEmail: string;
294
- connectedAt: string;
329
+ } | {
330
+ integration: "github";
331
+ };
332
+ export type CreateConnectionResult = {
333
+ status: "connected";
334
+ connection: Connection;
335
+ /** Commands you still need to run outside GitTerm, e.g. the Google IAM binding. */
336
+ nextSteps: Array<{
337
+ label: string;
338
+ command: string;
339
+ }>;
340
+ } | {
341
+ /** Finish in a browser at `authorizeUrl`, then `connections.waitFor()` the new connection. */
342
+ status: "pending";
343
+ integration: IntegrationKey;
344
+ authorizeUrl: string;
345
+ };
346
+ export type GitHubRepository = {
347
+ id: number;
348
+ name: string;
349
+ fullName: string;
350
+ owner: string;
351
+ private: boolean;
352
+ defaultBranch: string;
353
+ htmlUrl: string;
354
+ pushedAt: string | null;
355
+ };
356
+ export type GitHubBranch = {
357
+ name: string;
358
+ protected: boolean;
359
+ };
360
+ export type GoogleSetup = {
361
+ available: boolean;
362
+ /** OIDC issuer to configure on the Google workload identity provider. */
363
+ issuer: string | null;
364
+ attributeMapping: Record<string, string>;
295
365
  };
296
366
  export type WorkspaceRestartResult = {
297
367
  status: WorkspaceStatus;
@@ -546,14 +616,6 @@ export type ModelProviderInfo = {
546
616
  authType: string;
547
617
  isRecommended: boolean;
548
618
  };
549
- export type ModelInfo = {
550
- /** Full provider/model identifier accepted by runs.create(). */
551
- id: string;
552
- name: string;
553
- provider: string;
554
- isFree: boolean;
555
- isRecommended: boolean;
556
- };
557
619
  /** Control-plane configuration, not a live authentication check. */
558
620
  export type WorkspaceModelAccess = {
559
621
  providers: Array<{
@@ -562,8 +624,6 @@ export type WorkspaceModelAccess = {
562
624
  label: string | null;
563
625
  active: boolean;
564
626
  }>;
565
- /** Known catalog models whose provider is configured, plus free models. */
566
- models: ModelInfo[];
567
627
  };
568
628
  /** Explicit credential intent. Saved sources use dashboard labels, never credential IDs. */
569
629
  export type ModelCredentialSource = {
@@ -594,6 +654,8 @@ export type ModelCredential = {
594
654
  /** Select with models.providers[logicalProviderKey] = { source: "saved", label }. */
595
655
  label: string;
596
656
  keyHash: string;
657
+ /** Last four characters of the API key; null for OAuth credentials. */
658
+ keySuffix: string | null;
597
659
  isActive: boolean;
598
660
  isDefault: boolean;
599
661
  lastUsedAt: string | null;
@@ -15,9 +15,15 @@ export type WorkspaceSelf = {
15
15
  url: string | null;
16
16
  ports: WorkspacePort[];
17
17
  };
18
+ /**
19
+ * `private`: only the workspace owner's signed-in GitTerm browser session can reach the URL.
20
+ * `public`: anyone with the URL can reach it, so it works for APIs and webhooks.
21
+ */
22
+ export type WorkspacePortVisibility = "private" | "public";
18
23
  export type WorkspacePort = {
19
24
  port: number;
20
25
  name: string | null;
26
+ visibility: WorkspacePortVisibility;
21
27
  url: string | null;
22
28
  };
23
29
  export type WorkspaceClientOptions = Partial<WorkspaceEnvironment> & {
@@ -31,9 +37,12 @@ export type GittermWorkspaceClient = {
31
37
  };
32
38
  ports: {
33
39
  list(): Promise<WorkspacePort[]>;
40
+ /** Ports open as `private` unless `visibility` is set; reopening keeps the current visibility. */
34
41
  open(port: number, options?: {
35
42
  name?: string;
43
+ visibility?: WorkspacePortVisibility;
36
44
  }): Promise<WorkspacePort>;
45
+ setVisibility(port: number, visibility: WorkspacePortVisibility): Promise<WorkspacePort>;
37
46
  close(port: number): Promise<{
38
47
  port: number;
39
48
  closed: boolean;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gitterm/sdk",
3
- "version": "0.3.0",
3
+ "version": "0.6.0",
4
4
  "files": [
5
5
  "dist"
6
6
  ],