@gitterm/sdk 0.1.2 → 0.2.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/dist/types.d.ts CHANGED
@@ -6,6 +6,13 @@ export type AuthStatus = {
6
6
  plan: string;
7
7
  authMethod: "session" | "apiToken";
8
8
  };
9
+ /**
10
+ * `pending` — compute is being provisioned or resumed; `runtime.url` is null.
11
+ * `running` — the provider reports the sandbox/container up. The agent may
12
+ * still be booting; `runs.create()` waits for it to answer.
13
+ * `paused` — stopped but resumable with `workspaces.ensureRunning()`.
14
+ * `terminated` — gone for good.
15
+ */
9
16
  export type WorkspaceStatus = "pending" | "running" | "paused" | "terminated";
10
17
  export type WorkspaceHostingType = "cloud" | "local";
11
18
  export type Workspace = {
@@ -33,12 +40,37 @@ export type Workspace = {
33
40
  name: string;
34
41
  imageId: string;
35
42
  } | null;
43
+ /** Caller-owned tags supplied at create time. */
44
+ metadata: Record<string, string>;
45
+ /** OpenCode HTTP API generation the workspace's agent server speaks. */
46
+ opencodeApi: OpencodeApi;
47
+ /** When set, the workspace is terminated at this time regardless of activity. */
48
+ autoTerminateAt: string | null;
49
+ /** The caller-supplied image or E2B template this workspace runs, if any. */
50
+ customImage: string | null;
36
51
  startedAt: string | null;
37
52
  pausedAt: string | null;
38
53
  terminatedAt: string | null;
39
54
  lastActiveAt: string | null;
40
55
  updatedAt: string | null;
41
56
  };
