runline 0.11.2 → 0.11.4

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.
Files changed (31) hide show
  1. package/dist/plugin/loader.js +5 -0
  2. package/dist/plugins/googleDocs/src/documents.js +91 -0
  3. package/dist/plugins/googleDocs/src/formatting.js +126 -0
  4. package/dist/plugins/googleDocs/src/images.js +66 -0
  5. package/dist/plugins/googleDocs/src/index.js +45 -1008
  6. package/dist/plugins/googleDocs/src/shared.js +110 -0
  7. package/dist/plugins/googleDocs/src/structure.js +392 -0
  8. package/dist/plugins/googleDocs/src/tables.js +390 -0
  9. package/dist/plugins/googleDocs/src/tabs.js +77 -0
  10. package/dist/plugins/googleDocs/src/text.js +313 -0
  11. package/dist/plugins/linear/src/attachments.js +36 -12
  12. package/dist/plugins/linear/src/comments.js +20 -8
  13. package/dist/plugins/linear/src/cycles.js +22 -8
  14. package/dist/plugins/linear/src/initiatives.js +59 -19
  15. package/dist/plugins/linear/src/issues.js +123 -41
  16. package/dist/plugins/linear/src/labels.js +31 -11
  17. package/dist/plugins/linear/src/organization.js +1 -1
  18. package/dist/plugins/linear/src/projects.js +171 -57
  19. package/dist/plugins/linear/src/shared.js +16 -5
  20. package/dist/plugins/linear/src/states.js +14 -6
  21. package/dist/plugins/linear/src/teams.js +35 -12
  22. package/dist/plugins/linear/src/users.js +7 -3
  23. package/dist/plugins/linear/src/views.js +29 -10
  24. package/dist/plugins/linear/src/webhooks.js +39 -13
  25. package/dist/plugins/salesforce/src/index.js +33 -219
  26. package/dist/plugins/salesforce/src/metadata.js +50 -0
  27. package/dist/plugins/salesforce/src/query.js +52 -0
  28. package/dist/plugins/salesforce/src/queryResult.js +4 -0
  29. package/dist/plugins/salesforce/src/shared.js +122 -0
  30. package/dist/plugins/salesforce/src/sobjects.js +152 -0
  31. package/package.json +1 -1
