@gitterm/sdk 0.4.0 → 0.6.1

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 v1. v2 requires a compatible provider image/template. */
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
@@ -112,6 +112,23 @@ function normalizeServerUrl(value) {
112
112
  url.search = "";
113
113
  return url.toString().replace(/\/$/, "");
114
114
  }
115
+ function withPath(serverUrl, pathname) {
116
+ const url = new URL(serverUrl);
117
+ url.pathname = pathname;
118
+ return url.toString();
119
+ }
120
+ function basePath(serverUrl) {
121
+ return new URL(serverUrl).pathname.replace(/\/+$/, "");
122
+ }
123
+ function trpcEndpoint(serverUrl) {
124
+ const base = basePath(serverUrl);
125
+ return withPath(serverUrl, base.endsWith("/trpc") ? base : `${base}/trpc`);
126
+ }
127
+ function apiEndpoint(serverUrl, route) {
128
+ const base = basePath(serverUrl);
129
+ const apiBase = base.endsWith("/api") ? base : `${base}/api`;
130
+ return withPath(serverUrl, `${apiBase}/${route.replace(/^\/+/, "")}`);
131
+ }
115
132
  function createNoRedirectFetch(fetchImpl = fetch) {
116
133
  return async (input, init) => {
117
134
  const response = await fetchImpl(input, { ...init, redirect: "manual" });
@@ -270,6 +287,9 @@ function runHelpers(operations) {
270
287
  }
271
288
 
272
289
  // src/client.ts
290
+ function toConnection(connection) {
291
+ return { ...connection, connectedAt: toIso(connection.connectedAt) };
292
+ }
273
293
  function envValue(name) {
274
294
  const value = typeof process !== "undefined" ? process.env[name] : undefined;
275
295
  return value && value.trim() ? value : undefined;
@@ -283,9 +303,6 @@ function resolveCredentials(options) {
283
303
  }
284
304
  return { serverUrl: normalizeServerUrl(serverUrl), token };
285
305
  }
286
- function toTrpcUrl(serverUrl) {
287
- return new URL("/trpc", serverUrl).toString();
288
- }
289
306
  function toIso(value) {
290
307
  if (!value)
291
308
  return null;
@@ -351,7 +368,6 @@ function normalizeWorkspace(workspace) {
351
368
  imageId: workspace.image.imageId
352
369
  } : null,
353
370
  metadata: workspace.metadata ?? {},
354
- opencodeApi: workspace.opencodeApi ?? "v1",
355
371
  autoTerminateAt: toIso(workspace.autoTerminateAt),
356
372
  customImage: workspace.customImage ?? null,
357
373
  startedAt: toIso(workspace.startedAt),
@@ -490,14 +506,14 @@ function createGittermClient(options = {}) {
490
506
  splitLink({
491
507
  condition: (operation) => operation.type === "subscription",
492
508
  true: httpSubscriptionLink({
493
- url: toTrpcUrl(credentials.serverUrl),
509
+ url: trpcEndpoint(credentials.serverUrl),
494
510
  EventSource,
495
511
  eventSourceOptions: {
496
512
  fetch: (url, init) => fetchImpl(url, { ...init, headers: { ...init.headers, authorization } })
497
513
  }
498
514
  }),
499
515
  false: httpBatchLink({
500
- url: toTrpcUrl(credentials.serverUrl),
516
+ url: trpcEndpoint(credentials.serverUrl),
501
517
  fetch: fetchImpl,
502
518
  headers: () => ({ authorization })
503
519
  })
@@ -534,7 +550,7 @@ function createGittermClient(options = {}) {
534
550
  const timeoutMs = waitOptions?.timeoutMs ?? 10 * 60000;
535
551
  const pollIntervalMs = waitOptions?.pollIntervalMs ?? 2000;
536
552
  const signal = waitOptions?.signal;
537
- const deadline2 = Date.now() + timeoutMs;
553
+ const deadline = Date.now() + timeoutMs;
538
554
  while (true) {
539
555
  throwIfAborted(signal, "waiting for workspace setup");
540
556
  const result = await trpc.workspace.getSetupStatus.query({ workspaceId }, { signal });
@@ -545,7 +561,7 @@ function createGittermClient(options = {}) {
545
561
  throw new GittermError("BAD_REQUEST", `Workspace setup failed${result.exitCode === null ? "" : ` with exit code ${result.exitCode}`}${log ? `
546
562
  ${log}` : ""}`);
547
563
  }
548
- if (Date.now() >= deadline2) {
564
+ if (Date.now() >= deadline) {
549
565
  const log = result.log?.trim();
550
566
  throw new GittermError("TIMEOUT", `Timed out waiting for workspace ${workspaceId} setup (last status: ${result.status})${log ? `
551
567
  ${log}` : ""}`);
@@ -674,44 +690,43 @@ ${log}` : ""}`);
674
690
  }),
675
691
  workspaceOptions: () => run(async () => trpc.workspace.getWorkspaceCatalog.query())
676
692
  },
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
693
  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
- }));
694
+ catalog: () => run(async () => trpc.integrations.catalog.query()),
695
+ connections: {
696
+ list: (filter) => run(async () => {
697
+ const result = await trpc.integrations.connections.list.query(filter);
698
+ return result.map(toConnection);
699
+ }),
700
+ get: (id) => run(async () => toConnection(await trpc.integrations.connections.get.query({ id }))),
701
+ create: (input) => run(async () => {
702
+ const result = await trpc.integrations.connections.create.mutate(input);
703
+ return result.status === "connected" ? { ...result, connection: toConnection(result.connection) } : result;
704
+ }),
705
+ remove: (id) => run(async () => {
706
+ await trpc.integrations.connections.remove.mutate({ id });
707
+ }),
708
+ waitFor: ({ integration, since, timeoutMs = 5 * 60000, intervalMs = 3000 }) => run(async () => {
709
+ const sinceMs = since ? new Date(since).getTime() : 0;
710
+ const deadline = Date.now() + timeoutMs;
711
+ while (Date.now() < deadline) {
712
+ const result = await trpc.integrations.connections.list.query({
713
+ integration,
714
+ kind: "personal"
715
+ });
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];
717
+ if (match)
718
+ return match;
719
+ await new Promise((resolve) => setTimeout(resolve, intervalMs));
720
+ }
721
+ throw new Error(`Timed out waiting for a ${integration} connection`);
701
722
  })
702
723
  },
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
- })
724
+ github: {
725
+ repositories: (connectionId) => run(async () => trpc.integrations.github.repositories.query({ connectionId })),
726
+ branches: (connectionId, owner, repo) => run(async () => trpc.integrations.github.branches.query({ connectionId, owner, repo }))
727
+ },
728
+ google: {
729
+ setup: () => run(async () => trpc.integrations.google.setup.query())
715
730
  }