57
+ /** A workspace id, or any object carrying one (e.g. a `Workspace`). */
58
+ export type WorkspaceRef = string | {
59
+ id: string;
60
+ };
61
+ /** An `AgentRun`, or any object carrying its `workspaceId` and `id`. */
62
+ export type RunRef = {
63
+ workspaceId: string;
64
+ id: string;
65
+ };
66
+ /** `v1` = OpenCode 1.x (`/event`, `/session/*`); `v2` = OpenCode 2 (`/api/*`), experimental until 2.0 ships. */
67
+ export type OpencodeApi = "v1" | "v2";
68
+ export type WaitOptions = {
69
+ timeoutMs?: number;
70
+ pollIntervalMs?: number;
71
+ /** Abort the wait early; the promise rejects with code `ABORTED`. */
72
+ signal?: AbortSignal;
73
+ };
42
74
  export type WorkspaceRuntimeAccess = {
43
75
  workspaceId: string;
44
76
  status: WorkspaceStatus;
@@ -62,6 +94,8 @@ export type WorkspaceListOptions = {
62
94
  limit?: number;
63
95
  offset?: number;
64
96
  status?: "all" | "active" | "terminated";
97
+ /** Only workspaces whose metadata contains every given key/value. */
98
+ metadata?: Record<string, string>;
65
99
  };
66
100
  export type WorkspaceListResult = {
67
101
  workspaces: Workspace[];
@@ -156,6 +190,27 @@ export type AgentKey = BuiltInAgentKey | (string & {});
156
190
  export type WorkspaceCreateInput = {
157
191
  idempotencyKey?: string;
158
192
  name?: string;
193
+ /**
194
+ * Caller-owned tags (e.g. tenant or channel ids). Up to 20 keys of letters,
195
+ * digits, `_ . : -`; values up to 500 chars. Returned on the workspace and
196
+ * filterable with `workspaces.list({ metadata })`.
197
+ */
198
+ metadata?: Record<string, string>;
199
+ /**
200
+ * Terminate automatically this long after creation, whatever its activity.
201
+ * Between 1 minute and 30 days. Use it as a cost guardrail for ephemeral
202
+ * workspaces in case the caller crashes before `terminate()`.
203
+ */
204
+ autoTerminateAfterMs?: number;
205
+ /**
206
+ * Run your own image instead of the catalog image. Registry-backed providers
207
+ * (railway, aws, daytona, exedev) take an OCI reference such as
208
+ * `ghcr.io/acme/agent-runner:1.4.0`; E2B takes a public template id or
209
+ * alias. The managed service only runs images that can be pulled without
210
+ * credentials, and pins floating tags to a digest at create time. Build on
211
+ * `opeoginni/gitterm-opencode-server` and keep its entrypoint.
212
+ */
213
+ image?: string;
159
214
  repo: string;
160
215
  branch?: string;
161
216
  /** Commit SHA to pin the checkout to after cloning `branch`/`checkoutRef`. */
@@ -176,15 +231,8 @@ export type WorkspaceCreateInput = {
176
231
  /** Defaults from the selected provider. */
177
232
  persistent?: boolean;
178
233
  workspaceProfile?: "standard" | "ssh-enabled";
179
- /** Credential IDs from client.credentials.list(). Omit to inject dashboard defaults. */
180
- modelCredentialIds?: string[];
181
- /**
182
- * Inline API keys for this workspace only — injected at provision time and
183
- * never stored in the dashboard. An inline key overrides any dashboard
184
- * credential for the same provider. OAuth providers can't be supplied
185
- * inline; connect those in the dashboard.
186
- */
187
- modelCredentials?: WorkspaceModelCredentialInput[];
234
+ /** Omit to use dashboard defaults. An explicit block inherits nothing unless requested. */
235
+ models?: WorkspaceModelsInput;
188
236
  /** Ephemeral environment variables injected into this workspace only. */
189
237
  environmentVariables?: Record<string, string>;
190
238
  /**
@@ -218,6 +266,11 @@ export type WorkspaceCreateInput = {
218
266
  * webfetch: "allow" } } disables tool approval prompts in headless runs.
219
267
  */
220
268
  config?: Record<string, unknown>;
269
+ /**
270
+ * OpenCode API generation served by the image. Defaults to `v1`. Use `v2`
271
+ * with an image built on OpenCode 2 (`@opencode-ai/cli`); experimental.
272
+ */
273
+ api?: OpencodeApi;
221
274
  };
222
275
  };
223
276
  export type WorkspaceRestartResult = {
@@ -234,7 +287,64 @@ export type WorkspaceEnsureRunningResult = {
234
287
  workspace: Workspace;
235
288
  runtime: WorkspaceRuntimeAccess;
236
289
  };
237
- export type AgentRunStatus = "pending" | "running" | "retrying" | "completed" | "failed" | "cancelled";
290
+ export type AgentRunStatus = "pending" | "running" | "retrying"
291
+ /** Blocked on a permission prompt or agent question; answer with `runs.respond()`. */
292
+ | "awaiting_input" | "completed" | "failed" | "cancelled";
293
+ /** OpenCode asked to run a tool your `permission` config does not pre-approve. */
294
+ export type AgentPermissionRequest = {
295
+ id: string;
296
+ kind: "permission";
297
+ createdAt: string | null;
298
+ toolCallId: string | null;
299
+ /** Permission action, e.g. "bash" or "edit". */
300
+ permission: string;
301
+ /** What the action applies to, e.g. the shell command or file paths. */
302
+ patterns: string[];
303
+ /** Patterns OpenCode remembers when answered with "always". */
304
+ always: string[];
305
+ title: string;
306
+ };
307
+ /** One choice to show the user. Answer with the `label`. */
308
+ export type AgentQuestionOption = {
309
+ label: string;
310
+ description: string;
311
+ };
312
+ export type AgentQuestion = {
313
+ /** Identifies this question in `AgentRunReply.answers`. Unique within a request. */
314
+ key: string;
315
+ header: string;
316
+ question: string;
317
+ options: AgentQuestionOption[];
318
+ /** More than one option may be selected. */
319
+ multiple: boolean;
320
+ /** A free-text answer outside `options` is accepted. */
321
+ custom: boolean;
322
+ };
323
+ /** The agent called OpenCode's `question` tool. Answer every question in one reply. */
324
+ export type AgentQuestionRequest = {
325
+ id: string;
326
+ kind: "question";
327
+ createdAt: string | null;
328
+ toolCallId: string | null;
329
+ questions: AgentQuestion[];
330
+ };
331
+ /** A prompt the agent is blocked on. */
332
+ export type AgentRunInputRequest = AgentPermissionRequest | AgentQuestionRequest;
333
+ export type AgentRunReply = {
334
+ type: "permission";
335
+ response: "once" | "always" | "reject";
336
+ }
337
+ /**
338
+ * Keyed by `AgentQuestion.key`, each the selected option labels (or a single
339
+ * custom answer when the question allows one). Every question needs a key.
340
+ */
341
+ | {
342
+ type: "question";
343
+ answers: Record<string, string[]>;
344
+ } | {
345
+ type: "question";
346
+ reject: true;
347
+ };
238
348
  export type AgentRun = {
239
349
  id: string;
240
350
  workspaceId: string;
@@ -242,17 +352,47 @@ export type AgentRun = {
242
352
  status: AgentRunStatus;
243
353
  error: string | null;
244
354
  finalText: string | null;
355
+ /**
356
+ * Non-empty exactly while `status` is `awaiting_input`. Usually one request;
357
+ * several when the agent issued parallel tool calls that each need approval.
358
+ * Answer each with `runs.respond()`; the run resumes once none remain.
359
+ */
360
+ pendingInputs: AgentRunInputRequest[];
245
361
  context: {
246
362
  type: "isolated";
247
363
  } | {
248
364
  type: "continued";
249
365
  runId: string;
250
366
  };
367
+ createdAt: string;
368
+ /** When the prompt reached the agent; null while `pending`. */
369
+ submittedAt: string | null;
370
+ completedAt: string | null;
371
+ };
372
+ export type AgentRunListOptions = {
373
+ /** `active` = pending/running/retrying/awaiting_input; `terminal` = completed/failed/cancelled. */
374
+ status?: "all" | "active" | "terminal";
375
+ /** 1–50, default 20. */
376
+ limit?: number;
377
+ offset?: number;
378
+ };
379
+ export type AgentRunListResult = {
380
+ runs: AgentRun[];
381
+ pagination: {
382
+ total: number;
383
+ limit: number;
384
+ offset: number;
385
+ hasMore: boolean;
386
+ };
251
387
  };
252
388
  export type AgentRunCreateInput = {
253
- workspaceId: string;
254
- /** Stable key used to return the same run when a request is retried. */
255
- idempotencyKey: string;
389
+ workspace: WorkspaceRef;
390
+ /**
391
+ * Stable key used to return the same run when a request is retried.
392
+ * Defaults to a random UUID, which gives no retry protection; pass your own
393
+ * for anything a retry could duplicate.
394
+ */
395
+ idempotencyKey?: string;
256
396
  prompt: string;
257
397
  title?: string;
258
398
  agent?: string;
@@ -263,22 +403,105 @@ export type AgentRunCreateInput = {
263
403
  type: "isolated";
264
404
  } | {
265
405
  type: "continue";
266
- runId: string;
406
+ run: RunRef;
267
407
  };
268
- /** Wait for workspace setup commands before submitting the prompt. */
408
+ /**
409
+ * Wait for the `afterAgent` setup phase to succeed before submitting the
410
+ * prompt. Fails the call with the setup log if that phase failed.
411
+ */
269
412
  waitForSetup?: boolean;
270
413
  /** How long to wait for setup, in ms. Server maximum is 600000 (10 minutes). */
271
414
  setupTimeoutMs?: number;
415
+ /**
416
+ * How long to wait for a `pending` workspace to become `running`, in ms.
417
+ * Defaults to 120000; server maximum is 240000. Paused workspaces are not
418
+ * resumed — call `workspaces.ensureRunning()` first.
419
+ */
420
+ startTimeoutMs?: number;
421
+ /** Abort while waiting for setup or start; rejects with code `ABORTED`. */
422
+ signal?: AbortSignal;
423
+ };
424
+ export type AgentRunMessagePart = {
425
+ type: "text";
426
+ text: string;
427
+ } | {
428
+ type: "tool";
429
+ callId: string;
430
+ tool: string;
431
+ status: "pending" | "running" | "completed" | "error";
432
+ title: string | null;
433
+ input: Record<string, unknown>;
434
+ /** Tool output when completed, truncated to 4000 characters. */
435
+ output: string | null;
436
+ error: string | null;
437
+ startedAt: string | null;
438
+ completedAt: string | null;
439
+ };
440
+ export type RunWatchOptions = {
441
+ /** Stop the stream early; the iterator throws with code `ABORTED`. */
442
+ signal?: AbortSignal;
443
+ };
444
+ export type RunWaitOptions = RunWatchOptions & {
445
+ /** Default 30 minutes. When it elapses the promise rejects with code `TIMEOUT`. */
446
+ timeoutMs?: number;
447
+ /**
448
+ * `input-or-terminal` (default) also returns when the run is `awaiting_input`
449
+ * so the caller can answer with `runs.respond()`; `terminal` keeps waiting.
450
+ */
451
+ until?: "input-or-terminal" | "terminal";
452
+ };
453
+ export type AgentRunResult<T extends AgentRun = AgentRun> = T & {
454
+ status: "completed";
455
+ };
456
+ export type RunResultOptions = RunWatchOptions & {
457
+ /** Total deadline, including time spent in human-input handlers. Default 30 minutes. */
458
+ timeoutMs?: number;
459
+ onPermission?: (request: AgentPermissionRequest, options: {
460
+ signal: AbortSignal;
461
+ }) => AgentRunReplyPermission | Promise<AgentRunReplyPermission>;
462
+ onQuestion?: (request: AgentQuestionRequest, options: {
463
+ signal: AbortSignal;
464
+ }) => AgentRunReplyQuestion | Promise<AgentRunReplyQuestion>;
465
+ };
466
+ export type AgentRunReplyPermission = "once" | "always" | "reject";
467
+ export type AgentRunReplyQuestion = {
468
+ answers: Record<string, string[]>;
469
+ } | {
470
+ reject: true;
471
+ };
472
+ export type AgentRunEvent<T extends AgentRun = AgentRun> = {
473
+ type: "run.status";
474
+ run: T;
475
+ } | {
476
+ type: "input.required";
477
+ run: T;
478
+ request: AgentRunInputRequest;
479
+ } | {
480
+ type: "input.resolved";
481
+ run: T;
482
+ requestId: string;
483
+ } | {
484
+ type: "run.completed" | "run.failed" | "run.cancelled";
485
+ run: T;
272
486
  };
273
487
  export type AgentRunMessage = {
274
488
  id: string;
275
489
  role: "user" | "assistant";
276
490
  createdAt: string;
277
491
  completedAt: string | null;
492
+ /** Concatenated text parts. */
278
493
  text: string;
279
494
  error: string | null;
495
+ /** Ordered text and tool-call parts, for seeing what the agent actually did. */
496
+ parts: AgentRunMessagePart[];
280
497
  };
281
498
  export type WorkspaceSetupStatus = {
499
+ /**
500
+ * `not_requested` — no `afterAgent` commands. `waiting` — the agent isn't
501
+ * reachable yet, so setup hasn't started. `running`, `succeeded`, `failed`
502
+ * describe the `afterAgent` phase itself. A setup stuck in `waiting` for
503
+ * 15 minutes is marked `failed` with the reason in `log`.
504
+ */
282
505
  status: "not_requested" | "waiting" | "running" | "succeeded" | "failed";
283
506
  exitCode: number | null;
284
507
  startedAt: string | null;
@@ -293,19 +516,49 @@ export type WorkspaceSetupStatus = {
293
516
  export type ModelProviderInfo = {
294
517
  id: string;
295
518
  name: string;
519
+ /** Use this key in models.providers and provider/model references. */
520
+ logicalProviderKey: string;
296
521
  displayName: string;
297
522
  authType: string;
298
523
  isRecommended: boolean;
299
524
  };
300
- /**
301
- * An API key passed directly to workspaces.create(). `providerName` must be an
302
- * API-key provider from credentials.listProviders(), e.g. "anthropic" or
303
- * "openai"; unknown or OAuth-only providers throw MODEL_CREDENTIAL_INVALID.
304
- */
305
- export type WorkspaceModelCredentialInput = {
306
- providerName: string;
525
+ export type ModelInfo = {
526
+ /** Full provider/model identifier accepted by runs.create(). */
527
+ id: string;
528
+ name: string;
529
+ provider: string;
530
+ isFree: boolean;
531
+ isRecommended: boolean;
532
+ };
533
+ /** Control-plane configuration, not a live authentication check. */
534
+ export type WorkspaceModelAccess = {
535
+ providers: Array<{
536
+ provider: string;
537
+ source: "saved" | "apiKey";
538
+ label: string | null;
539
+ active: boolean;
540
+ }>;
541
+ /** Known catalog models whose provider is configured, plus free models. */
542
+ models: ModelInfo[];
543
+ };
544
+ /** Explicit credential intent. Saved sources use dashboard labels, never credential IDs. */
545
+ export type ModelCredentialSource = {
546
+ source: "saved";
547
+ label: string;
548
+ } | {
549
+ source: "default";
550
+ } | {
551
+ source: "apiKey";
307
552
  apiKey: string;
308
553
  };
554
+ export type WorkspaceModelsInput = {
555
+ /** Workspace default, overridden by runs.create({ model }). */
556
+ default?: string;
557
+ /** Default for an explicit block is none. */
558
+ inherit?: "defaults" | "none";
559
+ /** Keys are model provider names (e.g. openai for API keys AND ChatGPT subscriptions). */
560
+ providers?: Record<string, ModelCredentialSource>;
561
+ };
309
562
  /** Safe dashboard credential metadata. Secret material is never returned by the SDK. */
310
563
  export type ModelCredential = {
311
564
  id: string;
@@ -314,7 +567,8 @@ export type ModelCredential = {
314
567
  providerDisplayName: string;
315
568
  logicalProviderKey: string;
316
569
  authType: string;
317
- label: string | null;
570
+ /** Select with models.providers[logicalProviderKey] = { source: "saved", label }. */
571
+ label: string;
318
572
  keyHash: string;
319
573
  isActive: boolean;
320
574
  isDefault: boolean;
package/package.json CHANGED
@@ -1,10 +1,12 @@
1
1
  {
2
2
  "name": "@gitterm/sdk",
3
- "version": "0.1.2",
3
+ "version": "0.2.0",
4
4
  "files": [
5
5
  "dist"
6
6
  ],
7
7
  "type": "module",
8
+ "main": "./dist/index.js",
9
+ "types": "./dist/index.d.ts",
8
10
  "exports": {
9
11
  ".": {
10
12
  "types": "./dist/index.d.ts",
@@ -23,7 +25,7 @@
23
25
  "access": "public"
24
26
  },
25
27
  "scripts": {
26
- "build": "rm -rf dist && bun build src/index.ts src/direct/index.ts --outdir dist --target node --format esm --external @trpc/client --external @opencode-ai/sdk --external @opencode-ai/sdk/v2 --external e2b --external @asciidev/box-sdk --external @daytonaio/sdk --external @vercel/sandbox && tsc -p tsconfig.build.json",
28
+ "build": "rm -rf dist && bun build src/index.ts src/direct/index.ts --outdir dist --target node --format esm --external @trpc/client --external eventsource --external @opencode-ai/sdk --external @opencode-ai/sdk/v2 --external e2b --external @asciidev/box-sdk --external @daytonaio/sdk --external @vercel/sandbox && tsc -p tsconfig.build.json",
27
29
  "prepublishOnly": "bun run check-types && bun run build",
28
30
  "check-types": "tsc --noEmit"
29
31
  },
@@ -33,15 +35,17 @@
33
35
  "@opencode-ai/sdk": "^1.18.25",
34
36
  "@trpc/client": "^11.8.1",
35
37
  "@vercel/sandbox": "^3.2.1",
36
- "e2b": "^2.46.1"
38
+ "e2b": "^2.46.1",
39
+ "eventsource": "^5.1.1"
37
40
  },
38
41
  "devDependencies": {
42
+ "@gitterm/agent-runtime": "workspace:*",
39
43
  "@gitterm/api": "workspace:*",
40
44
  "@trpc/server": "catalog:",
41
45
  "@types/bun": "^1.2.6",
42
46
  "typescript": "^5.8.2"
43
47
  },
44
48
  "engines": {
45
- "node": ">=20.18.1"
49
+ "node": ">=22.12.0"
46
50
  }
47
51
  }