@@ -0,0 +1,122 @@
1
+ export const DEFAULT_API_VERSION = "v59.0";
2
+ export function config(ctx) {
3
+ return ctx.connection.config;
4
+ }
5
+ export function trimTrailingSlash(url) {
6
+ return url.replace(/\/+$/, "");
7
+ }
8
+ function requireString(value, name) {
9
+ if (typeof value !== "string" || value.trim() === "") {
10
+ throw new Error(`Salesforce connection is missing ${name}`);
11
+ }
12
+ return value.trim();
13
+ }
14
+ export function apiVersion(ctx) {
15
+ const raw = config(ctx).apiVersion;
16
+ if (typeof raw !== "string" || raw.trim() === "")
17
+ return DEFAULT_API_VERSION;
18
+ const version = raw.trim();
19
+ return version.startsWith("v") ? version : `v${version}`;
20
+ }
21
+ export function validateInstanceUrl(url) {
22
+ const normalized = trimTrailingSlash(url.trim());
23
+ if (/\.lightning\.force\.com$/i.test(new URL(normalized).hostname)) {
24
+ throw new Error("Salesforce instanceUrl/loginUrl must be the API My Domain URL, not the Lightning UI URL. Use a URL like https://your-domain.my.salesforce.com.");
25
+ }
26
+ return normalized;
27
+ }
28
+ export async function getSession(ctx) {
29
+ const c = config(ctx);
30
+ if (c.accessToken) {
31
+ return {
32
+ instanceUrl: validateInstanceUrl(requireString(c.instanceUrl, "instanceUrl")),
33
+ accessToken: requireString(c.accessToken, "accessToken"),
34
+ tokenType: "Bearer",
35
+ };
36
+ }
37
+ const loginUrl = validateInstanceUrl(requireString(c.loginUrl ?? c.instanceUrl, "loginUrl or instanceUrl"));
38
+ const clientId = requireString(c.clientId, "clientId");
39
+ const clientSecret = requireString(c.clientSecret, "clientSecret");
40
+ const body = new URLSearchParams();
41
+ body.set("grant_type", "client_credentials");
42
+ body.set("client_id", clientId);
43
+ body.set("client_secret", clientSecret);
44
+ const res = await fetch(`${loginUrl}/services/oauth2/token`, {
45
+ method: "POST",
46
+ headers: {
47
+ Accept: "application/json",
48
+ "Content-Type": "application/x-www-form-urlencoded",
49
+ },
50
+ body,
51
+ });
52
+ const text = await res.text();
53
+ let data;
54
+ try {
55
+ data = text ? JSON.parse(text) : {};
56
+ }
57
+ catch {
58
+ data = { raw: text };
59
+ }
60
+ if (!res.ok) {
61
+ const err = typeof data.error === "string" ? data.error : res.status;
62
+ const description = typeof data.error_description === "string"
63
+ ? `: ${data.error_description}`
64
+ : "";
65
+ throw new Error(`Salesforce token error ${err}${description}`);
66
+ }
67
+ return {
68
+ instanceUrl: validateInstanceUrl(requireString(data.instance_url, "token response instance_url")),
69
+ accessToken: requireString(data.access_token, "token response access_token"),
70
+ tokenType: typeof data.token_type === "string" ? data.token_type : "Bearer",
71
+ scope: typeof data.scope === "string" ? data.scope : undefined,
72
+ id: typeof data.id === "string" ? data.id : undefined,
73
+ issuedAt: typeof data.issued_at === "string" ? data.issued_at : undefined,
74
+ };
75
+ }
76
+ export async function api(ctx, method, endpoint, body, qs, session = getSession(ctx)) {
77
+ return rest(ctx, method, `/services/data/${apiVersion(ctx)}${endpoint}`, body, qs, session);
78
+ }
79
+ export async function rest(ctx, method, path, body, qs, session = getSession(ctx)) {
80
+ const resolvedSession = await session;
81
+ const url = new URL(path, resolvedSession.instanceUrl);
82
+ if (qs) {
83
+ for (const [k, v] of Object.entries(qs)) {
84
+ if (v !== undefined && v !== null)
85
+ url.searchParams.set(k, String(v));
86
+ }
87
+ }
88
+ const init = {
89
+ method,
90
+ headers: {
91
+ Authorization: `Bearer ${resolvedSession.accessToken}`,
92
+ Accept: "application/json",
93
+ "Content-Type": "application/json",
94
+ },
95
+ };
96
+ if (body && Object.keys(body).length > 0)
97
+ init.body = JSON.stringify(body);
98
+ const res = await fetch(url.toString(), init);
99
+ if (res.status === 204)
100
+ return { success: true };
101
+ const text = await res.text();
102
+ if (!res.ok)
103
+ throw new Error(`Salesforce error ${res.status}: ${text}`);
104
+ return text ? JSON.parse(text) : null;
105
+ }
106
+ export async function identity(ctx) {
107
+ const session = await getSession(ctx);
108
+ if (!session.id) {
109
+ return { instanceUrl: session.instanceUrl, tokenType: session.tokenType };
110
+ }
111
+ const res = await fetch(session.id, {
112
+ headers: {
113
+ Authorization: `Bearer ${session.accessToken}`,
114
+ Accept: "application/json",
115
+ },
116
+ });
117
+ const text = await res.text();
118
+ if (!res.ok) {
119
+ throw new Error(`Salesforce identity error ${res.status}: ${text}`);
120
+ }
121
+ return text ? JSON.parse(text) : {};
122
+ }
@@ -0,0 +1,152 @@
1
+ import * as t from "typebox";
2
+ import { records } from "./queryResult.js";
3
+ import { api } from "./shared.js";
4
+ export const SOBJECTS = [
5
+ "Account",
6
+ "Contact",
7
+ "Lead",
8
+ "Opportunity",
9
+ "Case",
10
+ "Task",
11
+ "User",
12
+ ];
13
+ export const DEFAULT_FIELDS = {
14
+ Account: "Id,Name,Type",
15
+ Contact: "Id,FirstName,LastName,Email",
16
+ Lead: "Id,Company,FirstName,LastName,Email,Status",
17
+ Opportunity: "Id,AccountId,Amount,Probability,StageName",
18
+ Case: "Id,AccountId,ContactId,Priority,Status,Subject",
19
+ Task: "Id,Subject,Status,Priority",
20
+ User: "Id,Name,Email",
21
+ };
22
+ const Data = t.Record(t.String(), t.Unknown(), {
23
+ description: "Salesforce field values",
24
+ });
25
+ const QueryInput = (sObject) => t.Object({
26
+ fields: t.Optional(t.String({
27
+ description: `Comma-separated fields (default: ${DEFAULT_FIELDS[sObject] ?? "Id"})`,
28
+ })),
29
+ where: t.Optional(t.String({ description: "SOQL WHERE clause" })),
30
+ limit: t.Optional(t.Number({ description: "Max records" })),
31
+ });
32
+ function buildQuery(sObject, input) {
33
+ const p = (input ?? {});
34
+ const fields = p.fields || DEFAULT_FIELDS[sObject] || "Id";
35
+ let q = `SELECT ${fields} FROM ${sObject}`;
36
+ if (p.where)
37
+ q += ` WHERE ${p.where}`;
38
+ if (p.limit)
39
+ q += ` LIMIT ${p.limit}`;
40
+ return q;
41
+ }
42
+ function registerSObject(rl, sObject) {
43
+ const lower = sObject.toLowerCase();
44
+ rl.registerAction(`${lower}.create`, {
45
+ description: `Create a ${sObject}`,
46
+ inputSchema: t.Object({ data: Data }),
47
+ async execute(input, ctx) {
48
+ return api(ctx, "POST", `/sobjects/${sObject}`, input.data);
49
+ },
50
+ });
51
+ rl.registerAction(`${lower}.get`, {
52
+ description: `Get a ${sObject} by ID`,
53
+ inputSchema: t.Object({ id: t.String() }),
54
+ async execute(input, ctx) {
55
+ return api(ctx, "GET", `/sobjects/${sObject}/${input.id}`);
56
+ },
57
+ });
58
+ rl.registerAction(`${lower}.update`, {
59
+ description: `Update a ${sObject}`,
60
+ inputSchema: t.Object({ id: t.String(), data: Data }),
61
+ async execute(input, ctx) {
62
+ const p = input;
63
+ await api(ctx, "PATCH", `/sobjects/${sObject}/${p.id}`, p.data);
64
+ return { success: true, id: p.id };
65
+ },
66
+ });
67
+ rl.registerAction(`${lower}.delete`, {
68
+ description: `Delete a ${sObject}`,
69
+ inputSchema: t.Object({ id: t.String() }),
70
+ async execute(input, ctx) {
71
+ await api(ctx, "DELETE", `/sobjects/${sObject}/${input.id}`);
72
+ return { success: true };
73
+ },
74
+ });
75
+ rl.registerAction(`${lower}.query`, {
76
+ description: `Query ${sObject}s with SOQL`,
77
+ inputSchema: QueryInput(sObject),
78
+ async execute(input, ctx) {
79
+ return records(await api(ctx, "GET", "/query", undefined, {
80
+ q: buildQuery(sObject, input),
81
+ }));
82
+ },
83
+ });
84
+ rl.registerAction(`${lower}.queryPage`, {
85
+ description: `Query ${sObject}s with SOQL and return Salesforce pagination metadata`,
86
+ inputSchema: QueryInput(sObject),
87
+ async execute(input, ctx) {
88
+ return api(ctx, "GET", "/query", undefined, {
89
+ q: buildQuery(sObject, input),
90
+ });
91
+ },
92
+ });
93
+ rl.registerAction(`${lower}.upsert`, {
94
+ description: `Upsert a ${sObject} by external ID`,
95
+ inputSchema: t.Object({
96
+ externalIdField: t.String(),
97
+ externalIdValue: t.String(),
98
+ data: Data,
99
+ }),
100
+ async execute(input, ctx) {
101
+ const p = input;
102
+ return api(ctx, "PATCH", `/sobjects/${sObject}/${p.externalIdField}/${p.externalIdValue}`, p.data);
103
+ },
104
+ });
105
+ }
106
+ export function registerStandardSObjectActions(rl) {
107
+ for (const sObject of SOBJECTS)
108
+ registerSObject(rl, sObject);
109
+ }
110
+ export function registerGenericSObjectActions(rl) {
111
+ rl.registerAction("sobject.create", {
112
+ description: "Create any sObject record",
113
+ inputSchema: t.Object({ sObject: t.String(), data: Data }),
114
+ async execute(input, ctx) {
115
+ const p = input;
116
+ return api(ctx, "POST", `/sobjects/${p.sObject}`, p.data);
117
+ },
118
+ });
119
+ rl.registerAction("sobject.get", {
120
+ description: "Get any sObject record",
121
+ inputSchema: t.Object({ sObject: t.String(), id: t.String() }),
122
+ async execute(input, ctx) {
123
+ const p = input;
124
+ return api(ctx, "GET", `/sobjects/${p.sObject}/${p.id}`);
125
+ },
126
+ });
127
+ rl.registerAction("sobject.update", {
128
+ description: "Update any sObject record",
129
+ inputSchema: t.Object({ sObject: t.String(), id: t.String(), data: Data }),
130
+ async execute(input, ctx) {
131
+ const p = input;
132
+ await api(ctx, "PATCH", `/sobjects/${p.sObject}/${p.id}`, p.data);
133
+ return { success: true };
134
+ },
135
+ });
136
+ rl.registerAction("sobject.delete", {
137
+ description: "Delete any sObject record",
138
+ inputSchema: t.Object({ sObject: t.String(), id: t.String() }),
139
+ async execute(input, ctx) {
140
+ const p = input;
141
+ await api(ctx, "DELETE", `/sobjects/${p.sObject}/${p.id}`);
142
+ return { success: true };
143
+ },
144
+ });
145
+ rl.registerAction("sobject.describe", {
146
+ description: "Describe an sObject's metadata/fields",
147
+ inputSchema: t.Object({ sObject: t.String() }),
148
+ async execute(input, ctx) {
149
+ return api(ctx, "GET", `/sobjects/${input.sObject}/describe`);
150
+ },
151
+ });
152
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "runline",
3
- "version": "0.11.2",
3
+ "version": "0.11.4",
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",