runline 0.11.4 → 0.11.6

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.
@@ -292,6 +292,11 @@ export function registerTablesActions(rl) {
292
292
  required: false,
293
293
  description: "Column width in points.",
294
294
  },
295
+ widthType: {
296
+ type: "string",
297
+ required: false,
298
+ description: "WIDTH_TYPE_UNSPECIFIED | EVENLY_DISTRIBUTED | FIXED_WIDTH. Defaults to FIXED_WIDTH when widthPt is provided.",
299
+ },
295
300
  fields: {
296
301
  type: "string",
297
302
  required: false,
@@ -307,7 +312,12 @@ export function registerTablesActions(rl) {
307
312
  const fields = [];
308
313
  if (p.widthPt !== undefined) {
309
314
  props.width = point(p.widthPt);
310
- fields.push("width");
315
+ props.widthType = p.widthType ?? "FIXED_WIDTH";
316
+ fields.push("width", "widthType");
317
+ }
318
+ else if (p.widthType) {
319
+ props.widthType = p.widthType;
320
+ fields.push("widthType");
311
321
  }
312
322
  const mask = p.fields ?? fields.join(",");
313
323
  if (!mask)
@@ -0,0 +1,15 @@
1
+ import * as t from "typebox";
2
+ import { registerIssueActions } from "./issues.js";
3
+ import { registerPageActions } from "./pages.js";
4
+ export default function shiftLabs(rl) {
5
+ rl.setName("shiftLabs");
6
+ rl.setVersion("0.1.0");
7
+ rl.setConnectionSchema(t.Object({
8
+ apiKey: t.String({
9
+ description: "Shift Labs API key",
10
+ env: "SHIFT_LABS_API_KEY",
11
+ }),
12
+ }));
13
+ registerIssueActions(rl);
14
+ registerPageActions(rl);
15
+ }
@@ -0,0 +1,70 @@
1
+ import * as t from "typebox";
2
+ import { enumSchema, ISSUE_KIND, ISSUE_PRIORITY, ISSUE_SEVERITY, ISSUE_SOURCE, ISSUE_STATUS, request, } from "./shared.js";
3
+ export function registerIssueActions(rl) {
4
+ rl.registerAction("issue.list", {
5
+ description: "List Shift Labs issues for the API key's organization.",
6
+ inputSchema: t.Object({
7
+ status: t.Optional(enumSchema("Issue status", ISSUE_STATUS)),
8
+ assigneeUserId: t.Optional(t.String()),
9
+ source: t.Optional(enumSchema("Issue source", ISSUE_SOURCE)),
10
+ limit: t.Optional(t.Number({ description: "Max results, default 50" })),
11
+ }),
12
+ async execute(input, ctx) {
13
+ const fields = (input ?? {});
14
+ const params = new URLSearchParams();
15
+ for (const key of ["status", "assigneeUserId", "source", "limit"]) {
16
+ const value = fields[key];
17
+ if (value !== undefined)
18
+ params.set(key, String(value));
19
+ }
20
+ const body = await request(ctx, `/v1/issues?${params}`);
21
+ return body.issues;
22
+ },
23
+ });
24
+ rl.registerAction("issue.get", {
25
+ description: "Get a Shift Labs issue by ID.",
26
+ inputSchema: t.Object({ id: t.String({ description: "Issue ID" }) }),
27
+ async execute(input, ctx) {
28
+ const { id } = input;
29
+ const body = await request(ctx, `/v1/issues/${encodeURIComponent(id)}`);
30
+ return body.issue;
31
+ },
32
+ });
33
+ rl.registerAction("issue.create", {
34
+ description: "Create a Shift Labs issue. The issue starts in triage.",
35
+ inputSchema: t.Object({
36
+ title: t.String({ description: "Issue title" }),
37
+ description: t.Optional(t.String({ description: "Issue description" })),
38
+ kind: t.Optional(enumSchema("Issue kind", ISSUE_KIND)),
39
+ priority: t.Optional(enumSchema("Issue priority", ISSUE_PRIORITY)),
40
+ severity: t.Optional(enumSchema("Issue severity", ISSUE_SEVERITY)),
41
+ source: t.Optional(enumSchema("Issue source", ISSUE_SOURCE)),
42
+ deploymentId: t.Optional(t.String()),
43
+ workspaceId: t.Optional(t.String()),
44
+ sessionId: t.Optional(t.String()),
45
+ traceId: t.Optional(t.String()),
46
+ fingerprint: t.Optional(t.String()),
47
+ labels: t.Optional(t.Array(t.String())),
48
+ metadata: t.Optional(t.Object({}, { description: "Issue metadata" })),
49
+ }),
50
+ async execute(input, ctx) {
51
+ const body = await request(ctx, "/v1/issues", {
52
+ method: "POST",
53
+ body: JSON.stringify(input),
54
+ });
55
+ return body.issue;
56
+ },
57
+ });
58
+ rl.registerAction("issue.comment", {
59
+ description: "Add a comment to a Shift Labs issue.",
60
+ inputSchema: t.Object({
61
+ id: t.String({ description: "Issue ID" }),
62
+ body: t.String({ description: "Comment body" }),
63
+ }),
64
+ async execute(input, ctx) {
65
+ const { id, body } = input;
66
+ const response = await request(ctx, `/v1/issues/${encodeURIComponent(id)}/comments`, { method: "POST", body: JSON.stringify({ body }) });
67
+ return response.event;
68
+ },
69
+ });
70
+ }
@@ -0,0 +1,138 @@
1
+ import * as t from "typebox";
2
+ import { enumSchema, PAGE_STATUS, PAGE_VISIBILITY, pageRenderUrl, request, } from "./shared.js";
3
+ export function registerPageActions(rl) {
4
+ rl.registerAction("page.list", {
5
+ description: "List Shift Labs pages for the API key's organization.",
6
+ inputSchema: t.Object({
7
+ status: t.Optional(enumSchema("Page status", PAGE_STATUS)),
8
+ limit: t.Optional(t.Number({ description: "Max results, default 50" })),
9
+ }),
10
+ async execute(input, ctx) {
11
+ const fields = (input ?? {});
12
+ const params = new URLSearchParams();
13
+ if (fields.status)
14
+ params.set("status", String(fields.status));
15
+ if (fields.limit)
16
+ params.set("limit", String(fields.limit));
17
+ const body = await request(ctx, `/v1/pages?${params}`);
18
+ return body.pages;
19
+ },
20
+ });
21
+ rl.registerAction("page.get", {
22
+ description: "Get a Shift Labs page by ID.",
23
+ inputSchema: t.Object({ id: t.String({ description: "Page ID" }) }),
24
+ async execute(input, ctx) {
25
+ const { id } = input;
26
+ const body = await request(ctx, `/v1/pages/${encodeURIComponent(id)}`);
27
+ return body.page;
28
+ },
29
+ });
30
+ rl.registerAction("page.create", {
31
+ description: "Create a draft hosted HTML page. Agents can publish it with page.publish.",
32
+ inputSchema: t.Object({
33
+ slug: t.String({ description: "Lowercase kebab-case page slug" }),
34
+ title: t.String({ description: "Page title" }),
35
+ html: t.Optional(t.String({ description: "Hosted HTML content" })),
36
+ visibility: t.Optional(enumSchema("Page visibility", PAGE_VISIBILITY)),
37
+ }),
38
+ async execute(input, ctx) {
39
+ const fields = input;
40
+ const body = await request(ctx, "/v1/pages", {
41
+ method: "POST",
42
+ body: JSON.stringify({
43
+ type: "hosted_html",
44
+ visibility: "org",
45
+ ...fields,
46
+ }),
47
+ });
48
+ return body.page;
49
+ },
50
+ });
51
+ rl.registerAction("page.update", {
52
+ description: "Update a hosted HTML page's slug, title, visibility, or HTML.",
53
+ inputSchema: t.Object({
54
+ id: t.String({ description: "Page ID" }),
55
+ slug: t.Optional(t.String({ description: "Lowercase kebab-case page slug" })),
56
+ title: t.Optional(t.String({ description: "Page title" })),
57
+ visibility: t.Optional(enumSchema("Page visibility", PAGE_VISIBILITY)),
58
+ html: t.Optional(t.String({ description: "Hosted HTML content" })),
59
+ }),
60
+ async execute(input, ctx) {
61
+ const { id, ...fields } = input;
62
+ const body = await request(ctx, `/v1/pages/${encodeURIComponent(id)}`, {
63
+ method: "PATCH",
64
+ body: JSON.stringify(fields),
65
+ });
66
+ return body.page;
67
+ },
68
+ });
69
+ rl.registerAction("page.publish", {
70
+ description: "Publish a Shift Labs hosted HTML page.",
71
+ inputSchema: t.Object({ id: t.String({ description: "Page ID" }) }),
72
+ async execute(input, ctx) {
73
+ const { id } = input;
74
+ const body = await request(ctx, `/v1/pages/${encodeURIComponent(id)}/publish`, { method: "POST" });
75
+ return body.page;
76
+ },
77
+ });
78
+ rl.registerAction("page.archive", {
79
+ description: "Archive a Shift Labs page.",
80
+ inputSchema: t.Object({ id: t.String({ description: "Page ID" }) }),
81
+ async execute(input, ctx) {
82
+ const { id } = input;
83
+ const body = await request(ctx, `/v1/pages/${encodeURIComponent(id)}/archive`, { method: "POST" });
84
+ return body.page;
85
+ },
86
+ });
87
+ rl.registerAction("page.shares", {
88
+ description: "List shares for a Shift Labs page.",
89
+ inputSchema: t.Object({ pageId: t.String({ description: "Page ID" }) }),
90
+ async execute(input, ctx) {
91
+ const { pageId } = input;
92
+ const body = await request(ctx, `/v1/pages/${encodeURIComponent(pageId)}/shares`);
93
+ return body.shares;
94
+ },
95
+ });
96
+ rl.registerAction("page.share", {
97
+ description: "Create a viewer share for a Shift Labs page.",
98
+ inputSchema: t.Object({
99
+ pageId: t.String({ description: "Page ID" }),
100
+ email: t.String({ description: "Viewer email address" }),
101
+ expiresAt: t.Optional(t.String({ description: "Optional ISO expiration" })),
102
+ }),
103
+ async execute(input, ctx) {
104
+ const { pageId, ...fields } = input;
105
+ const body = await request(ctx, `/v1/pages/${encodeURIComponent(pageId)}/shares`, {
106
+ method: "POST",
107
+ body: JSON.stringify(fields),
108
+ });
109
+ return body.share;
110
+ },
111
+ });
112
+ rl.registerAction("page.revokeShare", {
113
+ description: "Revoke a Shift Labs page share.",
114
+ inputSchema: t.Object({
115
+ shareId: t.String({ description: "Page share ID" }),
116
+ }),
117
+ async execute(input, ctx) {
118
+ const { shareId } = input;
119
+ await request(ctx, `/v1/pages/shares/${encodeURIComponent(shareId)}`, {
120
+ method: "DELETE",
121
+ });
122
+ return { success: true };
123
+ },
124
+ });
125
+ rl.registerAction("page.renderUrl", {
126
+ description: "Return the authenticated render URL for a page.",
127
+ inputSchema: t.Object({
128
+ pageId: t.String({ description: "Page ID" }),
129
+ }),
130
+ async execute(input, ctx) {
131
+ const { pageId } = input;
132
+ const body = await request(ctx, `/v1/pages/${encodeURIComponent(pageId)}`);
133
+ return {
134
+ url: pageRenderUrl(body.page.organizationId, body.page.slug),
135
+ };
136
+ },
137
+ });
138
+ }
@@ -0,0 +1,69 @@
1
+ import * as t from "typebox";
2
+ const SHIFT_LABS_API_URL = "https://d1ood6y5zobtne.cloudfront.net";
3
+ export function baseUrl() {
4
+ return `${SHIFT_LABS_API_URL}/`;
5
+ }
6
+ export async function request(ctx, path, init = {}) {
7
+ const headers = new Headers(init.headers);
8
+ const apiKey = ctx.connection.config.apiKey;
9
+ if (typeof apiKey !== "string" || !apiKey) {
10
+ throw new Error("Shift Labs apiKey is required");
11
+ }
12
+ headers.set("authorization", `Bearer ${apiKey}`);
13
+ if (init.body && !headers.has("content-type")) {
14
+ headers.set("content-type", "application/json");
15
+ }
16
+ const response = await fetch(new URL(path, baseUrl()), {
17
+ ...init,
18
+ headers,
19
+ });
20
+ if (!response.ok) {
21
+ throw new Error(`Shift Labs API error ${response.status}: ${await response.text()}`);
22
+ }
23
+ if (response.status === 204)
24
+ return undefined;
25
+ return (await response.json());
26
+ }
27
+ export function pathSegment(value) {
28
+ return encodeURIComponent(value);
29
+ }
30
+ export function pageRenderUrl(organizationId, slug) {
31
+ return new URL(`/pages/${pathSegment(organizationId)}/${pathSegment(slug)}`, baseUrl()).toString();
32
+ }
33
+ export const ISSUE_STATUS = [
34
+ "triage",
35
+ "open",
36
+ "in_progress",
37
+ "resolved",
38
+ "closed",
39
+ ];
40
+ export const ISSUE_KIND = [
41
+ "bug",
42
+ "support",
43
+ "feature_request",
44
+ "incident",
45
+ "task",
46
+ ];
47
+ export const ISSUE_PRIORITY = [
48
+ "none",
49
+ "low",
50
+ "medium",
51
+ "high",
52
+ "urgent",
53
+ ];
54
+ export const ISSUE_SEVERITY = ["info", "warning", "error", "critical"];
55
+ export const ISSUE_SOURCE = [
56
+ "user",
57
+ "agent",
58
+ "system",
59
+ "api",
60
+ "integration",
61
+ ];
62
+ export const PAGE_STATUS = ["draft", "published", "archived"];
63
+ export const PAGE_VISIBILITY = ["org", "invited"];
64
+ export function enumDescription(name, values) {
65
+ return `${name}: ${values.join(" | ")}`;
66
+ }
67
+ export function enumSchema(name, values) {
68
+ return t.Union(values.map((value) => t.Literal(value)), { description: enumDescription(name, values) });
69
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "runline",
3
- "version": "0.11.4",
3
+ "version": "0.11.6",
4
4
  "description": "Code mode for agents — turn any API or command into a callable action",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",