716
731
  },
717
732
  credentials: {
@@ -746,7 +761,7 @@ function sleep2(ms) {
746
761
  async function loginWithDeviceCode(serverUrl, options = {}) {
747
762
  const normalizedServerUrl = normalizeServerUrl(serverUrl);
748
763
  const fetchImpl = createNoRedirectFetch(options.fetch);
749
- const codeRes = await fetchImpl(new URL("/api/device/code", normalizedServerUrl), {
764
+ const codeRes = await fetchImpl(apiEndpoint(normalizedServerUrl, "device/code"), {
750
765
  method: "POST",
751
766
  headers: { "content-type": "application/json" },
752
767
  body: JSON.stringify({ clientName: options.clientName ?? "gitterm" })
@@ -760,9 +775,9 @@ async function loginWithDeviceCode(serverUrl, options = {}) {
760
775
  intervalSeconds: codeJson.intervalSeconds,
761
776
  expiresInSeconds: codeJson.expiresInSeconds
762
777
  });
763
- const deadline2 = Date.now() + codeJson.expiresInSeconds * 1000;
764
- while (Date.now() < deadline2) {
765
- const tokenRes = await fetchImpl(new URL("/api/device/token", normalizedServerUrl), {
778
+ const deadline = Date.now() + codeJson.expiresInSeconds * 1000;
779
+ while (Date.now() < deadline) {
780
+ const tokenRes = await fetchImpl(apiEndpoint(normalizedServerUrl, "device/token"), {
766
781
  method: "POST",
767
782
  headers: { "content-type": "application/json" },
768
783
  body: JSON.stringify({ deviceCode: codeJson.deviceCode })
@@ -801,10 +816,6 @@ function errorCode(code) {
801
816
  return code;
802
817
  return "SERVER_ERROR";
803
818
  }
804
- function toWorkspaceTrpcUrl(serverUrl) {
805
- const url = new URL(serverUrl);
806
- return url.pathname.endsWith("/trpc") ? serverUrl : new URL("/trpc", url).toString();
807
- }
808
819
  function createGittermWorkspaceClient(options = {}) {
809
820
  const detected = options.serverUrl && options.token && options.workspaceId ? null : getWorkspaceEnvironment();
810
821
  const rawServerUrl = options.serverUrl ?? detected?.serverUrl;
@@ -817,7 +828,7 @@ function createGittermWorkspaceClient(options = {}) {
817
828
  const trpc = createTRPCClient2({
818
829
  links: [
819
830
  httpBatchLink2({
820
- url: toWorkspaceTrpcUrl(serverUrl),
831
+ url: trpcEndpoint(serverUrl),
821
832
  fetch: createNoRedirectFetch(options.fetch),
822
833
  headers: () => ({ authorization: `Bearer ${token}` })
823
834
  })
@@ -840,6 +851,7 @@ function createGittermWorkspaceClient(options = {}) {
840
851
  ports: {
841
852
  list: () => run(() => trpc.workspaceOps.listPorts.query()),
842
853
  open: (port, input) => run(() => trpc.workspaceOps.openPort.mutate({ port, ...input })),
854
+ setVisibility: (port, visibility) => run(() => trpc.workspaceOps.setPortVisibility.mutate({ port, visibility })),
843
855
  close: (port) => run(() => trpc.workspaceOps.closePort.mutate({ port }))
844
856
  }
845
857
  };
@@ -1,2 +1,9 @@
1
1
  export declare function normalizeServerUrl(value: string): string;
2
+ /**
3
+ * Resolve the tRPC endpoint relative to the server URL's path, so a base like
4
+ * `https://host/api` (path-routing proxy) maps to `https://host/api/trpc`.
5
+ */
6
+ export declare function trpcEndpoint(serverUrl: string): string;
7
+ /** Resolve a server `/api/*` route, adding `/api` only when the base doesn't already end in it. */
8
+ export declare function apiEndpoint(serverUrl: string, route: string): string;
2
9
  export declare function createNoRedirectFetch(fetchImpl?: typeof fetch): typeof fetch;
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/*`) and the default; `v2` = OpenCode 2 (`/api/*`). */
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,28 +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 `v1`. Use `v2`
276
- * only with an explicitly compatible image.
277
- */
278
- api?: OpencodeApi;
279
271
  };
280
272
  };
281
- export type GitHubIntegration = {
282
- 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";
283
290
  accountLogin: string;
284
- accountType: string;
285
- repositorySelection: string;
286
- suspended: boolean;
287
- connectedAt: string;
291
+ accountType?: string;
292
+ repositorySelection?: "all" | "selected";
293
+ installationId?: string;
294
+ patSuffix?: string;
288
295
  };
289
- 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 = {
290
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";
291
324
  name: string;
292
325
  projectId: string;
326
+ /** projects/<number>/locations/global/workloadIdentityPools/<pool>/providers/<provider> */
293
327
  workloadIdentityProvider: string;
294
328
  serviceAccountEmail: string;
295
- 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>;
296
365
  };
297
366
  export type WorkspaceRestartResult = {
298
367
  status: WorkspaceStatus;
@@ -547,14 +616,6 @@ export type ModelProviderInfo = {
547
616
  authType: string;
548
617
  isRecommended: boolean;
549
618
  };
550
- export type ModelInfo = {
551
- /** Full provider/model identifier accepted by runs.create(). */
552
- id: string;
553
- name: string;
554
- provider: string;
555
- isFree: boolean;
556
- isRecommended: boolean;
557
- };
558
619
  /** Control-plane configuration, not a live authentication check. */
559
620
  export type WorkspaceModelAccess = {
560
621
  providers: Array<{
@@ -563,8 +624,6 @@ export type WorkspaceModelAccess = {
563
624
  label: string | null;
564
625
  active: boolean;
565
626
  }>;
566
- /** Known catalog models whose provider is configured, plus free models. */
567
- models: ModelInfo[];
568
627
  };
569
628
  /** Explicit credential intent. Saved sources use dashboard labels, never credential IDs. */
570
629
  export type ModelCredentialSource = {
@@ -595,6 +654,8 @@ export type ModelCredential = {
595
654
  /** Select with models.providers[logicalProviderKey] = { source: "saved", label }. */
596
655
  label: string;
597
656
  keyHash: string;
657
+ /** Last four characters of the API key; null for OAuth credentials. */
658
+ keySuffix: string | null;
598
659
  isActive: boolean;
599
660
  isDefault: boolean;
600
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.4.0",
3
+ "version": "0.6.1",
4
4
  "files": [
5
5
  "dist"
6
6
  ],