runline 0.1.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/.pi/extensions/runline-context/index.ts +135 -0
- package/.pi/extensions/runline-context/package.json +17 -0
- package/README.md +273 -0
- package/dist/commands/actions.d.ts +3 -0
- package/dist/commands/actions.js +43 -0
- package/dist/commands/connection.d.ts +11 -0
- package/dist/commands/connection.js +56 -0
- package/dist/commands/exec.d.ts +5 -0
- package/dist/commands/exec.js +46 -0
- package/dist/commands/init.d.ts +4 -0
- package/dist/commands/init.js +26 -0
- package/dist/commands/plugin.d.ts +10 -0
- package/dist/commands/plugin.js +57 -0
- package/dist/config/index.d.ts +3 -0
- package/dist/config/index.js +2 -0
- package/dist/config/loader.d.ts +11 -0
- package/dist/config/loader.js +82 -0
- package/dist/config/types.d.ts +9 -0
- package/dist/config/types.js +5 -0
- package/dist/core/engine.d.ts +21 -0
- package/dist/core/engine.js +280 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.js +9 -0
- package/dist/main.d.ts +2 -0
- package/dist/main.js +127 -0
- package/dist/plugin/api.d.ts +32 -0
- package/dist/plugin/api.js +68 -0
- package/dist/plugin/installer.d.ts +27 -0
- package/dist/plugin/installer.js +181 -0
- package/dist/plugin/loader.d.ts +13 -0
- package/dist/plugin/loader.js +164 -0
- package/dist/plugin/registry.d.ts +18 -0
- package/dist/plugin/registry.js +43 -0
- package/dist/plugin/types.d.ts +40 -0
- package/dist/plugin/types.js +1 -0
- package/dist/plugins/actionNetwork/src/index.js +353 -0
- package/dist/plugins/activeCampaign/src/index.js +711 -0
- package/dist/plugins/adalo/src/index.js +131 -0
- package/dist/plugins/affinity/src/index.js +279 -0
- package/dist/plugins/agileCrm/src/index.js +415 -0
- package/dist/plugins/airtable/src/index.js +280 -0
- package/dist/plugins/airtop/src/index.js +527 -0
- package/dist/plugins/apiTemplateIo/src/index.js +86 -0
- package/dist/plugins/asana/src/index.js +413 -0
- package/dist/plugins/autopilot/src/index.js +203 -0
- package/dist/plugins/bambooHr/src/index.js +252 -0
- package/dist/plugins/bannerbear/src/index.js +100 -0
- package/dist/plugins/baserow/src/index.js +180 -0
- package/dist/plugins/beeminder/src/index.js +298 -0
- package/dist/plugins/bitly/src/index.js +107 -0
- package/dist/plugins/bitwarden/src/index.js +383 -0
- package/dist/plugins/box/src/index.js +300 -0
- package/dist/plugins/brandfetch/src/index.js +80 -0
- package/dist/plugins/brevo/src/index.js +305 -0
- package/dist/plugins/bubble/src/index.js +181 -0
- package/dist/plugins/chargebee/src/index.js +126 -0
- package/dist/plugins/circleci/src/index.js +111 -0
- package/dist/plugins/ciscoWebex/src/index.js +245 -0
- package/dist/plugins/clearbit/src/index.js +103 -0
- package/dist/plugins/clickup/src/index.js +1043 -0
- package/dist/plugins/clockify/src/index.js +443 -0
- package/dist/plugins/cloudflare/src/index.js +93 -0
- package/dist/plugins/cockpit/src/index.js +131 -0
- package/dist/plugins/coda/src/index.js +327 -0
- package/dist/plugins/coingecko/src/index.js +244 -0
- package/dist/plugins/contentful/src/index.js +146 -0
- package/dist/plugins/convertkit/src/index.js +270 -0
- package/dist/plugins/copper/src/index.js +140 -0
- package/dist/plugins/cortex/src/index.js +147 -0
- package/dist/plugins/currents/src/index.js +405 -0
- package/dist/plugins/customerIo/src/index.js +184 -0
- package/dist/plugins/databricks/src/index.js +342 -0
- package/dist/plugins/deepl/src/index.js +87 -0
- package/dist/plugins/demio/src/index.js +111 -0
- package/dist/plugins/dhl/src/index.js +40 -0
- package/dist/plugins/discord/src/index.js +275 -0
- package/dist/plugins/discourse/src/index.js +273 -0
- package/dist/plugins/disqus/src/index.js +145 -0
- package/dist/plugins/docker/src/index.js +76 -0
- package/dist/plugins/drift/src/index.js +89 -0
- package/dist/plugins/dropbox/src/index.js +159 -0
- package/dist/plugins/dropcontact/src/index.js +59 -0
- package/dist/plugins/egoi/src/index.js +151 -0
- package/dist/plugins/elasticsearch/src/index.js +157 -0
- package/dist/plugins/emelia/src/index.js +174 -0
- package/dist/plugins/erpnext/src/index.js +121 -0
- package/dist/plugins/facebookGraph/src/index.js +57 -0
- package/dist/plugins/freshdesk/src/index.js +320 -0
- package/dist/plugins/freshservice/src/index.js +146 -0
- package/dist/plugins/freshworksCrm/src/index.js +149 -0
- package/dist/plugins/getresponse/src/index.js +140 -0
- package/dist/plugins/ghost/src/index.js +192 -0
- package/dist/plugins/github/src/index.js +630 -0
- package/dist/plugins/gitlab/src/index.js +358 -0
- package/dist/plugins/gong/src/index.js +126 -0
- package/dist/plugins/gotify/src/index.js +77 -0
- package/dist/plugins/gotowebinar/src/index.js +316 -0
- package/dist/plugins/grafana/src/index.js +250 -0
- package/dist/plugins/graphql/src/index.js +78 -0
- package/dist/plugins/grist/src/index.js +106 -0
- package/dist/plugins/hackernews/src/index.js +89 -0
- package/dist/plugins/halopsa/src/index.js +79 -0
- package/dist/plugins/harvest/src/index.js +163 -0
- package/dist/plugins/helpscout/src/index.js +176 -0
- package/dist/plugins/highlevel/src/index.js +172 -0
- package/dist/plugins/homeAssistant/src/index.js +148 -0
- package/dist/plugins/hubspot/src/index.js +176 -0
- package/dist/plugins/humanticAi/src/index.js +60 -0
- package/dist/plugins/hunter/src/index.js +59 -0
- package/dist/plugins/intercom/src/index.js +156 -0
- package/dist/plugins/iterable/src/index.js +139 -0
- package/dist/plugins/jenkins/src/index.js +132 -0
- package/dist/plugins/jira/src/index.js +229 -0
- package/dist/plugins/keap/src/index.js +502 -0
- package/dist/plugins/kobotoolbox/src/index.js +281 -0
- package/dist/plugins/lemlist/src/index.js +231 -0
- package/dist/plugins/linear/src/index.js +133 -0
- package/dist/plugins/lingvanex/src/index.js +31 -0
- package/dist/plugins/linkedin/src/index.js +80 -0
- package/dist/plugins/lonescale/src/index.js +119 -0
- package/dist/plugins/magento/src/index.js +300 -0
- package/dist/plugins/mailcheck/src/index.js +27 -0
- package/dist/plugins/mailchimp/src/index.js +321 -0
- package/dist/plugins/mailerlite/src/index.js +123 -0
- package/dist/plugins/mailgun/src/index.js +48 -0
- package/dist/plugins/mailjet/src/index.js +155 -0
- package/dist/plugins/mandrill/src/index.js +145 -0
- package/dist/plugins/marketstack/src/index.js +97 -0
- package/dist/plugins/matrix/src/index.js +194 -0
- package/dist/plugins/mattermost/src/index.js +331 -0
- package/dist/plugins/mautic/src/index.js +311 -0
- package/dist/plugins/medium/src/index.js +77 -0
- package/dist/plugins/messagebird/src/index.js +57 -0
- package/dist/plugins/metabase/src/index.js +130 -0
- package/dist/plugins/misp/src/index.js +476 -0
- package/dist/plugins/mocean/src/index.js +67 -0
- package/dist/plugins/monday/src/index.js +231 -0
- package/dist/plugins/monicaCrm/src/index.js +52 -0
- package/dist/plugins/msg91/src/index.js +31 -0
- package/dist/plugins/nasa/src/index.js +146 -0
- package/dist/plugins/netlify/src/index.js +151 -0
- package/dist/plugins/netscalerAdc/src/index.js +131 -0
- package/dist/plugins/nextcloud/src/index.js +263 -0
- package/dist/plugins/nocodb/src/index.js +130 -0
- package/dist/plugins/notion/src/index.js +112 -0
- package/dist/plugins/npm/src/index.js +104 -0
- package/dist/plugins/odoo/src/index.js +157 -0
- package/dist/plugins/okta/src/index.js +141 -0
- package/dist/plugins/oneSimpleApi/src/index.js +155 -0
- package/dist/plugins/onfleet/src/index.js +254 -0
- package/dist/plugins/openThesaurus/src/index.js +32 -0
- package/dist/plugins/openweathermap/src/index.js +60 -0
- package/dist/plugins/oura/src/index.js +62 -0
- package/dist/plugins/paddle/src/index.js +247 -0
- package/dist/plugins/pagerduty/src/index.js +201 -0
- package/dist/plugins/paypal/src/index.js +106 -0
- package/dist/plugins/peekalink/src/index.js +35 -0
- package/dist/plugins/phantombuster/src/index.js +94 -0
- package/dist/plugins/philipsHue/src/index.js +98 -0
- package/dist/plugins/pipedrive/src/index.js +169 -0
- package/dist/plugins/plivo/src/index.js +66 -0
- package/dist/plugins/postbin/src/index.js +93 -0
- package/dist/plugins/posthog/src/index.js +113 -0
- package/dist/plugins/profitwell/src/index.js +50 -0
- package/dist/plugins/pushbullet/src/index.js +102 -0
- package/dist/plugins/pushcut/src/index.js +39 -0
- package/dist/plugins/pushover/src/index.js +65 -0
- package/dist/plugins/quickbase/src/index.js +153 -0
- package/dist/plugins/quickbooks/src/index.js +73 -0
- package/dist/plugins/quickchart/src/index.js +36 -0
- package/dist/plugins/raindrop/src/index.js +209 -0
- package/dist/plugins/reddit/src/index.js +185 -0
- package/dist/plugins/rocketchat/src/index.js +53 -0
- package/dist/plugins/rundeck/src/index.js +62 -0
- package/dist/plugins/salesforce/src/index.js +94 -0
- package/dist/plugins/salesmate/src/index.js +83 -0
- package/dist/plugins/securityScorecard/src/index.js +200 -0
- package/dist/plugins/segment/src/index.js +125 -0
- package/dist/plugins/sendgrid/src/index.js +187 -0
- package/dist/plugins/sendy/src/index.js +138 -0
- package/dist/plugins/sentry/src/index.js +233 -0
- package/dist/plugins/servicenow/src/index.js +108 -0
- package/dist/plugins/shopify/src/index.js +222 -0
- package/dist/plugins/signl4/src/index.js +61 -0
- package/dist/plugins/slack/src/index.js +236 -0
- package/dist/plugins/sms77/src/index.js +63 -0
- package/dist/plugins/splunk/src/index.js +207 -0
- package/dist/plugins/spotify/src/index.js +188 -0
- package/dist/plugins/stackby/src/index.js +82 -0
- package/dist/plugins/storyblok/src/index.js +141 -0
- package/dist/plugins/strapi/src/index.js +152 -0
- package/dist/plugins/strava/src/index.js +137 -0
- package/dist/plugins/stripe/src/index.js +222 -0
- package/dist/plugins/supabase/src/index.js +121 -0
- package/dist/plugins/syncromsp/src/index.js +255 -0
- package/dist/plugins/tapfiliate/src/index.js +125 -0
- package/dist/plugins/telegram/src/index.js +233 -0
- package/dist/plugins/thehive/src/index.js +142 -0
- package/dist/plugins/thehiveProject/src/index.js +194 -0
- package/dist/plugins/todoist/src/index.js +244 -0
- package/dist/plugins/travisci/src/index.js +71 -0
- package/dist/plugins/trello/src/index.js +341 -0
- package/dist/plugins/twake/src/index.js +40 -0
- package/dist/plugins/twilio/src/index.js +75 -0
- package/dist/plugins/twist/src/index.js +90 -0
- package/dist/plugins/twitter/src/index.js +123 -0
- package/dist/plugins/unleashedSoftware/src/index.js +84 -0
- package/dist/plugins/uplead/src/index.js +59 -0
- package/dist/plugins/uproc/src/index.js +34 -0
- package/dist/plugins/uptimerobot/src/index.js +264 -0
- package/dist/plugins/urlscanio/src/index.js +64 -0
- package/dist/plugins/vero/src/index.js +80 -0
- package/dist/plugins/vonage/src/index.js +42 -0
- package/dist/plugins/wekan/src/index.js +91 -0
- package/dist/plugins/woocommerce/src/index.js +92 -0
- package/dist/plugins/wordpress/src/index.js +121 -0
- package/dist/plugins/xero/src/index.js +136 -0
- package/dist/plugins/yourls/src/index.js +56 -0
- package/dist/plugins/zammad/src/index.js +91 -0
- package/dist/plugins/zendesk/src/index.js +137 -0
- package/dist/plugins/zoho/src/index.js +85 -0
- package/dist/plugins/zoom/src/index.js +122 -0
- package/dist/plugins/zulip/src/index.js +170 -0
- package/dist/sdk.d.ts +38 -0
- package/dist/sdk.js +105 -0
- package/dist/utils/cli.d.ts +13 -0
- package/dist/utils/cli.js +32 -0
- package/dist/utils/output.d.ts +4 -0
- package/dist/utils/output.js +13 -0
- package/package.json +57 -0
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import { installPlugin, listInstalled, removePlugin, } from "../plugin/installer.js";
|
|
3
|
+
import { loadAllPlugins } from "../plugin/loader.js";
|
|
4
|
+
import { registry } from "../plugin/registry.js";
|
|
5
|
+
import { printError, printJson, printSuccess } from "../utils/output.js";
|
|
6
|
+
export async function pluginInstall(source, options) {
|
|
7
|
+
try {
|
|
8
|
+
const result = await installPlugin(source, { global: options.global });
|
|
9
|
+
if (options.json) {
|
|
10
|
+
printJson({ ok: true, ...result });
|
|
11
|
+
}
|
|
12
|
+
else {
|
|
13
|
+
printSuccess(`Installed ${chalk.bold(result.name)} from ${source}`);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
catch (err) {
|
|
17
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
18
|
+
printError(msg);
|
|
19
|
+
process.exit(1);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
export async function pluginRemove(name, options) {
|
|
23
|
+
const removed = removePlugin(name);
|
|
24
|
+
if (!removed) {
|
|
25
|
+
printError(`Plugin "${name}" not found`);
|
|
26
|
+
process.exit(1);
|
|
27
|
+
}
|
|
28
|
+
if (options.json) {
|
|
29
|
+
printJson({ ok: true, removed: name });
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
printSuccess(`Removed ${chalk.bold(name)}`);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
export async function pluginList(options) {
|
|
36
|
+
await loadAllPlugins();
|
|
37
|
+
const installed = listInstalled();
|
|
38
|
+
const loaded = registry.listPlugins();
|
|
39
|
+
if (options.json) {
|
|
40
|
+
printJson(loaded.map((p) => ({
|
|
41
|
+
name: p.name,
|
|
42
|
+
version: p.version,
|
|
43
|
+
actions: p.actions.map((a) => a.name),
|
|
44
|
+
source: installed.find((i) => i.name === p.name)?.source,
|
|
45
|
+
})));
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
if (loaded.length === 0) {
|
|
49
|
+
console.log("No plugins loaded.");
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
for (const p of loaded) {
|
|
53
|
+
const src = installed.find((i) => i.name === p.name);
|
|
54
|
+
const srcLabel = src ? chalk.dim(` (${src.source})`) : "";
|
|
55
|
+
console.log(` ${chalk.bold(p.name)} v${p.version}${srcLabel} — ${p.actions.length} action(s)`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ConnectionConfig } from "../plugin/types.js";
|
|
2
|
+
import { type RunlineConfig } from "./types.js";
|
|
3
|
+
export declare function findConfigDir(): string | null;
|
|
4
|
+
export declare function loadConfig(): RunlineConfig;
|
|
5
|
+
export declare function saveConfig(config: RunlineConfig): void;
|
|
6
|
+
export declare function addConnection(name: string, plugin: string, configValues: Record<string, unknown>): void;
|
|
7
|
+
export declare function removeConnection(name: string): boolean;
|
|
8
|
+
export declare function getConnection(plugin: string, name?: string): ConnectionConfig | undefined;
|
|
9
|
+
export declare function applyEnvOverrides(conn: ConnectionConfig, schema?: Record<string, {
|
|
10
|
+
env?: string;
|
|
11
|
+
}>): ConnectionConfig;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { DEFAULT_CONFIG } from "./types.js";
|
|
4
|
+
const CONFIG_DIR_NAME = ".runline";
|
|
5
|
+
const CONFIG_FILE = "config.json";
|
|
6
|
+
export function findConfigDir() {
|
|
7
|
+
let dir = process.cwd();
|
|
8
|
+
while (true) {
|
|
9
|
+
const candidate = join(dir, CONFIG_DIR_NAME);
|
|
10
|
+
if (existsSync(candidate))
|
|
11
|
+
return candidate;
|
|
12
|
+
const parent = join(dir, "..");
|
|
13
|
+
if (parent === dir)
|
|
14
|
+
break;
|
|
15
|
+
dir = parent;
|
|
16
|
+
}
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
export function loadConfig() {
|
|
20
|
+
const configDir = findConfigDir();
|
|
21
|
+
if (!configDir)
|
|
22
|
+
return { ...DEFAULT_CONFIG };
|
|
23
|
+
const configPath = join(configDir, CONFIG_FILE);
|
|
24
|
+
if (!existsSync(configPath))
|
|
25
|
+
return { ...DEFAULT_CONFIG };
|
|
26
|
+
try {
|
|
27
|
+
const raw = JSON.parse(readFileSync(configPath, "utf-8"));
|
|
28
|
+
return {
|
|
29
|
+
...DEFAULT_CONFIG,
|
|
30
|
+
...raw,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
return { ...DEFAULT_CONFIG };
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
export function saveConfig(config) {
|
|
38
|
+
const configDir = findConfigDir() ?? join(process.cwd(), CONFIG_DIR_NAME);
|
|
39
|
+
mkdirSync(configDir, { recursive: true });
|
|
40
|
+
const configPath = join(configDir, CONFIG_FILE);
|
|
41
|
+
writeFileSync(configPath, `${JSON.stringify(config, null, 2)}\n`);
|
|
42
|
+
}
|
|
43
|
+
export function addConnection(name, plugin, configValues) {
|
|
44
|
+
const config = loadConfig();
|
|
45
|
+
const existing = config.connections.findIndex((c) => c.name === name);
|
|
46
|
+
const conn = { name, plugin, config: configValues };
|
|
47
|
+
if (existing >= 0) {
|
|
48
|
+
config.connections[existing] = conn;
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
config.connections.push(conn);
|
|
52
|
+
}
|
|
53
|
+
saveConfig(config);
|
|
54
|
+
}
|
|
55
|
+
export function removeConnection(name) {
|
|
56
|
+
const config = loadConfig();
|
|
57
|
+
const idx = config.connections.findIndex((c) => c.name === name);
|
|
58
|
+
if (idx < 0)
|
|
59
|
+
return false;
|
|
60
|
+
config.connections.splice(idx, 1);
|
|
61
|
+
saveConfig(config);
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
64
|
+
export function getConnection(plugin, name) {
|
|
65
|
+
const config = loadConfig();
|
|
66
|
+
if (name)
|
|
67
|
+
return config.connections.find((c) => c.name === name);
|
|
68
|
+
return config.connections.find((c) => c.plugin === plugin);
|
|
69
|
+
}
|
|
70
|
+
export function applyEnvOverrides(conn, schema) {
|
|
71
|
+
if (!schema)
|
|
72
|
+
return conn;
|
|
73
|
+
const config = { ...conn.config };
|
|
74
|
+
for (const [key, field] of Object.entries(schema)) {
|
|
75
|
+
if (field.env && !config[key]) {
|
|
76
|
+
const envVal = process.env[field.env];
|
|
77
|
+
if (envVal)
|
|
78
|
+
config[key] = envVal;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return { ...conn, config };
|
|
82
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ConnectionConfig } from "../plugin/types.js";
|
|
2
|
+
export interface RunlineConfig {
|
|
3
|
+
connections: ConnectionConfig[];
|
|
4
|
+
/** Execution timeout in ms. Default 30_000. */
|
|
5
|
+
timeoutMs: number;
|
|
6
|
+
/** Memory limit for QuickJS in bytes. Default 64MB. */
|
|
7
|
+
memoryLimitBytes: number;
|
|
8
|
+
}
|
|
9
|
+
export declare const DEFAULT_CONFIG: RunlineConfig;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { RunlineConfig } from "../config/types.js";
|
|
2
|
+
import type { PluginRegistry } from "../plugin/registry.js";
|
|
3
|
+
export interface ExecuteResult {
|
|
4
|
+
result: unknown;
|
|
5
|
+
error?: string;
|
|
6
|
+
logs: string[];
|
|
7
|
+
}
|
|
8
|
+
export interface EngineOptions {
|
|
9
|
+
timeoutMs?: number;
|
|
10
|
+
memoryLimitBytes?: number;
|
|
11
|
+
}
|
|
12
|
+
export declare class ExecutionEngine {
|
|
13
|
+
private registry;
|
|
14
|
+
private config;
|
|
15
|
+
constructor(registry: PluginRegistry, config: RunlineConfig);
|
|
16
|
+
execute(code: string, options?: EngineOptions): Promise<ExecuteResult>;
|
|
17
|
+
private invokeAction;
|
|
18
|
+
private resolveConnection;
|
|
19
|
+
private drainAsync;
|
|
20
|
+
private drainJobs;
|
|
21
|
+
}
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
import { getQuickJS, shouldInterruptAfterDeadline, } from "quickjs-emscripten";
|
|
2
|
+
import { applyEnvOverrides } from "../config/loader.js";
|
|
3
|
+
export class ExecutionEngine {
|
|
4
|
+
registry;
|
|
5
|
+
config;
|
|
6
|
+
constructor(registry, config) {
|
|
7
|
+
this.registry = registry;
|
|
8
|
+
this.config = config;
|
|
9
|
+
}
|
|
10
|
+
async execute(code, options) {
|
|
11
|
+
const timeoutMs = options?.timeoutMs ?? this.config.timeoutMs;
|
|
12
|
+
const memoryLimitBytes = options?.memoryLimitBytes ?? this.config.memoryLimitBytes;
|
|
13
|
+
const deadlineMs = Date.now() + timeoutMs;
|
|
14
|
+
const logs = [];
|
|
15
|
+
const pendingDeferreds = new Set();
|
|
16
|
+
const QuickJS = await getQuickJS();
|
|
17
|
+
const runtime = QuickJS.newRuntime();
|
|
18
|
+
try {
|
|
19
|
+
runtime.setMemoryLimit(memoryLimitBytes);
|
|
20
|
+
runtime.setInterruptHandler(shouldInterruptAfterDeadline(deadlineMs));
|
|
21
|
+
const context = runtime.newContext();
|
|
22
|
+
try {
|
|
23
|
+
// Inject log bridge
|
|
24
|
+
const logBridge = context.newFunction("__runline_log", (levelHandle, lineHandle) => {
|
|
25
|
+
const level = context.getString(levelHandle);
|
|
26
|
+
const line = context.getString(lineHandle);
|
|
27
|
+
logs.push(`[${level}] ${line}`);
|
|
28
|
+
return context.undefined;
|
|
29
|
+
});
|
|
30
|
+
context.setProp(context.global, "__runline_log", logBridge);
|
|
31
|
+
logBridge.dispose();
|
|
32
|
+
// Inject action bridge
|
|
33
|
+
const actionBridge = context.newFunction("__runline_invoke", (pathHandle, argsHandle) => {
|
|
34
|
+
const path = context.getString(pathHandle);
|
|
35
|
+
const args = argsHandle === undefined ||
|
|
36
|
+
context.typeof(argsHandle) === "undefined"
|
|
37
|
+
? undefined
|
|
38
|
+
: context.dump(argsHandle);
|
|
39
|
+
const deferred = context.newPromise();
|
|
40
|
+
pendingDeferreds.add(deferred);
|
|
41
|
+
deferred.settled.finally(() => pendingDeferreds.delete(deferred));
|
|
42
|
+
this.invokeAction(path, args).then((value) => {
|
|
43
|
+
if (!deferred.alive)
|
|
44
|
+
return;
|
|
45
|
+
if (value === undefined) {
|
|
46
|
+
deferred.resolve();
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
const serialized = JSON.stringify(value);
|
|
50
|
+
const handle = context.newString(serialized);
|
|
51
|
+
deferred.resolve(handle);
|
|
52
|
+
handle.dispose();
|
|
53
|
+
}, (err) => {
|
|
54
|
+
if (!deferred.alive)
|
|
55
|
+
return;
|
|
56
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
57
|
+
const handle = context.newError(msg);
|
|
58
|
+
deferred.reject(handle);
|
|
59
|
+
handle.dispose();
|
|
60
|
+
});
|
|
61
|
+
return deferred.handle;
|
|
62
|
+
});
|
|
63
|
+
context.setProp(context.global, "__runline_invoke", actionBridge);
|
|
64
|
+
actionBridge.dispose();
|
|
65
|
+
const plugins = this.registry.listPlugins();
|
|
66
|
+
const pluginNames = plugins.map((p) => p.name);
|
|
67
|
+
const helpData = buildHelpData(plugins);
|
|
68
|
+
const source = buildExecutionSource(code, pluginNames, helpData);
|
|
69
|
+
const evaluated = context.evalCode(source, "runline-sandbox.js");
|
|
70
|
+
if (evaluated.error) {
|
|
71
|
+
const error = context.dump(evaluated.error);
|
|
72
|
+
evaluated.error.dispose();
|
|
73
|
+
return { result: null, error: formatError(error), logs };
|
|
74
|
+
}
|
|
75
|
+
// Set up promise tracking
|
|
76
|
+
context.setProp(context.global, "__runline_result", evaluated.value);
|
|
77
|
+
evaluated.value.dispose();
|
|
78
|
+
const stateResult = context.evalCode(`(function(p){ var s = { v: void 0, e: void 0, settled: false };
|
|
79
|
+
var fmtErr = function(e){ if (e && typeof e === 'object') { var m = typeof e.message === 'string' ? e.message : ''; var st = typeof e.stack === 'string' ? e.stack : ''; if (m && st) return st.indexOf(m) === -1 ? m + '\\n' + st : st; if (m) return m; if (st) return st; } return String(e); };
|
|
80
|
+
p.then(function(v){ s.v = v; s.settled = true; }, function(e){ s.e = fmtErr(e); s.settled = true; }); return s; })(__runline_result)`);
|
|
81
|
+
if (stateResult.error) {
|
|
82
|
+
const error = context.dump(stateResult.error);
|
|
83
|
+
stateResult.error.dispose();
|
|
84
|
+
return { result: null, error: formatError(error), logs };
|
|
85
|
+
}
|
|
86
|
+
const stateHandle = stateResult.value;
|
|
87
|
+
try {
|
|
88
|
+
await this.drainAsync(context, runtime, pendingDeferreds, deadlineMs, timeoutMs);
|
|
89
|
+
const settled = readProp(context, stateHandle, "settled") === true;
|
|
90
|
+
if (!settled) {
|
|
91
|
+
return {
|
|
92
|
+
result: null,
|
|
93
|
+
error: `Execution timed out after ${timeoutMs}ms`,
|
|
94
|
+
logs,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
const error = readProp(context, stateHandle, "e");
|
|
98
|
+
if (error !== undefined) {
|
|
99
|
+
return { result: null, error: formatError(error), logs };
|
|
100
|
+
}
|
|
101
|
+
return { result: readProp(context, stateHandle, "v"), logs };
|
|
102
|
+
}
|
|
103
|
+
finally {
|
|
104
|
+
stateHandle.dispose();
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
finally {
|
|
108
|
+
for (const d of pendingDeferreds) {
|
|
109
|
+
if (d.alive)
|
|
110
|
+
d.dispose();
|
|
111
|
+
}
|
|
112
|
+
pendingDeferreds.clear();
|
|
113
|
+
context.dispose();
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
catch (err) {
|
|
117
|
+
return {
|
|
118
|
+
result: null,
|
|
119
|
+
error: formatError(err),
|
|
120
|
+
logs,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
finally {
|
|
124
|
+
runtime.dispose();
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
async invokeAction(path, args) {
|
|
128
|
+
const resolved = this.registry.resolveAction(path);
|
|
129
|
+
if (!resolved) {
|
|
130
|
+
throw new Error(`Unknown action: ${path}`);
|
|
131
|
+
}
|
|
132
|
+
const { plugin, action } = resolved;
|
|
133
|
+
const connection = this.resolveConnection(plugin);
|
|
134
|
+
const ctx = {
|
|
135
|
+
connection,
|
|
136
|
+
log: {
|
|
137
|
+
info: (msg) => console.log(`[${plugin.name}] ${msg}`),
|
|
138
|
+
warn: (msg) => console.warn(`[${plugin.name}] ${msg}`),
|
|
139
|
+
error: (msg) => console.error(`[${plugin.name}] ${msg}`),
|
|
140
|
+
},
|
|
141
|
+
};
|
|
142
|
+
return action.execute(args, ctx);
|
|
143
|
+
}
|
|
144
|
+
resolveConnection(plugin) {
|
|
145
|
+
const conn = this.config.connections.find((c) => c.plugin === plugin.name);
|
|
146
|
+
const base = conn ?? {
|
|
147
|
+
name: "default",
|
|
148
|
+
plugin: plugin.name,
|
|
149
|
+
config: {},
|
|
150
|
+
};
|
|
151
|
+
return applyEnvOverrides(base, plugin.connectionConfigSchema);
|
|
152
|
+
}
|
|
153
|
+
async drainAsync(context, runtime, pendingDeferreds, deadlineMs, timeoutMs) {
|
|
154
|
+
this.drainJobs(context, runtime, deadlineMs, timeoutMs);
|
|
155
|
+
while (pendingDeferreds.size > 0) {
|
|
156
|
+
const remainingMs = deadlineMs - Date.now();
|
|
157
|
+
if (remainingMs <= 0) {
|
|
158
|
+
throw new Error(`Execution timed out after ${timeoutMs}ms`);
|
|
159
|
+
}
|
|
160
|
+
let timer;
|
|
161
|
+
try {
|
|
162
|
+
await Promise.race([
|
|
163
|
+
Promise.race([...pendingDeferreds].map((d) => d.settled)),
|
|
164
|
+
new Promise((_, reject) => {
|
|
165
|
+
timer = setTimeout(() => reject(new Error(`Execution timed out after ${timeoutMs}ms`)), remainingMs);
|
|
166
|
+
}),
|
|
167
|
+
]);
|
|
168
|
+
}
|
|
169
|
+
finally {
|
|
170
|
+
if (timer)
|
|
171
|
+
clearTimeout(timer);
|
|
172
|
+
}
|
|
173
|
+
this.drainJobs(context, runtime, deadlineMs, timeoutMs);
|
|
174
|
+
}
|
|
175
|
+
this.drainJobs(context, runtime, deadlineMs, timeoutMs);
|
|
176
|
+
}
|
|
177
|
+
drainJobs(context, runtime, deadlineMs, timeoutMs) {
|
|
178
|
+
while (runtime.hasPendingJob()) {
|
|
179
|
+
if (Date.now() >= deadlineMs) {
|
|
180
|
+
throw new Error(`Execution timed out after ${timeoutMs}ms`);
|
|
181
|
+
}
|
|
182
|
+
const pending = runtime.executePendingJobs();
|
|
183
|
+
if (pending.error) {
|
|
184
|
+
const error = context.dump(pending.error);
|
|
185
|
+
pending.error.dispose();
|
|
186
|
+
throw error instanceof Error ? error : new Error(String(error));
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
// ── Helpers ──────────────────────────────────────────────
|
|
192
|
+
function readProp(context, handle, key) {
|
|
193
|
+
const prop = context.getProp(handle, key);
|
|
194
|
+
try {
|
|
195
|
+
return context.dump(prop);
|
|
196
|
+
}
|
|
197
|
+
finally {
|
|
198
|
+
prop.dispose();
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
function formatError(cause) {
|
|
202
|
+
if (cause instanceof Error)
|
|
203
|
+
return cause.stack ?? cause.message;
|
|
204
|
+
if (typeof cause === "object" &&
|
|
205
|
+
cause !== null &&
|
|
206
|
+
"message" in cause &&
|
|
207
|
+
typeof cause.message === "string") {
|
|
208
|
+
return cause.message;
|
|
209
|
+
}
|
|
210
|
+
return String(cause);
|
|
211
|
+
}
|
|
212
|
+
function buildHelpData(plugins) {
|
|
213
|
+
const data = {};
|
|
214
|
+
for (const p of plugins) {
|
|
215
|
+
data[p.name] = p.actions.map((a) => ({
|
|
216
|
+
action: a.name,
|
|
217
|
+
description: a.description,
|
|
218
|
+
inputs: Object.fromEntries(Object.entries(a.inputSchema ?? {}).map(([k, v]) => [
|
|
219
|
+
k,
|
|
220
|
+
`${v.type}${v.required ? " (required)" : ""}${v.description ? " — " + v.description : ""}`,
|
|
221
|
+
])),
|
|
222
|
+
}));
|
|
223
|
+
}
|
|
224
|
+
return data;
|
|
225
|
+
}
|
|
226
|
+
function buildExecutionSource(code, pluginNames = [], helpData = {}) {
|
|
227
|
+
const trimmed = code.trim();
|
|
228
|
+
const looksLikeArrow = (trimmed.startsWith("async") || trimmed.startsWith("(")) &&
|
|
229
|
+
trimmed.includes("=>");
|
|
230
|
+
const body = looksLikeArrow
|
|
231
|
+
? `const __fn = (${trimmed});\nif (typeof __fn !== 'function') throw new Error('Code must evaluate to a function');\nreturn await __fn();`
|
|
232
|
+
: code;
|
|
233
|
+
const wrapped = `"use strict";
|
|
234
|
+
const __invoke = __runline_invoke;
|
|
235
|
+
const __log = __runline_log;
|
|
236
|
+
try { delete globalThis.__runline_invoke; } catch {}
|
|
237
|
+
try { delete globalThis.__runline_log; } catch {}
|
|
238
|
+
|
|
239
|
+
const __fmt = (v) => {
|
|
240
|
+
if (typeof v === 'string') return v;
|
|
241
|
+
try { return JSON.stringify(v); } catch { return String(v); }
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
const __help = ${JSON.stringify(helpData)};
|
|
245
|
+
|
|
246
|
+
const __makeProxy = (path = []) => new Proxy(() => undefined, {
|
|
247
|
+
get(_t, prop) {
|
|
248
|
+
if (prop === 'then' || typeof prop === 'symbol') return undefined;
|
|
249
|
+
if (prop === 'help') {
|
|
250
|
+
const pluginName = path[0];
|
|
251
|
+
return () => pluginName && __help[pluginName] ? __help[pluginName] : __help;
|
|
252
|
+
}
|
|
253
|
+
return __makeProxy([...path, String(prop)]);
|
|
254
|
+
},
|
|
255
|
+
apply(_t, _this, args) {
|
|
256
|
+
const p = path.join('.');
|
|
257
|
+
if (!p) throw new Error('Action path missing');
|
|
258
|
+
return Promise.resolve(__invoke(p, args[0]))
|
|
259
|
+
.then((raw) => raw === undefined ? undefined : JSON.parse(raw));
|
|
260
|
+
},
|
|
261
|
+
});
|
|
262
|
+
const actions = __makeProxy();
|
|
263
|
+
const help = () => __help;
|
|
264
|
+
${pluginNames.map((n) => `const ${n} = __makeProxy(['${n}']);`).join("\n")}
|
|
265
|
+
|
|
266
|
+
const console = {
|
|
267
|
+
log: (...a) => __log('log', a.map(__fmt).join(' ')),
|
|
268
|
+
warn: (...a) => __log('warn', a.map(__fmt).join(' ')),
|
|
269
|
+
error: (...a) => __log('error', a.map(__fmt).join(' ')),
|
|
270
|
+
info: (...a) => __log('info', a.map(__fmt).join(' ')),
|
|
271
|
+
debug: (...a) => __log('debug', a.map(__fmt).join(' ')),
|
|
272
|
+
};
|
|
273
|
+
|
|
274
|
+
const fetch = () => { throw new Error('fetch is disabled in runline sandbox'); };
|
|
275
|
+
|
|
276
|
+
(async () => {
|
|
277
|
+
${body}
|
|
278
|
+
})()`;
|
|
279
|
+
return wrapped;
|
|
280
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export { addConnection, findConfigDir, getConnection, loadConfig, removeConnection, saveConfig, } from "./config/loader.js";
|
|
2
|
+
export type { RunlineConfig } from "./config/types.js";
|
|
3
|
+
export { DEFAULT_CONFIG } from "./config/types.js";
|
|
4
|
+
export type { EngineOptions, ExecuteResult } from "./core/engine.js";
|
|
5
|
+
export { ExecutionEngine } from "./core/engine.js";
|
|
6
|
+
export type { ActionDefinition, PluginFunction, RunlinePluginAPI, SchemaField, } from "./plugin/api.js";
|
|
7
|
+
export { createPluginAPI, isPluginFunction, resolvePluginExport, } from "./plugin/api.js";
|
|
8
|
+
export type { InstalledPlugin, PluginSource } from "./plugin/installer.js";
|
|
9
|
+
export { installPlugin, listInstalled, parsePluginSource, removePlugin, } from "./plugin/installer.js";
|
|
10
|
+
export { discoverPlugins, loadAllPlugins, loadPluginFromPath, loadPluginsFromConfig, } from "./plugin/loader.js";
|
|
11
|
+
export { PluginRegistry, registry } from "./plugin/registry.js";
|
|
12
|
+
export type { ActionContext, ActionDef, ConnectionConfig, InputField, InputSchema, PluginDef, } from "./plugin/types.js";
|
|
13
|
+
export type { RunlineOptions } from "./sdk.js";
|
|
14
|
+
export { Runline } from "./sdk.js";
|
|
15
|
+
export type { ExecOptions, ExecResult, OutputParser } from "./utils/cli.js";
|
|
16
|
+
export { commandExists, syncExec } from "./utils/cli.js";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { addConnection, findConfigDir, getConnection, loadConfig, removeConnection, saveConfig, } from "./config/loader.js";
|
|
2
|
+
export { DEFAULT_CONFIG } from "./config/types.js";
|
|
3
|
+
export { ExecutionEngine } from "./core/engine.js";
|
|
4
|
+
export { createPluginAPI, isPluginFunction, resolvePluginExport, } from "./plugin/api.js";
|
|
5
|
+
export { installPlugin, listInstalled, parsePluginSource, removePlugin, } from "./plugin/installer.js";
|
|
6
|
+
export { discoverPlugins, loadAllPlugins, loadPluginFromPath, loadPluginsFromConfig, } from "./plugin/loader.js";
|
|
7
|
+
export { PluginRegistry, registry } from "./plugin/registry.js";
|
|
8
|
+
export { Runline } from "./sdk.js";
|
|
9
|
+
export { commandExists, syncExec } from "./utils/cli.js";
|
package/dist/main.d.ts
ADDED
package/dist/main.js
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { createRequire } from "node:module";
|
|
3
|
+
import { Command } from "commander";
|
|
4
|
+
import { actions } from "./commands/actions.js";
|
|
5
|
+
import { connectionAdd, connectionList, connectionRemove, } from "./commands/connection.js";
|
|
6
|
+
import { exec } from "./commands/exec.js";
|
|
7
|
+
import { init } from "./commands/init.js";
|
|
8
|
+
import { pluginInstall, pluginList, pluginRemove } from "./commands/plugin.js";
|
|
9
|
+
const require = createRequire(import.meta.url);
|
|
10
|
+
const { version } = require("../package.json");
|
|
11
|
+
const program = new Command();
|
|
12
|
+
program
|
|
13
|
+
.name("runline")
|
|
14
|
+
.description("Code mode for agents — turn any API or command into a callable action")
|
|
15
|
+
.version(`runline ${version}`, "-v, --version")
|
|
16
|
+
.option("--json", "Output as JSON")
|
|
17
|
+
.option("-q, --quiet", "Suppress output")
|
|
18
|
+
.option("--no-color", "Disable color output")
|
|
19
|
+
.hook("preAction", (thisCommand) => {
|
|
20
|
+
if (thisCommand.opts().color === false) {
|
|
21
|
+
process.env.NO_COLOR = "1";
|
|
22
|
+
}
|
|
23
|
+
})
|
|
24
|
+
.addHelpText("after", `
|
|
25
|
+
Examples:
|
|
26
|
+
$ runline exec 'return await docker.containers.list()'
|
|
27
|
+
$ runline exec -f ./scripts/deploy.js
|
|
28
|
+
$ runline actions
|
|
29
|
+
$ runline connection add gh --plugin github --set token=ghp_xxx
|
|
30
|
+
|
|
31
|
+
https://github.com/Michaelliv/runline`);
|
|
32
|
+
program
|
|
33
|
+
.command("exec <code>")
|
|
34
|
+
.alias("e")
|
|
35
|
+
.description("Execute JavaScript code in the sandbox")
|
|
36
|
+
.option("-f, --file", "Treat <code> as a file path")
|
|
37
|
+
.addHelpText("after", `
|
|
38
|
+
The code runs in a QuickJS sandbox with an \`actions\` proxy.
|
|
39
|
+
Each installed plugin is a top-level global. Dot-chain into resource and action.
|
|
40
|
+
|
|
41
|
+
Examples:
|
|
42
|
+
$ runline exec 'return await docker.containers.list()'
|
|
43
|
+
$ runline exec -f ./scripts/deploy.js
|
|
44
|
+
$ runline exec 'return await github.repo.list({ owner: "torvalds" })'`)
|
|
45
|
+
.action(async (code, opts, cmd) => {
|
|
46
|
+
const globals = cmd.optsWithGlobals();
|
|
47
|
+
await exec(code, {
|
|
48
|
+
file: opts.file,
|
|
49
|
+
json: globals.json,
|
|
50
|
+
quiet: globals.quiet,
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
program
|
|
54
|
+
.command("actions")
|
|
55
|
+
.description("List all available actions and their schemas")
|
|
56
|
+
.action(async (_opts, cmd) => {
|
|
57
|
+
const globals = cmd.optsWithGlobals();
|
|
58
|
+
await actions({ json: globals.json });
|
|
59
|
+
});
|
|
60
|
+
// ── connection ──────────────────────────────────────────
|
|
61
|
+
const connCmd = program
|
|
62
|
+
.command("connection")
|
|
63
|
+
.alias("conn")
|
|
64
|
+
.description("Manage connections");
|
|
65
|
+
connCmd
|
|
66
|
+
.command("add <name>")
|
|
67
|
+
.description("Add a connection")
|
|
68
|
+
.requiredOption("-p, --plugin <plugin>", "Plugin name")
|
|
69
|
+
.option("-s, --set <key=value...>", "Config values", (v, prev) => [...prev, v], [])
|
|
70
|
+
.action(async (name, opts, cmd) => {
|
|
71
|
+
const globals = cmd.optsWithGlobals();
|
|
72
|
+
await connectionAdd(name, {
|
|
73
|
+
plugin: opts.plugin,
|
|
74
|
+
set: opts.set,
|
|
75
|
+
json: globals.json,
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
connCmd
|
|
79
|
+
.command("remove <name>")
|
|
80
|
+
.description("Remove a connection")
|
|
81
|
+
.action(async (name, _opts, cmd) => {
|
|
82
|
+
const globals = cmd.optsWithGlobals();
|
|
83
|
+
await connectionRemove(name, { json: globals.json });
|
|
84
|
+
});
|
|
85
|
+
connCmd
|
|
86
|
+
.command("list")
|
|
87
|
+
.description("List connections")
|
|
88
|
+
.action(async (_opts, cmd) => {
|
|
89
|
+
const globals = cmd.optsWithGlobals();
|
|
90
|
+
await connectionList({ json: globals.json });
|
|
91
|
+
});
|
|
92
|
+
// ── plugin ──────────────────────────────────────────────
|
|
93
|
+
const pluginCmd = program.command("plugin").description("Manage plugins");
|
|
94
|
+
pluginCmd
|
|
95
|
+
.command("install <source>")
|
|
96
|
+
.description("Install a plugin (npm:pkg, git:repo, or local path)")
|
|
97
|
+
.option("-g, --global", "Install globally")
|
|
98
|
+
.action(async (source, opts, cmd) => {
|
|
99
|
+
const globals = cmd.optsWithGlobals();
|
|
100
|
+
await pluginInstall(source, { global: opts.global, json: globals.json });
|
|
101
|
+
});
|
|
102
|
+
pluginCmd
|
|
103
|
+
.command("remove <name>")
|
|
104
|
+
.description("Remove an installed plugin")
|
|
105
|
+
.action(async (name, _opts, cmd) => {
|
|
106
|
+
const globals = cmd.optsWithGlobals();
|
|
107
|
+
await pluginRemove(name, { json: globals.json });
|
|
108
|
+
});
|
|
109
|
+
pluginCmd
|
|
110
|
+
.command("list")
|
|
111
|
+
.description("List all plugins")
|
|
112
|
+
.action(async (_opts, cmd) => {
|
|
113
|
+
const globals = cmd.optsWithGlobals();
|
|
114
|
+
await pluginList({ json: globals.json });
|
|
115
|
+
});
|
|
116
|
+
// ── init ────────────────────────────────────────────────
|
|
117
|
+
program
|
|
118
|
+
.command("init")
|
|
119
|
+
.description("Create .runline/ in current directory")
|
|
120
|
+
.action(async (_opts, cmd) => {
|
|
121
|
+
const globals = cmd.optsWithGlobals();
|
|
122
|
+
await init({ json: globals.json, quiet: globals.quiet });
|
|
123
|
+
});
|
|
124
|
+
program.parseAsync(process.argv).catch((err) => {
|
|
125
|
+
console.error("Fatal error:", err.message);
|
|
126
|
+
process.exit(1);
|
|
127
|
+
});
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { ActionDef, InputSchema, PluginDef } from "./types.js";
|
|
2
|
+
export interface SchemaField {
|
|
3
|
+
type: "string" | "number" | "boolean";
|
|
4
|
+
required?: boolean;
|
|
5
|
+
description?: string;
|
|
6
|
+
default?: unknown;
|
|
7
|
+
env?: string;
|
|
8
|
+
}
|
|
9
|
+
export interface ActionDefinition {
|
|
10
|
+
description?: string;
|
|
11
|
+
inputSchema?: InputSchema;
|
|
12
|
+
execute: ActionDef["execute"];
|
|
13
|
+
}
|
|
14
|
+
export interface RunlinePluginAPI {
|
|
15
|
+
registerAction(name: string, def: ActionDefinition): void;
|
|
16
|
+
setConnectionSchema(schema: Record<string, SchemaField>): void;
|
|
17
|
+
setName(name: string): void;
|
|
18
|
+
setVersion(version: string): void;
|
|
19
|
+
onInit(fn: (config: Record<string, unknown>) => void): void;
|
|
20
|
+
log: {
|
|
21
|
+
info(msg: string): void;
|
|
22
|
+
warn(msg: string): void;
|
|
23
|
+
error(msg: string): void;
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
export type PluginFunction = (api: RunlinePluginAPI) => void;
|
|
27
|
+
export declare function createPluginAPI(pluginId: string): {
|
|
28
|
+
api: RunlinePluginAPI;
|
|
29
|
+
resolve: () => PluginDef;
|
|
30
|
+
};
|
|
31
|
+
export declare function isPluginFunction(val: unknown): val is PluginFunction;
|
|
32
|
+
export declare function resolvePluginExport(exported: PluginFunction | PluginDef, pluginId: string): PluginDef;
|