@withone/cli 1.14.1 → 1.15.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/index.js
CHANGED
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
loadFlow,
|
|
12
12
|
resolveFlowPath,
|
|
13
13
|
saveFlow
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-SX2Y4HDW.js";
|
|
15
15
|
|
|
16
16
|
// src/index.ts
|
|
17
17
|
import { createRequire as createRequire2 } from "module";
|
|
@@ -1316,7 +1316,9 @@ async function connectionListCommand(options) {
|
|
|
1316
1316
|
connections: limited.map((conn) => ({
|
|
1317
1317
|
platform: conn.platform,
|
|
1318
1318
|
state: conn.state,
|
|
1319
|
-
key: conn.key
|
|
1319
|
+
key: conn.key,
|
|
1320
|
+
...conn.name && { name: conn.name },
|
|
1321
|
+
...conn.tags?.length && { tags: conn.tags }
|
|
1320
1322
|
})),
|
|
1321
1323
|
...limited.length < filtered.length && {
|
|
1322
1324
|
hint: `Showing ${limited.length} of ${filtered.length} connections. Use --search <query> to filter by platform or --limit <n> to see more.`
|
|
@@ -2495,8 +2497,345 @@ function colorStatus(status) {
|
|
|
2495
2497
|
}
|
|
2496
2498
|
}
|
|
2497
2499
|
|
|
2498
|
-
// src/commands/
|
|
2500
|
+
// src/commands/relay.ts
|
|
2499
2501
|
import pc8 from "picocolors";
|
|
2502
|
+
function getConfig3() {
|
|
2503
|
+
const apiKey = getApiKey();
|
|
2504
|
+
if (!apiKey) {
|
|
2505
|
+
error("Not configured. Run `one init` first.");
|
|
2506
|
+
}
|
|
2507
|
+
const ac = getAccessControlFromAllSources();
|
|
2508
|
+
const connectionKeys = ac.connectionKeys || ["*"];
|
|
2509
|
+
return { apiKey, connectionKeys };
|
|
2510
|
+
}
|
|
2511
|
+
function parseJsonArg2(value, argName) {
|
|
2512
|
+
try {
|
|
2513
|
+
return JSON.parse(value);
|
|
2514
|
+
} catch {
|
|
2515
|
+
error(`Invalid JSON for ${argName}: ${value}`);
|
|
2516
|
+
}
|
|
2517
|
+
}
|
|
2518
|
+
async function relayCreateCommand(options) {
|
|
2519
|
+
const { apiKey, connectionKeys } = getConfig3();
|
|
2520
|
+
if (!connectionKeys.includes("*") && !connectionKeys.includes(options.connectionKey)) {
|
|
2521
|
+
error(`Connection key "${options.connectionKey}" is not allowed.`);
|
|
2522
|
+
}
|
|
2523
|
+
const api = new OneApi(apiKey);
|
|
2524
|
+
const spinner5 = createSpinner();
|
|
2525
|
+
spinner5.start("Creating relay endpoint...");
|
|
2526
|
+
try {
|
|
2527
|
+
const body = {
|
|
2528
|
+
connectionKey: options.connectionKey
|
|
2529
|
+
};
|
|
2530
|
+
if (options.description) body.description = options.description;
|
|
2531
|
+
if (options.eventFilters) body.eventFilters = parseJsonArg2(options.eventFilters, "--event-filters");
|
|
2532
|
+
if (options.tags) body.tags = parseJsonArg2(options.tags, "--tags");
|
|
2533
|
+
if (options.createWebhook) body.createWebhook = true;
|
|
2534
|
+
const result = await api.createRelayEndpoint(body);
|
|
2535
|
+
if (isAgentMode()) {
|
|
2536
|
+
json(result);
|
|
2537
|
+
return;
|
|
2538
|
+
}
|
|
2539
|
+
spinner5.stop("Relay endpoint created");
|
|
2540
|
+
console.log();
|
|
2541
|
+
console.log(` ${pc8.dim("ID:")} ${result.id}`);
|
|
2542
|
+
console.log(` ${pc8.dim("URL:")} ${result.url}`);
|
|
2543
|
+
console.log(` ${pc8.dim("Active:")} ${result.active}`);
|
|
2544
|
+
if (result.description) console.log(` ${pc8.dim("Description:")} ${result.description}`);
|
|
2545
|
+
if (result.eventFilters?.length) console.log(` ${pc8.dim("Events:")} ${result.eventFilters.join(", ")}`);
|
|
2546
|
+
if (result.webhookPayload?.id) console.log(` ${pc8.dim("Webhook ID:")} ${result.webhookPayload.id}`);
|
|
2547
|
+
console.log();
|
|
2548
|
+
} catch (error2) {
|
|
2549
|
+
spinner5.stop("Failed to create relay endpoint");
|
|
2550
|
+
error(`Error: ${error2 instanceof Error ? error2.message : "Unknown error"}`);
|
|
2551
|
+
}
|
|
2552
|
+
}
|
|
2553
|
+
async function relayListCommand(options) {
|
|
2554
|
+
const { apiKey } = getConfig3();
|
|
2555
|
+
const api = new OneApi(apiKey);
|
|
2556
|
+
const spinner5 = createSpinner();
|
|
2557
|
+
spinner5.start("Loading relay endpoints...");
|
|
2558
|
+
try {
|
|
2559
|
+
const query = {};
|
|
2560
|
+
if (options.limit) query.limit = options.limit;
|
|
2561
|
+
if (options.page) query.page = options.page;
|
|
2562
|
+
const result = await api.listRelayEndpoints(query);
|
|
2563
|
+
const endpoints = result.rows || [];
|
|
2564
|
+
if (isAgentMode()) {
|
|
2565
|
+
json({
|
|
2566
|
+
total: result.total,
|
|
2567
|
+
showing: endpoints.length,
|
|
2568
|
+
endpoints: endpoints.map((e) => ({
|
|
2569
|
+
id: e.id,
|
|
2570
|
+
active: e.active,
|
|
2571
|
+
description: e.description,
|
|
2572
|
+
eventFilters: e.eventFilters,
|
|
2573
|
+
actionsCount: e.actions?.length || 0,
|
|
2574
|
+
url: e.url,
|
|
2575
|
+
createdAt: e.createdAt
|
|
2576
|
+
}))
|
|
2577
|
+
});
|
|
2578
|
+
return;
|
|
2579
|
+
}
|
|
2580
|
+
spinner5.stop(`${endpoints.length} relay endpoint${endpoints.length === 1 ? "" : "s"} found`);
|
|
2581
|
+
if (endpoints.length === 0) {
|
|
2582
|
+
console.log("\n No relay endpoints yet.\n");
|
|
2583
|
+
return;
|
|
2584
|
+
}
|
|
2585
|
+
printTable(
|
|
2586
|
+
["Status", "Description", "Events", "Actions", "ID"],
|
|
2587
|
+
endpoints.map((e) => [
|
|
2588
|
+
e.active ? pc8.green("\u25CF") : pc8.dim("\u25CB"),
|
|
2589
|
+
e.description || pc8.dim("(none)"),
|
|
2590
|
+
e.eventFilters?.join(", ") || pc8.dim("all"),
|
|
2591
|
+
String(e.actions?.length || 0),
|
|
2592
|
+
pc8.dim(e.id.slice(0, 8))
|
|
2593
|
+
])
|
|
2594
|
+
);
|
|
2595
|
+
} catch (error2) {
|
|
2596
|
+
spinner5.stop("Failed to list relay endpoints");
|
|
2597
|
+
error(`Error: ${error2 instanceof Error ? error2.message : "Unknown error"}`);
|
|
2598
|
+
}
|
|
2599
|
+
}
|
|
2600
|
+
async function relayGetCommand(id) {
|
|
2601
|
+
const { apiKey } = getConfig3();
|
|
2602
|
+
const api = new OneApi(apiKey);
|
|
2603
|
+
const spinner5 = createSpinner();
|
|
2604
|
+
spinner5.start("Loading relay endpoint...");
|
|
2605
|
+
try {
|
|
2606
|
+
const result = await api.getRelayEndpoint(id);
|
|
2607
|
+
if (isAgentMode()) {
|
|
2608
|
+
json(result);
|
|
2609
|
+
return;
|
|
2610
|
+
}
|
|
2611
|
+
spinner5.stop("Relay endpoint loaded");
|
|
2612
|
+
console.log();
|
|
2613
|
+
console.log(` ${pc8.dim("ID:")} ${result.id}`);
|
|
2614
|
+
console.log(` ${pc8.dim("URL:")} ${result.url}`);
|
|
2615
|
+
console.log(` ${pc8.dim("Active:")} ${result.active}`);
|
|
2616
|
+
if (result.description) console.log(` ${pc8.dim("Description:")} ${result.description}`);
|
|
2617
|
+
if (result.eventFilters?.length) console.log(` ${pc8.dim("Events:")} ${result.eventFilters.join(", ")}`);
|
|
2618
|
+
console.log(` ${pc8.dim("Actions:")} ${result.actions?.length || 0}`);
|
|
2619
|
+
if (result.actions?.length) {
|
|
2620
|
+
for (const [i, action] of result.actions.entries()) {
|
|
2621
|
+
console.log(` ${pc8.dim(`[${i}]`)} type=${action.type}${action.actionId ? ` actionId=${action.actionId}` : ""}${action.url ? ` url=${action.url}` : ""}`);
|
|
2622
|
+
}
|
|
2623
|
+
}
|
|
2624
|
+
console.log(` ${pc8.dim("Created:")} ${result.createdAt}`);
|
|
2625
|
+
console.log();
|
|
2626
|
+
} catch (error2) {
|
|
2627
|
+
spinner5.stop("Failed to load relay endpoint");
|
|
2628
|
+
error(`Error: ${error2 instanceof Error ? error2.message : "Unknown error"}`);
|
|
2629
|
+
}
|
|
2630
|
+
}
|
|
2631
|
+
async function relayUpdateCommand(id, options) {
|
|
2632
|
+
const { apiKey } = getConfig3();
|
|
2633
|
+
const api = new OneApi(apiKey);
|
|
2634
|
+
const spinner5 = createSpinner();
|
|
2635
|
+
spinner5.start("Updating relay endpoint...");
|
|
2636
|
+
try {
|
|
2637
|
+
const body = {};
|
|
2638
|
+
if (options.description !== void 0) body.description = options.description;
|
|
2639
|
+
if (options.active !== void 0) body.active = options.active;
|
|
2640
|
+
if (options.eventFilters) body.eventFilters = parseJsonArg2(options.eventFilters, "--event-filters");
|
|
2641
|
+
if (options.tags) body.tags = parseJsonArg2(options.tags, "--tags");
|
|
2642
|
+
if (options.actions) body.actions = parseJsonArg2(options.actions, "--actions");
|
|
2643
|
+
const result = await api.updateRelayEndpoint(id, body);
|
|
2644
|
+
if (isAgentMode()) {
|
|
2645
|
+
json(result);
|
|
2646
|
+
return;
|
|
2647
|
+
}
|
|
2648
|
+
spinner5.stop("Relay endpoint updated");
|
|
2649
|
+
console.log(` ${pc8.dim("ID:")} ${result.id}`);
|
|
2650
|
+
console.log(` ${pc8.dim("Active:")} ${result.active}`);
|
|
2651
|
+
console.log(` ${pc8.dim("Actions:")} ${result.actions?.length || 0}`);
|
|
2652
|
+
console.log();
|
|
2653
|
+
} catch (error2) {
|
|
2654
|
+
spinner5.stop("Failed to update relay endpoint");
|
|
2655
|
+
error(`Error: ${error2 instanceof Error ? error2.message : "Unknown error"}`);
|
|
2656
|
+
}
|
|
2657
|
+
}
|
|
2658
|
+
async function relayDeleteCommand(id) {
|
|
2659
|
+
const { apiKey } = getConfig3();
|
|
2660
|
+
const api = new OneApi(apiKey);
|
|
2661
|
+
const spinner5 = createSpinner();
|
|
2662
|
+
spinner5.start("Deleting relay endpoint...");
|
|
2663
|
+
try {
|
|
2664
|
+
const result = await api.deleteRelayEndpoint(id);
|
|
2665
|
+
if (isAgentMode()) {
|
|
2666
|
+
json({ deleted: true, id: result.id });
|
|
2667
|
+
return;
|
|
2668
|
+
}
|
|
2669
|
+
spinner5.stop("Relay endpoint deleted");
|
|
2670
|
+
console.log(` Deleted: ${result.id}`);
|
|
2671
|
+
console.log();
|
|
2672
|
+
} catch (error2) {
|
|
2673
|
+
spinner5.stop("Failed to delete relay endpoint");
|
|
2674
|
+
error(`Error: ${error2 instanceof Error ? error2.message : "Unknown error"}`);
|
|
2675
|
+
}
|
|
2676
|
+
}
|
|
2677
|
+
async function relayActivateCommand(id, options) {
|
|
2678
|
+
const { apiKey } = getConfig3();
|
|
2679
|
+
const api = new OneApi(apiKey);
|
|
2680
|
+
const spinner5 = createSpinner();
|
|
2681
|
+
spinner5.start("Activating relay endpoint...");
|
|
2682
|
+
try {
|
|
2683
|
+
const actions2 = parseJsonArg2(options.actions, "--actions");
|
|
2684
|
+
const body = { actions: actions2 };
|
|
2685
|
+
if (options.webhookSecret) body.webhookSecret = options.webhookSecret;
|
|
2686
|
+
const result = await api.activateRelayEndpoint(id, body);
|
|
2687
|
+
if (isAgentMode()) {
|
|
2688
|
+
json(result);
|
|
2689
|
+
return;
|
|
2690
|
+
}
|
|
2691
|
+
spinner5.stop("Relay endpoint activated");
|
|
2692
|
+
console.log(` ${pc8.dim("ID:")} ${result.id}`);
|
|
2693
|
+
console.log(` ${pc8.dim("Active:")} ${result.active}`);
|
|
2694
|
+
console.log(` ${pc8.dim("Actions:")} ${result.actions?.length || 0}`);
|
|
2695
|
+
console.log();
|
|
2696
|
+
} catch (error2) {
|
|
2697
|
+
spinner5.stop("Failed to activate relay endpoint");
|
|
2698
|
+
error(`Error: ${error2 instanceof Error ? error2.message : "Unknown error"}`);
|
|
2699
|
+
}
|
|
2700
|
+
}
|
|
2701
|
+
async function relayEventsCommand(options) {
|
|
2702
|
+
const { apiKey } = getConfig3();
|
|
2703
|
+
const api = new OneApi(apiKey);
|
|
2704
|
+
const spinner5 = createSpinner();
|
|
2705
|
+
spinner5.start("Loading relay events...");
|
|
2706
|
+
try {
|
|
2707
|
+
const query = {};
|
|
2708
|
+
if (options.limit) query.limit = options.limit;
|
|
2709
|
+
if (options.page) query.page = options.page;
|
|
2710
|
+
if (options.platform) query.platform = options.platform;
|
|
2711
|
+
if (options.eventType) query.eventType = options.eventType;
|
|
2712
|
+
if (options.after) query.after = options.after;
|
|
2713
|
+
if (options.before) query.before = options.before;
|
|
2714
|
+
const result = await api.listRelayEvents(query);
|
|
2715
|
+
const events = result.rows || [];
|
|
2716
|
+
if (isAgentMode()) {
|
|
2717
|
+
json({
|
|
2718
|
+
total: result.total,
|
|
2719
|
+
showing: events.length,
|
|
2720
|
+
events: events.map((e) => ({
|
|
2721
|
+
id: e.id,
|
|
2722
|
+
platform: e.platform,
|
|
2723
|
+
eventType: e.eventType,
|
|
2724
|
+
timestamp: e.timestamp || e.createdAt
|
|
2725
|
+
}))
|
|
2726
|
+
});
|
|
2727
|
+
return;
|
|
2728
|
+
}
|
|
2729
|
+
spinner5.stop(`${events.length} event${events.length === 1 ? "" : "s"} found`);
|
|
2730
|
+
if (events.length === 0) {
|
|
2731
|
+
console.log("\n No events found.\n");
|
|
2732
|
+
return;
|
|
2733
|
+
}
|
|
2734
|
+
printTable(
|
|
2735
|
+
["Platform", "Event Type", "Timestamp", "ID"],
|
|
2736
|
+
events.map((e) => [
|
|
2737
|
+
e.platform,
|
|
2738
|
+
e.eventType || pc8.dim("unknown"),
|
|
2739
|
+
e.timestamp || e.createdAt,
|
|
2740
|
+
pc8.dim(e.id.slice(0, 8))
|
|
2741
|
+
])
|
|
2742
|
+
);
|
|
2743
|
+
} catch (error2) {
|
|
2744
|
+
spinner5.stop("Failed to list relay events");
|
|
2745
|
+
error(`Error: ${error2 instanceof Error ? error2.message : "Unknown error"}`);
|
|
2746
|
+
}
|
|
2747
|
+
}
|
|
2748
|
+
async function relayEventGetCommand(id) {
|
|
2749
|
+
const { apiKey } = getConfig3();
|
|
2750
|
+
const api = new OneApi(apiKey);
|
|
2751
|
+
const spinner5 = createSpinner();
|
|
2752
|
+
spinner5.start("Loading relay event...");
|
|
2753
|
+
try {
|
|
2754
|
+
const result = await api.getRelayEvent(id);
|
|
2755
|
+
if (isAgentMode()) {
|
|
2756
|
+
json(result);
|
|
2757
|
+
return;
|
|
2758
|
+
}
|
|
2759
|
+
spinner5.stop("Relay event loaded");
|
|
2760
|
+
console.log();
|
|
2761
|
+
console.log(` ${pc8.dim("ID:")} ${result.id}`);
|
|
2762
|
+
console.log(` ${pc8.dim("Platform:")} ${result.platform}`);
|
|
2763
|
+
console.log(` ${pc8.dim("Event:")} ${result.eventType}`);
|
|
2764
|
+
console.log(` ${pc8.dim("Timestamp:")} ${result.timestamp || result.createdAt}`);
|
|
2765
|
+
console.log(` ${pc8.dim("Payload:")}`);
|
|
2766
|
+
console.log(JSON.stringify(result.payload, null, 2));
|
|
2767
|
+
console.log();
|
|
2768
|
+
} catch (error2) {
|
|
2769
|
+
spinner5.stop("Failed to load relay event");
|
|
2770
|
+
error(`Error: ${error2 instanceof Error ? error2.message : "Unknown error"}`);
|
|
2771
|
+
}
|
|
2772
|
+
}
|
|
2773
|
+
async function relayDeliveriesCommand(options) {
|
|
2774
|
+
if (!options.endpointId && !options.eventId) {
|
|
2775
|
+
error("Provide either --endpoint-id or --event-id");
|
|
2776
|
+
}
|
|
2777
|
+
const { apiKey } = getConfig3();
|
|
2778
|
+
const api = new OneApi(apiKey);
|
|
2779
|
+
const spinner5 = createSpinner();
|
|
2780
|
+
spinner5.start("Loading deliveries...");
|
|
2781
|
+
try {
|
|
2782
|
+
const deliveries = options.endpointId ? await api.listRelayEndpointDeliveries(options.endpointId) : await api.listRelayEventDeliveries(options.eventId);
|
|
2783
|
+
const items = Array.isArray(deliveries) ? deliveries : deliveries.rows || [];
|
|
2784
|
+
if (isAgentMode()) {
|
|
2785
|
+
json({ deliveries: items });
|
|
2786
|
+
return;
|
|
2787
|
+
}
|
|
2788
|
+
spinner5.stop(`${items.length} deliver${items.length === 1 ? "y" : "ies"} found`);
|
|
2789
|
+
if (items.length === 0) {
|
|
2790
|
+
console.log("\n No deliveries found.\n");
|
|
2791
|
+
return;
|
|
2792
|
+
}
|
|
2793
|
+
printTable(
|
|
2794
|
+
["Status", "Code", "Attempt", "Delivered At", "Error"],
|
|
2795
|
+
items.map((d) => [
|
|
2796
|
+
d.status === "success" ? pc8.green(d.status) : pc8.red(d.status),
|
|
2797
|
+
d.statusCode != null ? String(d.statusCode) : pc8.dim("-"),
|
|
2798
|
+
String(d.attempt),
|
|
2799
|
+
d.deliveredAt || pc8.dim("-"),
|
|
2800
|
+
d.error ? pc8.red(d.error.slice(0, 50)) : pc8.dim("-")
|
|
2801
|
+
])
|
|
2802
|
+
);
|
|
2803
|
+
} catch (error2) {
|
|
2804
|
+
spinner5.stop("Failed to load deliveries");
|
|
2805
|
+
error(`Error: ${error2 instanceof Error ? error2.message : "Unknown error"}`);
|
|
2806
|
+
}
|
|
2807
|
+
}
|
|
2808
|
+
async function relayEventTypesCommand(platform) {
|
|
2809
|
+
const { apiKey } = getConfig3();
|
|
2810
|
+
const api = new OneApi(apiKey);
|
|
2811
|
+
const spinner5 = createSpinner();
|
|
2812
|
+
spinner5.start(`Loading event types for ${pc8.cyan(platform)}...`);
|
|
2813
|
+
try {
|
|
2814
|
+
const eventTypes = await api.listRelayEventTypes(platform);
|
|
2815
|
+
if (isAgentMode()) {
|
|
2816
|
+
json({ platform, eventTypes });
|
|
2817
|
+
return;
|
|
2818
|
+
}
|
|
2819
|
+
spinner5.stop(`${eventTypes.length} event type${eventTypes.length === 1 ? "" : "s"} found`);
|
|
2820
|
+
if (eventTypes.length === 0) {
|
|
2821
|
+
console.log(`
|
|
2822
|
+
No event types found for ${platform}.
|
|
2823
|
+
`);
|
|
2824
|
+
return;
|
|
2825
|
+
}
|
|
2826
|
+
console.log();
|
|
2827
|
+
for (const type of eventTypes) {
|
|
2828
|
+
console.log(` ${type}`);
|
|
2829
|
+
}
|
|
2830
|
+
console.log();
|
|
2831
|
+
} catch (error2) {
|
|
2832
|
+
spinner5.stop("Failed to load event types");
|
|
2833
|
+
error(`Error: ${error2 instanceof Error ? error2.message : "Unknown error"}`);
|
|
2834
|
+
}
|
|
2835
|
+
}
|
|
2836
|
+
|
|
2837
|
+
// src/commands/guide.ts
|
|
2838
|
+
import pc9 from "picocolors";
|
|
2500
2839
|
|
|
2501
2840
|
// src/lib/guide-content.ts
|
|
2502
2841
|
var GUIDE_OVERVIEW = `# One CLI \u2014 Agent Guide
|
|
@@ -2517,886 +2856,316 @@ one --agent <command>
|
|
|
2517
2856
|
|
|
2518
2857
|
All commands return JSON. If an \`error\` key is present, the command failed.
|
|
2519
2858
|
|
|
2520
|
-
##
|
|
2521
|
-
|
|
2522
|
-
This guide has three sections you can request individually:
|
|
2523
|
-
|
|
2524
|
-
- **overview** \u2014 This section. Setup, flag usage, and discovery workflow.
|
|
2525
|
-
- **actions** \u2014 Full workflow for searching, reading docs, and executing platform actions.
|
|
2526
|
-
- **workflows** \u2014 Building and executing multi-step API workflows (JSON-based).
|
|
2527
|
-
|
|
2528
|
-
## Discovery Workflow
|
|
2529
|
-
|
|
2530
|
-
1. \`one --agent connection list\` \u2014 See connected platforms and connection keys
|
|
2531
|
-
2. \`one --agent actions search <platform> <query>\` \u2014 Find actions
|
|
2532
|
-
3. \`one --agent actions knowledge <platform> <actionId>\` \u2014 Read full docs (REQUIRED before execute)
|
|
2533
|
-
4. \`one --agent actions execute <platform> <actionId> <connectionKey>\` \u2014 Execute the action
|
|
2534
|
-
|
|
2535
|
-
For multi-step workflows:
|
|
2536
|
-
1. Discover actions with the workflow above
|
|
2537
|
-
2. Build a workflow JSON definition
|
|
2538
|
-
3. \`one --agent flow create <key> --definition '<json>'\`
|
|
2539
|
-
4. \`one --agent flow execute <key> -i param=value\`
|
|
2540
|
-
|
|
2541
|
-
Platform names are always kebab-case (e.g., \`hub-spot\`, \`google-calendar\`).
|
|
2542
|
-
Run \`one platforms\` to browse all 200+ available platforms.
|
|
2543
|
-
`;
|
|
2544
|
-
var GUIDE_ACTIONS = `# One Actions CLI Workflow
|
|
2545
|
-
|
|
2546
|
-
You have access to the One CLI which lets you interact with 200+ third-party platforms through their APIs. The CLI handles authentication, request building, and execution through One's passthrough proxy.
|
|
2547
|
-
|
|
2548
|
-
## The Workflow
|
|
2549
|
-
|
|
2550
|
-
Always follow this sequence \u2014 each step builds on the previous one:
|
|
2551
|
-
|
|
2552
|
-
1. **List connections** to see what platforms the user has connected
|
|
2553
|
-
2. **Search actions** to find the right API action for what the user wants to do
|
|
2554
|
-
3. **Get knowledge** to understand the action's parameters, requirements, and structure
|
|
2555
|
-
4. **Execute** the action with the correct parameters
|
|
2556
|
-
|
|
2557
|
-
Never skip the knowledge step before executing \u2014 it contains critical information about required parameters, validation rules, and request structure that you need to build a correct request.
|
|
2558
|
-
|
|
2559
|
-
## Commands
|
|
2560
|
-
|
|
2561
|
-
### 1. List Connections
|
|
2562
|
-
|
|
2563
|
-
\`\`\`bash
|
|
2564
|
-
one --agent connection list
|
|
2565
|
-
\`\`\`
|
|
2566
|
-
|
|
2567
|
-
Returns JSON with all connected platforms, their status, and connection keys. You need the **connection key** for executing actions, and the **platform name** (kebab-case) for searching actions.
|
|
2568
|
-
|
|
2569
|
-
Output format:
|
|
2570
|
-
\`\`\`json
|
|
2571
|
-
{"connections": [{"platform": "gmail", "state": "active", "key": "conn_abc123"}, ...]}
|
|
2572
|
-
\`\`\`
|
|
2573
|
-
|
|
2574
|
-
### 2. Search Actions
|
|
2859
|
+
## IMPORTANT: Learn before you use
|
|
2575
2860
|
|
|
2576
|
-
|
|
2577
|
-
one --agent actions search <platform> <query>
|
|
2578
|
-
\`\`\`
|
|
2579
|
-
|
|
2580
|
-
Search for actions on a specific platform using natural language. Returns JSON with up to 5 matching actions including their action IDs, HTTP methods, and paths.
|
|
2861
|
+
Before using any feature, you MUST read the corresponding skill documentation first. The skills are bundled with the CLI and teach you the correct workflow, required steps, template syntax, and common mistakes. Never guess \u2014 read the skill, then act.
|
|
2581
2862
|
|
|
2582
|
-
|
|
2583
|
-
- \`<query>\` \u2014 Natural language description of what you want to do (e.g., \`"send email"\`, \`"list contacts"\`, \`"create order"\`)
|
|
2863
|
+
## Features
|
|
2584
2864
|
|
|
2585
|
-
|
|
2586
|
-
|
|
2865
|
+
### 1. Actions \u2014 Execute API calls on 200+ platforms
|
|
2866
|
+
Search for actions, read their docs, and execute them. This is the core workflow.
|
|
2587
2867
|
|
|
2588
|
-
|
|
2868
|
+
**Quick start:**
|
|
2589
2869
|
\`\`\`bash
|
|
2590
|
-
one --agent
|
|
2870
|
+
one --agent connection list # See connected platforms
|
|
2871
|
+
one --agent actions search <platform> "<query>" -t execute # Find an action
|
|
2872
|
+
one --agent actions knowledge <platform> <actionId> # Read docs (REQUIRED)
|
|
2873
|
+
one --agent actions execute <platform> <actionId> <key> -d '{}' # Execute it
|
|
2591
2874
|
\`\`\`
|
|
2592
2875
|
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
|
|
2600
|
-
\`\`\`bash
|
|
2601
|
-
one --agent actions knowledge <platform> <actionId>
|
|
2602
|
-
\`\`\`
|
|
2876
|
+
**Parameter flags:**
|
|
2877
|
+
- \`-d <json>\` \u2014 Request body (POST/PUT/PATCH)
|
|
2878
|
+
- \`--path-vars <json>\` \u2014 URL path variables (e.g., \`{"userId": "me"}\`)
|
|
2879
|
+
- \`--query-params <json>\` \u2014 Query parameters (arrays expand to repeated params)
|
|
2880
|
+
- \`--form-url-encoded\` \u2014 Send as form data instead of JSON
|
|
2881
|
+
- \`--dry-run\` \u2014 Preview request without executing
|
|
2603
2882
|
|
|
2604
|
-
|
|
2883
|
+
Do NOT pass path or query parameters in \`-d\` \u2014 use the correct flags.
|
|
2605
2884
|
|
|
2606
|
-
|
|
2885
|
+
### 2. Flows \u2014 Multi-step API workflows
|
|
2886
|
+
Chain actions across platforms as JSON workflow files with conditions, loops, parallel execution, transforms, and AI analysis via bash steps.
|
|
2607
2887
|
|
|
2608
|
-
|
|
2888
|
+
**Quick start:**
|
|
2609
2889
|
\`\`\`bash
|
|
2610
|
-
one --agent
|
|
2890
|
+
one --agent flow create <key> --definition '<json>' # Create a workflow
|
|
2891
|
+
one --agent flow validate <key> # Validate it
|
|
2892
|
+
one --agent flow execute <key> -i param=value # Execute it
|
|
2893
|
+
one --agent flow list # List all workflows
|
|
2611
2894
|
\`\`\`
|
|
2612
2895
|
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
\`\`\`bash
|
|
2621
|
-
one --agent actions execute <platform> <actionId> <connectionKey> [options]
|
|
2622
|
-
\`\`\`
|
|
2623
|
-
|
|
2624
|
-
Execute an action on a connected platform. Returns JSON with the request details and response data. You must have retrieved the knowledge for this action first.
|
|
2625
|
-
|
|
2626
|
-
- \`<platform>\` \u2014 Platform name in kebab-case
|
|
2627
|
-
- \`<actionId>\` \u2014 Action ID from the search results
|
|
2628
|
-
- \`<connectionKey>\` \u2014 Connection key from \`one connection list\`
|
|
2896
|
+
**Key concepts:**
|
|
2897
|
+
- Workflows are JSON files at \`.one/flows/<key>.flow.json\`
|
|
2898
|
+
- 12 step types: action, transform, code, condition, loop, parallel, file-read, file-write, while, flow, paginate, bash
|
|
2899
|
+
- Data wiring via selectors: \`$.input.param\`, \`$.steps.stepId.response\`, \`$.loop.item\`
|
|
2900
|
+
- AI analysis via bash steps: \`claude --print\` with \`parseJson: true\`
|
|
2901
|
+
- Use \`--allow-bash\` to enable bash steps, \`--mock\` for dry-run with mock responses
|
|
2629
2902
|
|
|
2630
|
-
|
|
2631
|
-
|
|
2632
|
-
- \`--path-vars <json>\` \u2014 Path variables as JSON (for URLs with \`{id}\` placeholders)
|
|
2633
|
-
- \`--query-params <json>\` \u2014 Query parameters as JSON
|
|
2634
|
-
- \`--headers <json>\` \u2014 Additional headers as JSON
|
|
2635
|
-
- \`--form-data\` \u2014 Send as multipart/form-data instead of JSON
|
|
2636
|
-
- \`--form-url-encoded\` \u2014 Send as application/x-www-form-urlencoded
|
|
2637
|
-
- \`--dry-run\` \u2014 Show the request that would be sent without executing it
|
|
2903
|
+
### 3. Relay \u2014 Webhook event forwarding between platforms
|
|
2904
|
+
Receive webhooks from platforms (Stripe, GitHub, Airtable, Attio, Google Calendar) and forward event data to any connected platform using passthrough actions with Handlebars templates. No middleware, no code.
|
|
2638
2905
|
|
|
2639
|
-
|
|
2906
|
+
**Quick start:**
|
|
2640
2907
|
\`\`\`bash
|
|
2641
|
-
#
|
|
2642
|
-
one --agent
|
|
2643
|
-
|
|
2644
|
-
#
|
|
2645
|
-
one --agent
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
# With path variables and query params
|
|
2649
|
-
one --agent actions execute shopify <actionId> <connectionKey> \\
|
|
2650
|
-
--path-vars '{"order_id": "12345"}' \\
|
|
2651
|
-
--query-params '{"limit": "10"}'
|
|
2652
|
-
\`\`\`
|
|
2653
|
-
|
|
2654
|
-
Output format:
|
|
2655
|
-
\`\`\`json
|
|
2656
|
-
{"request": {"method": "POST", "url": "https://..."}, "response": {...}}
|
|
2908
|
+
one --agent relay event-types <platform> # See available events
|
|
2909
|
+
one --agent relay create --connection-key <key> --create-webhook --event-filters '["event.type"]'
|
|
2910
|
+
one --agent relay activate <id> --actions '[{"type":"passthrough","actionId":"...","connectionKey":"...","body":{...}}]'
|
|
2911
|
+
one --agent relay list # List endpoints
|
|
2912
|
+
one --agent relay events --platform <p> # List received events
|
|
2913
|
+
one --agent relay deliveries --endpoint-id <id> # Check delivery status
|
|
2657
2914
|
\`\`\`
|
|
2658
2915
|
|
|
2659
|
-
|
|
2916
|
+
**Key concepts:**
|
|
2917
|
+
- \`passthrough\` actions map webhook fields to another platform's API using Handlebars: \`{{payload.data.object.email}}\`
|
|
2918
|
+
- Template context: \`{{relayEventId}}\`, \`{{platform}}\`, \`{{eventType}}\`, \`{{payload}}\`, \`{{timestamp}}\`, \`{{connectionId}}\`
|
|
2919
|
+
- \`--create-webhook\` auto-registers the webhook URL with the source platform
|
|
2920
|
+
- Use \`actions knowledge\` to learn both the incoming payload shape AND the destination API shape before building templates
|
|
2660
2921
|
|
|
2661
|
-
|
|
2662
|
-
\`\`\`json
|
|
2663
|
-
{"error": "Error message here"}
|
|
2664
|
-
\`\`\`
|
|
2922
|
+
## Topics
|
|
2665
2923
|
|
|
2666
|
-
|
|
2924
|
+
Request specific sections:
|
|
2925
|
+
- \`one guide overview\` \u2014 This section
|
|
2926
|
+
- \`one guide actions\` \u2014 Actions reference (search, knowledge, execute)
|
|
2927
|
+
- \`one guide flows\` \u2014 Workflow engine reference (step types, selectors, examples)
|
|
2928
|
+
- \`one guide relay\` \u2014 Webhook relay reference (templates, passthrough actions)
|
|
2929
|
+
- \`one guide all\` \u2014 Everything
|
|
2667
2930
|
|
|
2668
2931
|
## Important Notes
|
|
2669
2932
|
|
|
2670
|
-
- **Always use \`--agent\` flag**
|
|
2671
|
-
- Platform names are always **kebab-case** (e.g., \`hub-spot
|
|
2672
|
-
- Always use the **exact action ID** from search results \u2014 don't guess
|
|
2673
|
-
- Always read
|
|
2674
|
-
-
|
|
2675
|
-
- If search returns no results, try broader queries (e.g., \`"list"\` instead of \`"list active premium customers"\`)
|
|
2676
|
-
- The execute command respects access control settings configured via \`one config\` \u2014 if execution is blocked, the user may need to adjust their permissions
|
|
2933
|
+
- **Always use \`--agent\` flag** for structured JSON output
|
|
2934
|
+
- Platform names are always **kebab-case** (e.g., \`hub-spot\`, \`google-calendar\`)
|
|
2935
|
+
- Always use the **exact action ID** from search results \u2014 don't guess
|
|
2936
|
+
- Always read **knowledge** before executing any action
|
|
2937
|
+
- Connection keys come from \`one connection list\` \u2014 don't hardcode them
|
|
2677
2938
|
`;
|
|
2678
|
-
var
|
|
2939
|
+
var GUIDE_ACTIONS = `# One Actions \u2014 Reference
|
|
2679
2940
|
|
|
2680
|
-
|
|
2941
|
+
## Workflow: search \u2192 knowledge \u2192 execute
|
|
2681
2942
|
|
|
2682
|
-
|
|
2943
|
+
Always follow this sequence. Never skip the knowledge step.
|
|
2683
2944
|
|
|
2684
|
-
|
|
2685
|
-
- All dynamic values (including connection keys) are declared as **inputs**
|
|
2686
|
-
- Each workflow has a unique **key** used to reference and execute it
|
|
2687
|
-
- Executed via \`one --agent flow execute <key> -i name=value\`
|
|
2688
|
-
|
|
2689
|
-
## 2. Building a Workflow \u2014 Step-by-Step Process
|
|
2690
|
-
|
|
2691
|
-
**You MUST follow this process to build a correct workflow:**
|
|
2692
|
-
|
|
2693
|
-
### Step 1: Discover connections
|
|
2945
|
+
### 1. List Connections
|
|
2694
2946
|
|
|
2695
2947
|
\`\`\`bash
|
|
2696
2948
|
one --agent connection list
|
|
2697
2949
|
\`\`\`
|
|
2698
2950
|
|
|
2699
|
-
|
|
2951
|
+
Returns platforms, status, connection keys, and tags.
|
|
2700
2952
|
|
|
2701
|
-
###
|
|
2953
|
+
### 2. Search Actions
|
|
2702
2954
|
|
|
2703
2955
|
\`\`\`bash
|
|
2704
|
-
# Find the action ID
|
|
2705
2956
|
one --agent actions search <platform> "<query>" -t execute
|
|
2706
|
-
|
|
2707
|
-
# Read the full docs \u2014 REQUIRED before adding to a workflow
|
|
2708
|
-
one --agent actions knowledge <platform> <actionId>
|
|
2709
2957
|
\`\`\`
|
|
2710
2958
|
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
|
|
2959
|
+
- Use \`-t execute\` when the user wants to perform an action
|
|
2960
|
+
- Use \`-t knowledge\` (default) for documentation/code generation
|
|
2961
|
+
- Returns up to 5 matching actions with IDs, methods, and paths
|
|
2714
2962
|
|
|
2715
|
-
|
|
2716
|
-
- All inputs declared (connection keys + user parameters)
|
|
2717
|
-
- Each step with the correct actionId, platform, and data structure (from knowledge)
|
|
2718
|
-
- Data wired between steps using \`$.input.*\` and \`$.steps.*\` selectors
|
|
2719
|
-
|
|
2720
|
-
### Step 4: Write the workflow file
|
|
2963
|
+
### 3. Get Knowledge
|
|
2721
2964
|
|
|
2722
2965
|
\`\`\`bash
|
|
2723
|
-
one --agent
|
|
2966
|
+
one --agent actions knowledge <platform> <actionId>
|
|
2724
2967
|
\`\`\`
|
|
2725
2968
|
|
|
2726
|
-
|
|
2969
|
+
Returns full API docs: required fields, validation rules, request structure. **REQUIRED before execute.** The output includes a CLI PARAMETER MAPPING section showing which flags to use.
|
|
2727
2970
|
|
|
2728
|
-
###
|
|
2971
|
+
### 4. Execute
|
|
2729
2972
|
|
|
2730
2973
|
\`\`\`bash
|
|
2731
|
-
one --agent
|
|
2732
|
-
\`\`\`
|
|
2733
|
-
|
|
2734
|
-
### Step 6: Execute
|
|
2735
|
-
|
|
2736
|
-
\`\`\`bash
|
|
2737
|
-
one --agent flow execute <key> -i connectionKey=xxx -i param=value
|
|
2738
|
-
\`\`\`
|
|
2739
|
-
|
|
2740
|
-
## 3. Workflow JSON Schema Reference
|
|
2741
|
-
|
|
2742
|
-
\`\`\`json
|
|
2743
|
-
{
|
|
2744
|
-
"key": "welcome-customer",
|
|
2745
|
-
"name": "Welcome New Customer",
|
|
2746
|
-
"description": "Look up a Stripe customer and send them a welcome email via Gmail",
|
|
2747
|
-
"version": "1",
|
|
2748
|
-
"inputs": {
|
|
2749
|
-
"stripeConnectionKey": {
|
|
2750
|
-
"type": "string",
|
|
2751
|
-
"required": true,
|
|
2752
|
-
"description": "Stripe connection key from one connection list",
|
|
2753
|
-
"connection": { "platform": "stripe" }
|
|
2754
|
-
},
|
|
2755
|
-
"gmailConnectionKey": {
|
|
2756
|
-
"type": "string",
|
|
2757
|
-
"required": true,
|
|
2758
|
-
"description": "Gmail connection key from one connection list",
|
|
2759
|
-
"connection": { "platform": "gmail" }
|
|
2760
|
-
},
|
|
2761
|
-
"customerEmail": {
|
|
2762
|
-
"type": "string",
|
|
2763
|
-
"required": true,
|
|
2764
|
-
"description": "Customer email to look up"
|
|
2765
|
-
}
|
|
2766
|
-
},
|
|
2767
|
-
"steps": [
|
|
2768
|
-
{
|
|
2769
|
-
"id": "stepId",
|
|
2770
|
-
"name": "Human-readable label",
|
|
2771
|
-
"type": "action",
|
|
2772
|
-
"action": {
|
|
2773
|
-
"platform": "stripe",
|
|
2774
|
-
"actionId": "the-action-id-from-search",
|
|
2775
|
-
"connectionKey": "$.input.stripeConnectionKey",
|
|
2776
|
-
"data": {},
|
|
2777
|
-
"pathVars": {},
|
|
2778
|
-
"queryParams": {},
|
|
2779
|
-
"headers": {}
|
|
2780
|
-
}
|
|
2781
|
-
}
|
|
2782
|
-
]
|
|
2783
|
-
}
|
|
2784
|
-
\`\`\`
|
|
2785
|
-
|
|
2786
|
-
### Input declarations
|
|
2787
|
-
|
|
2788
|
-
| Field | Type | Description |
|
|
2789
|
-
|---|---|---|
|
|
2790
|
-
| \`type\` | string | \`string\`, \`number\`, \`boolean\`, \`object\`, \`array\` |
|
|
2791
|
-
| \`required\` | boolean | Whether this input must be provided (default: true) |
|
|
2792
|
-
| \`default\` | any | Default value if not provided |
|
|
2793
|
-
| \`description\` | string | Human-readable description |
|
|
2794
|
-
| \`connection\` | object | Connection metadata: \`{ "platform": "gmail" }\` \u2014 enables auto-resolution |
|
|
2795
|
-
|
|
2796
|
-
**Connection inputs** have a \`connection\` field. If the user has exactly one connection for that platform, the workflow engine auto-resolves it.
|
|
2797
|
-
|
|
2798
|
-
## 4. Selector Syntax Reference
|
|
2799
|
-
|
|
2800
|
-
| Pattern | Resolves To |
|
|
2801
|
-
|---|---|
|
|
2802
|
-
| \`$.input.gmailConnectionKey\` | Input value (including connection keys) |
|
|
2803
|
-
| \`$.input.customerEmail\` | Any input parameter |
|
|
2804
|
-
| \`$.steps.stepId.response\` | Full API response from a step |
|
|
2805
|
-
| \`$.steps.stepId.response.data[0].email\` | Nested field with array index |
|
|
2806
|
-
| \`$.steps.stepId.response.data[*].id\` | Wildcard \u2014 maps array to field |
|
|
2807
|
-
| \`$.env.MY_VAR\` | Environment variable |
|
|
2808
|
-
| \`$.loop.item\` | Current loop item |
|
|
2809
|
-
| \`$.loop.i\` | Current loop index |
|
|
2810
|
-
| \`"Hello {{$.steps.getUser.response.data.name}}"\` | String interpolation |
|
|
2811
|
-
|
|
2812
|
-
**Rules:**
|
|
2813
|
-
- A value that is purely \`$.xxx\` resolves to the raw type (object, array, number)
|
|
2814
|
-
- A string containing \`{{$.xxx}}\` does string interpolation (stringifies objects)
|
|
2815
|
-
- Selectors inside objects/arrays are resolved recursively
|
|
2816
|
-
|
|
2817
|
-
## 5. Step Types Reference
|
|
2818
|
-
|
|
2819
|
-
### \`action\` \u2014 Execute a One API action
|
|
2820
|
-
|
|
2821
|
-
\`\`\`json
|
|
2822
|
-
{
|
|
2823
|
-
"id": "findCustomer",
|
|
2824
|
-
"name": "Search Stripe customers",
|
|
2825
|
-
"type": "action",
|
|
2826
|
-
"action": {
|
|
2827
|
-
"platform": "stripe",
|
|
2828
|
-
"actionId": "conn_mod_def::xxx::yyy",
|
|
2829
|
-
"connectionKey": "$.input.stripeConnectionKey",
|
|
2830
|
-
"data": {
|
|
2831
|
-
"query": "email:'{{$.input.customerEmail}}'"
|
|
2832
|
-
}
|
|
2833
|
-
}
|
|
2834
|
-
}
|
|
2835
|
-
\`\`\`
|
|
2836
|
-
|
|
2837
|
-
### \`transform\` \u2014 Transform data with a JS expression
|
|
2838
|
-
|
|
2839
|
-
\`\`\`json
|
|
2840
|
-
{
|
|
2841
|
-
"id": "extractNames",
|
|
2842
|
-
"name": "Extract customer names",
|
|
2843
|
-
"type": "transform",
|
|
2844
|
-
"transform": {
|
|
2845
|
-
"expression": "$.steps.findCustomer.response.data.map(c => c.name)"
|
|
2846
|
-
}
|
|
2847
|
-
}
|
|
2848
|
-
\`\`\`
|
|
2849
|
-
|
|
2850
|
-
The expression is evaluated with the full flow context as \`$\`.
|
|
2851
|
-
|
|
2852
|
-
### \`code\` \u2014 Run multi-line JavaScript
|
|
2853
|
-
|
|
2854
|
-
Unlike \`transform\` (single expression, implicit return), \`code\` runs a full function body with explicit \`return\`. Use it when you need variables, loops, try/catch, or \`await\`.
|
|
2855
|
-
|
|
2856
|
-
\`\`\`json
|
|
2857
|
-
{
|
|
2858
|
-
"id": "processData",
|
|
2859
|
-
"name": "Process and enrich data",
|
|
2860
|
-
"type": "code",
|
|
2861
|
-
"code": {
|
|
2862
|
-
"source": "const customers = $.steps.listCustomers.response.data;\\nconst enriched = customers.map(c => ({\\n ...c,\\n tier: c.spend > 1000 ? 'gold' : 'silver'\\n}));\\nreturn enriched;"
|
|
2863
|
-
}
|
|
2864
|
-
}
|
|
2865
|
-
\`\`\`
|
|
2866
|
-
|
|
2867
|
-
The \`source\` field contains a JS function body. The flow context is available as \`$\`. The function is async, so you can use \`await\`. The return value is stored as the step result.
|
|
2868
|
-
|
|
2869
|
-
### \`condition\` \u2014 If/then/else branching
|
|
2870
|
-
|
|
2871
|
-
\`\`\`json
|
|
2872
|
-
{
|
|
2873
|
-
"id": "checkFound",
|
|
2874
|
-
"name": "Check if customer was found",
|
|
2875
|
-
"type": "condition",
|
|
2876
|
-
"condition": {
|
|
2877
|
-
"expression": "$.steps.findCustomer.response.data.length > 0",
|
|
2878
|
-
"then": [
|
|
2879
|
-
{ "id": "sendEmail", "name": "Send welcome email", "type": "action", "action": { "..." : "..." } }
|
|
2880
|
-
],
|
|
2881
|
-
"else": [
|
|
2882
|
-
{ "id": "logNotFound", "name": "Log not found", "type": "transform", "transform": { "expression": "'Customer not found'" } }
|
|
2883
|
-
]
|
|
2884
|
-
}
|
|
2885
|
-
}
|
|
2886
|
-
\`\`\`
|
|
2887
|
-
|
|
2888
|
-
### \`loop\` \u2014 Iterate over an array
|
|
2889
|
-
|
|
2890
|
-
\`\`\`json
|
|
2891
|
-
{
|
|
2892
|
-
"id": "processOrders",
|
|
2893
|
-
"name": "Process each order",
|
|
2894
|
-
"type": "loop",
|
|
2895
|
-
"loop": {
|
|
2896
|
-
"over": "$.steps.listOrders.response.data",
|
|
2897
|
-
"as": "order",
|
|
2898
|
-
"indexAs": "i",
|
|
2899
|
-
"maxIterations": 1000,
|
|
2900
|
-
"maxConcurrency": 5,
|
|
2901
|
-
"steps": [
|
|
2902
|
-
{
|
|
2903
|
-
"id": "createInvoice",
|
|
2904
|
-
"name": "Create invoice for order",
|
|
2905
|
-
"type": "action",
|
|
2906
|
-
"action": {
|
|
2907
|
-
"platform": "quickbooks",
|
|
2908
|
-
"actionId": "...",
|
|
2909
|
-
"connectionKey": "$.input.qbConnectionKey",
|
|
2910
|
-
"data": { "amount": "$.loop.order.total" }
|
|
2911
|
-
}
|
|
2912
|
-
}
|
|
2913
|
-
]
|
|
2914
|
-
}
|
|
2915
|
-
}
|
|
2974
|
+
one --agent actions execute <platform> <actionId> <connectionKey> [options]
|
|
2916
2975
|
\`\`\`
|
|
2917
2976
|
|
|
2918
|
-
|
|
2977
|
+
**Flags:**
|
|
2978
|
+
- \`-d, --data <json>\` \u2014 Request body (POST/PUT/PATCH)
|
|
2979
|
+
- \`--path-vars <json>\` \u2014 Path variables: \`{"userId": "me"}\`
|
|
2980
|
+
- \`--query-params <json>\` \u2014 Query params: \`{"limit": "10"}\`
|
|
2981
|
+
- Arrays expand to repeated params: \`{"metadataHeaders": ["From", "Subject"]}\`
|
|
2982
|
+
- \`--headers <json>\` \u2014 Additional headers
|
|
2983
|
+
- \`--form-data\` / \`--form-url-encoded\` \u2014 Alternative content types
|
|
2984
|
+
- \`--dry-run\` \u2014 Preview without executing
|
|
2919
2985
|
|
|
2920
|
-
|
|
2986
|
+
**Do NOT** pass path or query parameters in \`-d\`. Use the correct flags.
|
|
2921
2987
|
|
|
2922
|
-
|
|
2923
|
-
{
|
|
2924
|
-
"id": "parallelLookups",
|
|
2925
|
-
"name": "Look up in parallel",
|
|
2926
|
-
"type": "parallel",
|
|
2927
|
-
"parallel": {
|
|
2928
|
-
"maxConcurrency": 5,
|
|
2929
|
-
"steps": [
|
|
2930
|
-
{ "id": "getStripe", "name": "Get Stripe data", "type": "action", "action": { "...": "..." } },
|
|
2931
|
-
{ "id": "getHubspot", "name": "Get HubSpot data", "type": "action", "action": { "...": "..." } }
|
|
2932
|
-
]
|
|
2933
|
-
}
|
|
2934
|
-
}
|
|
2935
|
-
\`\`\`
|
|
2988
|
+
## Error Handling
|
|
2936
2989
|
|
|
2937
|
-
|
|
2990
|
+
All errors return JSON: \`{"error": "message"}\`. Check the \`error\` key.
|
|
2938
2991
|
|
|
2939
|
-
|
|
2940
|
-
{
|
|
2941
|
-
"id": "readConfig",
|
|
2942
|
-
"name": "Read config file",
|
|
2943
|
-
"type": "file-read",
|
|
2944
|
-
"fileRead": { "path": "./data/config.json", "parseJson": true }
|
|
2945
|
-
}
|
|
2946
|
-
\`\`\`
|
|
2992
|
+
## Notes
|
|
2947
2993
|
|
|
2948
|
-
|
|
2994
|
+
- Platform names are **kebab-case** (e.g., \`hub-spot\`)
|
|
2995
|
+
- JSON flags use single quotes around the JSON to avoid shell escaping
|
|
2996
|
+
- If search returns no results, try broader queries
|
|
2997
|
+
- Access control settings from \`one config\` may restrict execution
|
|
2998
|
+
`;
|
|
2999
|
+
var GUIDE_FLOWS = `# One Flows \u2014 Reference
|
|
2949
3000
|
|
|
2950
|
-
|
|
2951
|
-
{
|
|
2952
|
-
"id": "writeResults",
|
|
2953
|
-
"name": "Save results",
|
|
2954
|
-
"type": "file-write",
|
|
2955
|
-
"fileWrite": {
|
|
2956
|
-
"path": "./output/results.json",
|
|
2957
|
-
"content": "$.steps.transform.output",
|
|
2958
|
-
"append": false
|
|
2959
|
-
}
|
|
2960
|
-
}
|
|
2961
|
-
\`\`\`
|
|
3001
|
+
## Overview
|
|
2962
3002
|
|
|
2963
|
-
|
|
3003
|
+
Workflows are JSON files at \`.one/flows/<key>.flow.json\` that chain actions across platforms.
|
|
2964
3004
|
|
|
2965
|
-
|
|
3005
|
+
## Commands
|
|
2966
3006
|
|
|
2967
|
-
\`\`\`
|
|
2968
|
-
|
|
2969
|
-
|
|
2970
|
-
|
|
2971
|
-
|
|
2972
|
-
|
|
2973
|
-
|
|
2974
|
-
|
|
2975
|
-
|
|
2976
|
-
{
|
|
2977
|
-
"id": "fetchPage",
|
|
2978
|
-
"name": "Fetch next page",
|
|
2979
|
-
"type": "action",
|
|
2980
|
-
"action": {
|
|
2981
|
-
"platform": "gmail",
|
|
2982
|
-
"actionId": "GMAIL_LIST_MESSAGES_ACTION_ID",
|
|
2983
|
-
"connectionKey": "$.input.gmailKey",
|
|
2984
|
-
"queryParams": {
|
|
2985
|
-
"pageToken": "$.steps.paginate.output.lastResult.nextPageToken"
|
|
2986
|
-
}
|
|
2987
|
-
}
|
|
2988
|
-
}
|
|
2989
|
-
]
|
|
2990
|
-
}
|
|
2991
|
-
}
|
|
3007
|
+
\`\`\`bash
|
|
3008
|
+
one --agent flow create <key> --definition '<json>' # Create
|
|
3009
|
+
one --agent flow list # List
|
|
3010
|
+
one --agent flow validate <key> # Validate
|
|
3011
|
+
one --agent flow execute <key> -i name=value # Execute
|
|
3012
|
+
one --agent flow execute <key> --dry-run --mock # Test with mock data
|
|
3013
|
+
one --agent flow execute <key> --allow-bash # Enable bash steps
|
|
3014
|
+
one --agent flow runs [flowKey] # List past runs
|
|
3015
|
+
one --agent flow resume <runId> # Resume failed run
|
|
2992
3016
|
\`\`\`
|
|
2993
3017
|
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
|
|
3018
|
+
## Building a Workflow
|
|
3019
|
+
|
|
3020
|
+
1. **Design first** \u2014 clarify the end goal, map the full value chain, identify where AI analysis is needed
|
|
3021
|
+
2. **Discover connections** \u2014 \`one --agent connection list\`
|
|
3022
|
+
3. **Get knowledge** for every action \u2014 \`one --agent actions knowledge <platform> <actionId>\`
|
|
3023
|
+
4. **Construct JSON** \u2014 declare inputs, wire steps with selectors
|
|
3024
|
+
5. **Validate** \u2014 \`one --agent flow validate <key>\`
|
|
3025
|
+
6. **Execute** \u2014 \`one --agent flow execute <key> -i param=value\`
|
|
3026
|
+
|
|
3027
|
+
## Step Types
|
|
3028
|
+
|
|
3029
|
+
| Type | Purpose |
|
|
3030
|
+
|------|---------|
|
|
3031
|
+
| \`action\` | Execute a platform API action |
|
|
3032
|
+
| \`transform\` | Single JS expression (implicit return) |
|
|
3033
|
+
| \`code\` | Multi-line async JS (explicit return) |
|
|
3034
|
+
| \`condition\` | If/then/else branching |
|
|
3035
|
+
| \`loop\` | Iterate over array with optional concurrency |
|
|
3036
|
+
| \`parallel\` | Run steps concurrently |
|
|
3037
|
+
| \`file-read\` | Read file (optional JSON parse) |
|
|
3038
|
+
| \`file-write\` | Write/append to file |
|
|
3039
|
+
| \`while\` | Do-while loop with condition |
|
|
3040
|
+
| \`flow\` | Execute a sub-flow |
|
|
3041
|
+
| \`paginate\` | Auto-paginate API results |
|
|
3042
|
+
| \`bash\` | Shell command (requires \`--allow-bash\`) |
|
|
3043
|
+
|
|
3044
|
+
## Selectors
|
|
2999
3045
|
|
|
3000
|
-
|
|
3001
|
-
|
|
3002
|
-
|
|
3046
|
+
| Pattern | Resolves To |
|
|
3047
|
+
|---------|-------------|
|
|
3048
|
+
| \`$.input.paramName\` | Input value |
|
|
3049
|
+
| \`$.steps.stepId.response\` | Full API response |
|
|
3050
|
+
| \`$.steps.stepId.response.data[0].email\` | Nested field |
|
|
3051
|
+
| \`$.steps.stepId.response.data[*].id\` | Wildcard array map |
|
|
3052
|
+
| \`$.env.MY_VAR\` | Environment variable |
|
|
3053
|
+
| \`$.loop.item\` / \`$.loop.i\` | Loop iteration |
|
|
3054
|
+
| \`"Hello {{$.steps.getUser.response.name}}"\` | String interpolation |
|
|
3003
3055
|
|
|
3004
|
-
|
|
3056
|
+
## Error Handling
|
|
3005
3057
|
|
|
3006
3058
|
\`\`\`json
|
|
3007
|
-
{
|
|
3008
|
-
"id": "processCustomer",
|
|
3009
|
-
"name": "Run customer enrichment flow",
|
|
3010
|
-
"type": "flow",
|
|
3011
|
-
"flow": {
|
|
3012
|
-
"key": "enrich-customer",
|
|
3013
|
-
"inputs": {
|
|
3014
|
-
"email": "$.steps.getCustomer.response.email",
|
|
3015
|
-
"connectionKey": "$.input.hubspotConnectionKey"
|
|
3016
|
-
}
|
|
3017
|
-
}
|
|
3018
|
-
}
|
|
3059
|
+
{"onError": {"strategy": "retry", "retries": 3, "retryDelayMs": 1000}}
|
|
3019
3060
|
\`\`\`
|
|
3020
3061
|
|
|
3021
|
-
|
|
3022
|
-
|---|---|---|
|
|
3023
|
-
| \`key\` | string | Flow key or path (supports selectors) |
|
|
3024
|
-
| \`inputs\` | object | Input values mapped to the sub-flow's declared inputs (supports selectors) |
|
|
3062
|
+
Strategies: \`fail\` (default), \`continue\`, \`retry\`, \`fallback\`
|
|
3025
3063
|
|
|
3026
|
-
|
|
3064
|
+
Conditional execution: \`"if": "$.steps.prev.response.data.length > 0"\`
|
|
3027
3065
|
|
|
3028
|
-
|
|
3066
|
+
## AI-Augmented Pattern
|
|
3029
3067
|
|
|
3030
|
-
|
|
3031
|
-
{
|
|
3032
|
-
"id": "allMessages",
|
|
3033
|
-
"name": "Fetch all Gmail messages",
|
|
3034
|
-
"type": "paginate",
|
|
3035
|
-
"paginate": {
|
|
3036
|
-
"action": {
|
|
3037
|
-
"platform": "gmail",
|
|
3038
|
-
"actionId": "GMAIL_LIST_MESSAGES_ACTION_ID",
|
|
3039
|
-
"connectionKey": "$.input.gmailKey",
|
|
3040
|
-
"queryParams": { "maxResults": 100 }
|
|
3041
|
-
},
|
|
3042
|
-
"pageTokenField": "nextPageToken",
|
|
3043
|
-
"resultsField": "messages",
|
|
3044
|
-
"inputTokenParam": "queryParams.pageToken",
|
|
3045
|
-
"maxPages": 10
|
|
3046
|
-
}
|
|
3047
|
-
}
|
|
3048
|
-
\`\`\`
|
|
3068
|
+
For workflows that need analysis/summarization, use the file-write \u2192 bash \u2192 code pattern:
|
|
3049
3069
|
|
|
3050
|
-
|
|
3051
|
-
|
|
3052
|
-
|
|
3053
|
-
| \`pageTokenField\` | string | Dot-path in the API response to the next page token |
|
|
3054
|
-
| \`resultsField\` | string | Dot-path in the API response to the results array |
|
|
3055
|
-
| \`inputTokenParam\` | string | Dot-path in the action config where the page token is injected |
|
|
3056
|
-
| \`maxPages\` | number | Maximum pages to fetch, default: 10 |
|
|
3070
|
+
1. \`file-write\` \u2014 save data to temp file
|
|
3071
|
+
2. \`bash\` \u2014 \`claude --print\` analyzes it (\`parseJson: true\`, \`timeout: 180000\`)
|
|
3072
|
+
3. \`code\` \u2014 parse and structure the output
|
|
3057
3073
|
|
|
3058
|
-
|
|
3074
|
+
Set timeout to at least 180000ms (3 min). Run Claude-heavy flows sequentially, not in parallel.
|
|
3059
3075
|
|
|
3060
|
-
|
|
3076
|
+
## Notes
|
|
3061
3077
|
|
|
3062
|
-
|
|
3063
|
-
|
|
3064
|
-
|
|
3065
|
-
|
|
3066
|
-
|
|
3067
|
-
|
|
3068
|
-
|
|
3069
|
-
"timeout": 120000,
|
|
3070
|
-
"parseJson": true
|
|
3071
|
-
}
|
|
3072
|
-
}
|
|
3073
|
-
\`\`\`
|
|
3074
|
-
|
|
3075
|
-
| Field | Type | Description |
|
|
3076
|
-
|---|---|---|
|
|
3077
|
-
| \`command\` | string | Shell command to execute (supports selectors and interpolation) |
|
|
3078
|
-
| \`timeout\` | number | Timeout in ms, default: 30000 |
|
|
3079
|
-
| \`parseJson\` | boolean | Parse stdout as JSON, default: false |
|
|
3080
|
-
| \`cwd\` | string | Working directory (supports selectors) |
|
|
3081
|
-
| \`env\` | object | Additional environment variables |
|
|
3078
|
+
- Connection keys are **inputs**, not hardcoded
|
|
3079
|
+
- Action IDs in examples are placeholders \u2014 always use \`actions search\`
|
|
3080
|
+
- Code steps allow \`crypto\`, \`buffer\`, \`url\`, \`path\` \u2014 \`fs\`, \`http\`, \`child_process\` are blocked
|
|
3081
|
+
- Bash steps require \`--allow-bash\` flag
|
|
3082
|
+
- State is persisted after every step \u2014 resume picks up where it left off
|
|
3083
|
+
`;
|
|
3084
|
+
var GUIDE_RELAY = `# One Relay \u2014 Reference
|
|
3082
3085
|
|
|
3083
|
-
|
|
3086
|
+
## Overview
|
|
3084
3087
|
|
|
3085
|
-
|
|
3088
|
+
Webhook relay receives events from platforms (Stripe, GitHub, Airtable, Attio, Google Calendar) and forwards them to any connected platform using passthrough actions with Handlebars templates.
|
|
3086
3089
|
|
|
3087
|
-
|
|
3090
|
+
## Commands
|
|
3088
3091
|
|
|
3089
|
-
\`\`\`
|
|
3090
|
-
|
|
3091
|
-
|
|
3092
|
-
|
|
3093
|
-
|
|
3094
|
-
|
|
3095
|
-
|
|
3096
|
-
|
|
3097
|
-
|
|
3098
|
-
|
|
3099
|
-
|
|
3100
|
-
}
|
|
3092
|
+
\`\`\`bash
|
|
3093
|
+
one --agent relay event-types <platform> # List available events
|
|
3094
|
+
one --agent relay create --connection-key <key> --create-webhook --event-filters '["event.type"]'
|
|
3095
|
+
one --agent relay activate <id> --actions '<json>' # Add forwarding actions
|
|
3096
|
+
one --agent relay list # List endpoints
|
|
3097
|
+
one --agent relay get <id> # Get endpoint details
|
|
3098
|
+
one --agent relay update <id> --actions '<json>' # Update endpoint
|
|
3099
|
+
one --agent relay delete <id> # Delete endpoint
|
|
3100
|
+
one --agent relay events --platform <p> # List received events
|
|
3101
|
+
one --agent relay event <id> # Get event with payload
|
|
3102
|
+
one --agent relay deliveries --endpoint-id <id> # Check delivery status
|
|
3101
3103
|
\`\`\`
|
|
3102
3104
|
|
|
3103
|
-
|
|
3104
|
-
|---|---|
|
|
3105
|
-
| \`fail\` | Stop the flow immediately (default) |
|
|
3106
|
-
| \`continue\` | Mark step as failed, continue to next step |
|
|
3107
|
-
| \`retry\` | Retry up to N times with delay |
|
|
3108
|
-
| \`fallback\` | On failure, execute a different step |
|
|
3105
|
+
## Building a Relay
|
|
3109
3106
|
|
|
3110
|
-
|
|
3107
|
+
1. **Discover connections** \u2014 identify source and destination platforms
|
|
3108
|
+
2. **Get event types** \u2014 \`one --agent relay event-types <platform>\`
|
|
3109
|
+
3. **Get source knowledge** \u2014 understand the incoming webhook payload shape (\`{{payload.*}}\` paths)
|
|
3110
|
+
4. **Get destination knowledge** \u2014 understand the outgoing API body shape
|
|
3111
|
+
5. **Create endpoint** \u2014 with \`--create-webhook\` and \`--event-filters\`
|
|
3112
|
+
6. **Activate** \u2014 with passthrough action mapping source fields to destination fields
|
|
3111
3113
|
|
|
3112
|
-
|
|
3114
|
+
## Template Context
|
|
3113
3115
|
|
|
3114
|
-
|
|
3115
|
-
|
|
3116
|
-
|
|
3117
|
-
|
|
3118
|
-
|
|
3119
|
-
|
|
3120
|
-
|
|
3121
|
-
}
|
|
3122
|
-
|
|
3123
|
-
|
|
3124
|
-
## 7. Updating Existing Workflows
|
|
3125
|
-
|
|
3126
|
-
To modify an existing workflow:
|
|
3116
|
+
| Variable | Description |
|
|
3117
|
+
|----------|-------------|
|
|
3118
|
+
| \`{{relayEventId}}\` | Unique event UUID |
|
|
3119
|
+
| \`{{platform}}\` | Source platform (e.g., \`stripe\`) |
|
|
3120
|
+
| \`{{eventType}}\` | Event type (e.g., \`customer.created\`) |
|
|
3121
|
+
| \`{{payload}}\` | Full incoming webhook body |
|
|
3122
|
+
| \`{{timestamp}}\` | When the event was received |
|
|
3123
|
+
| \`{{connectionId}}\` | Source connection UUID |
|
|
3124
|
+
| \`{{json payload}}\` | Embed full payload as JSON string |
|
|
3127
3125
|
|
|
3128
|
-
|
|
3129
|
-
2. Understand its current structure
|
|
3130
|
-
3. Use \`one --agent actions knowledge <platform> <actionId>\` for any new actions
|
|
3131
|
-
4. Modify the JSON (add/remove/update steps, change data mappings, add inputs)
|
|
3132
|
-
5. Write back the updated workflow file
|
|
3133
|
-
6. Validate: \`one --agent flow validate <key>\`
|
|
3126
|
+
Access nested fields: \`{{payload.data.object.email}}\`
|
|
3134
3127
|
|
|
3135
|
-
##
|
|
3136
|
-
|
|
3137
|
-
### Example 1: Simple 2-step workflow \u2014 Search Stripe customer, send Gmail email
|
|
3128
|
+
## Action Types
|
|
3138
3129
|
|
|
3130
|
+
**passthrough** (primary) \u2014 forward to another platform's API:
|
|
3139
3131
|
\`\`\`json
|
|
3140
3132
|
{
|
|
3141
|
-
"
|
|
3142
|
-
"
|
|
3143
|
-
"
|
|
3144
|
-
"
|
|
3145
|
-
"
|
|
3146
|
-
"stripeConnectionKey": {
|
|
3147
|
-
"type": "string",
|
|
3148
|
-
"required": true,
|
|
3149
|
-
"description": "Stripe connection key",
|
|
3150
|
-
"connection": { "platform": "stripe" }
|
|
3151
|
-
},
|
|
3152
|
-
"gmailConnectionKey": {
|
|
3153
|
-
"type": "string",
|
|
3154
|
-
"required": true,
|
|
3155
|
-
"description": "Gmail connection key",
|
|
3156
|
-
"connection": { "platform": "gmail" }
|
|
3157
|
-
},
|
|
3158
|
-
"customerEmail": {
|
|
3159
|
-
"type": "string",
|
|
3160
|
-
"required": true,
|
|
3161
|
-
"description": "Customer email to look up"
|
|
3162
|
-
}
|
|
3163
|
-
},
|
|
3164
|
-
"steps": [
|
|
3165
|
-
{
|
|
3166
|
-
"id": "findCustomer",
|
|
3167
|
-
"name": "Search for customer in Stripe",
|
|
3168
|
-
"type": "action",
|
|
3169
|
-
"action": {
|
|
3170
|
-
"platform": "stripe",
|
|
3171
|
-
"actionId": "STRIPE_SEARCH_CUSTOMERS_ACTION_ID",
|
|
3172
|
-
"connectionKey": "$.input.stripeConnectionKey",
|
|
3173
|
-
"data": {
|
|
3174
|
-
"query": "email:'{{$.input.customerEmail}}'"
|
|
3175
|
-
}
|
|
3176
|
-
}
|
|
3177
|
-
},
|
|
3178
|
-
{
|
|
3179
|
-
"id": "sendWelcome",
|
|
3180
|
-
"name": "Send welcome email via Gmail",
|
|
3181
|
-
"type": "action",
|
|
3182
|
-
"if": "$.steps.findCustomer.response.data && $.steps.findCustomer.response.data.length > 0",
|
|
3183
|
-
"action": {
|
|
3184
|
-
"platform": "gmail",
|
|
3185
|
-
"actionId": "GMAIL_SEND_EMAIL_ACTION_ID",
|
|
3186
|
-
"connectionKey": "$.input.gmailConnectionKey",
|
|
3187
|
-
"data": {
|
|
3188
|
-
"to": "{{$.input.customerEmail}}",
|
|
3189
|
-
"subject": "Welcome, {{$.steps.findCustomer.response.data[0].name}}!",
|
|
3190
|
-
"body": "Thank you for being a customer. We're glad to have you!"
|
|
3191
|
-
}
|
|
3192
|
-
}
|
|
3193
|
-
}
|
|
3194
|
-
]
|
|
3133
|
+
"type": "passthrough",
|
|
3134
|
+
"actionId": "<action-id>",
|
|
3135
|
+
"connectionKey": "<dest-connection-key>",
|
|
3136
|
+
"body": { "channel": "#alerts", "text": "New customer: {{payload.data.object.name}}" },
|
|
3137
|
+
"eventFilters": ["customer.created"]
|
|
3195
3138
|
}
|
|
3196
3139
|
\`\`\`
|
|
3197
3140
|
|
|
3198
|
-
|
|
3199
|
-
|
|
3141
|
+
**url** \u2014 forward raw event to a URL:
|
|
3200
3142
|
\`\`\`json
|
|
3201
|
-
{
|
|
3202
|
-
"key": "sync-hubspot-contact",
|
|
3203
|
-
"name": "Sync Contact to HubSpot",
|
|
3204
|
-
"description": "Check if a contact exists in HubSpot, create if new or update if existing",
|
|
3205
|
-
"version": "1",
|
|
3206
|
-
"inputs": {
|
|
3207
|
-
"hubspotConnectionKey": {
|
|
3208
|
-
"type": "string",
|
|
3209
|
-
"required": true,
|
|
3210
|
-
"connection": { "platform": "hub-spot" }
|
|
3211
|
-
},
|
|
3212
|
-
"email": { "type": "string", "required": true },
|
|
3213
|
-
"firstName": { "type": "string", "required": true },
|
|
3214
|
-
"lastName": { "type": "string", "required": true }
|
|
3215
|
-
},
|
|
3216
|
-
"steps": [
|
|
3217
|
-
{
|
|
3218
|
-
"id": "searchContact",
|
|
3219
|
-
"name": "Search for existing contact",
|
|
3220
|
-
"type": "action",
|
|
3221
|
-
"action": {
|
|
3222
|
-
"platform": "hub-spot",
|
|
3223
|
-
"actionId": "HUBSPOT_SEARCH_CONTACTS_ACTION_ID",
|
|
3224
|
-
"connectionKey": "$.input.hubspotConnectionKey",
|
|
3225
|
-
"data": {
|
|
3226
|
-
"filterGroups": [{ "filters": [{ "propertyName": "email", "operator": "EQ", "value": "$.input.email" }] }]
|
|
3227
|
-
}
|
|
3228
|
-
}
|
|
3229
|
-
},
|
|
3230
|
-
{
|
|
3231
|
-
"id": "createOrUpdate",
|
|
3232
|
-
"name": "Create or update contact",
|
|
3233
|
-
"type": "condition",
|
|
3234
|
-
"condition": {
|
|
3235
|
-
"expression": "$.steps.searchContact.response.total > 0",
|
|
3236
|
-
"then": [
|
|
3237
|
-
{
|
|
3238
|
-
"id": "updateContact",
|
|
3239
|
-
"name": "Update existing contact",
|
|
3240
|
-
"type": "action",
|
|
3241
|
-
"action": {
|
|
3242
|
-
"platform": "hub-spot",
|
|
3243
|
-
"actionId": "HUBSPOT_UPDATE_CONTACT_ACTION_ID",
|
|
3244
|
-
"connectionKey": "$.input.hubspotConnectionKey",
|
|
3245
|
-
"pathVars": { "contactId": "$.steps.searchContact.response.results[0].id" },
|
|
3246
|
-
"data": {
|
|
3247
|
-
"properties": { "firstname": "$.input.firstName", "lastname": "$.input.lastName" }
|
|
3248
|
-
}
|
|
3249
|
-
}
|
|
3250
|
-
}
|
|
3251
|
-
],
|
|
3252
|
-
"else": [
|
|
3253
|
-
{
|
|
3254
|
-
"id": "createContact",
|
|
3255
|
-
"name": "Create new contact",
|
|
3256
|
-
"type": "action",
|
|
3257
|
-
"action": {
|
|
3258
|
-
"platform": "hub-spot",
|
|
3259
|
-
"actionId": "HUBSPOT_CREATE_CONTACT_ACTION_ID",
|
|
3260
|
-
"connectionKey": "$.input.hubspotConnectionKey",
|
|
3261
|
-
"data": {
|
|
3262
|
-
"properties": { "email": "$.input.email", "firstname": "$.input.firstName", "lastname": "$.input.lastName" }
|
|
3263
|
-
}
|
|
3264
|
-
}
|
|
3265
|
-
}
|
|
3266
|
-
]
|
|
3267
|
-
}
|
|
3268
|
-
}
|
|
3269
|
-
]
|
|
3270
|
-
}
|
|
3143
|
+
{"type": "url", "url": "https://your-app.com/webhook", "eventFilters": ["customer.created"]}
|
|
3271
3144
|
\`\`\`
|
|
3272
3145
|
|
|
3273
|
-
|
|
3274
|
-
|
|
3146
|
+
**agent** \u2014 send to an agent:
|
|
3275
3147
|
\`\`\`json
|
|
3276
|
-
{
|
|
3277
|
-
"key": "shopify-to-invoices",
|
|
3278
|
-
"name": "Shopify Orders to Invoices",
|
|
3279
|
-
"description": "Fetch recent Shopify orders and create an invoice for each",
|
|
3280
|
-
"version": "1",
|
|
3281
|
-
"inputs": {
|
|
3282
|
-
"shopifyConnectionKey": {
|
|
3283
|
-
"type": "string",
|
|
3284
|
-
"required": true,
|
|
3285
|
-
"connection": { "platform": "shopify" }
|
|
3286
|
-
},
|
|
3287
|
-
"qbConnectionKey": {
|
|
3288
|
-
"type": "string",
|
|
3289
|
-
"required": true,
|
|
3290
|
-
"connection": { "platform": "quick-books" }
|
|
3291
|
-
}
|
|
3292
|
-
},
|
|
3293
|
-
"steps": [
|
|
3294
|
-
{
|
|
3295
|
-
"id": "listOrders",
|
|
3296
|
-
"name": "List recent Shopify orders",
|
|
3297
|
-
"type": "action",
|
|
3298
|
-
"action": {
|
|
3299
|
-
"platform": "shopify",
|
|
3300
|
-
"actionId": "SHOPIFY_LIST_ORDERS_ACTION_ID",
|
|
3301
|
-
"connectionKey": "$.input.shopifyConnectionKey",
|
|
3302
|
-
"queryParams": { "status": "any", "limit": "50" }
|
|
3303
|
-
}
|
|
3304
|
-
},
|
|
3305
|
-
{
|
|
3306
|
-
"id": "createInvoices",
|
|
3307
|
-
"name": "Create invoice for each order",
|
|
3308
|
-
"type": "loop",
|
|
3309
|
-
"loop": {
|
|
3310
|
-
"over": "$.steps.listOrders.response.orders",
|
|
3311
|
-
"as": "order",
|
|
3312
|
-
"indexAs": "i",
|
|
3313
|
-
"steps": [
|
|
3314
|
-
{
|
|
3315
|
-
"id": "createInvoice",
|
|
3316
|
-
"name": "Create QuickBooks invoice",
|
|
3317
|
-
"type": "action",
|
|
3318
|
-
"onError": { "strategy": "continue" },
|
|
3319
|
-
"action": {
|
|
3320
|
-
"platform": "quick-books",
|
|
3321
|
-
"actionId": "QB_CREATE_INVOICE_ACTION_ID",
|
|
3322
|
-
"connectionKey": "$.input.qbConnectionKey",
|
|
3323
|
-
"data": {
|
|
3324
|
-
"Line": [
|
|
3325
|
-
{
|
|
3326
|
-
"Amount": "$.loop.order.total_price",
|
|
3327
|
-
"Description": "Shopify Order #{{$.loop.order.order_number}}"
|
|
3328
|
-
}
|
|
3329
|
-
]
|
|
3330
|
-
}
|
|
3331
|
-
}
|
|
3332
|
-
}
|
|
3333
|
-
]
|
|
3334
|
-
}
|
|
3335
|
-
},
|
|
3336
|
-
{
|
|
3337
|
-
"id": "summary",
|
|
3338
|
-
"name": "Generate summary",
|
|
3339
|
-
"type": "transform",
|
|
3340
|
-
"transform": {
|
|
3341
|
-
"expression": "({ totalOrders: $.steps.listOrders.response.orders.length, processed: $.steps.createInvoices.output.length })"
|
|
3342
|
-
}
|
|
3343
|
-
}
|
|
3344
|
-
]
|
|
3345
|
-
}
|
|
3148
|
+
{"type": "agent", "agentId": "<uuid>", "eventFilters": ["customer.created"]}
|
|
3346
3149
|
\`\`\`
|
|
3347
3150
|
|
|
3348
|
-
##
|
|
3349
|
-
|
|
3350
|
-
\`\`\`bash
|
|
3351
|
-
# Create a workflow
|
|
3352
|
-
one --agent flow create <key> --definition '<json>'
|
|
3353
|
-
|
|
3354
|
-
# List all workflows
|
|
3355
|
-
one --agent flow list
|
|
3356
|
-
|
|
3357
|
-
# Validate a workflow
|
|
3358
|
-
one --agent flow validate <key>
|
|
3359
|
-
|
|
3360
|
-
# Execute a workflow
|
|
3361
|
-
one --agent flow execute <key> -i connectionKey=value -i param=value
|
|
3362
|
-
|
|
3363
|
-
# Execute with dry run (validate only)
|
|
3364
|
-
one --agent flow execute <key> --dry-run -i connectionKey=value
|
|
3151
|
+
## Supported Source Platforms
|
|
3365
3152
|
|
|
3366
|
-
|
|
3367
|
-
one --agent flow execute <key> --dry-run --mock -i connectionKey=value
|
|
3153
|
+
Airtable, Attio, GitHub, Google Calendar, Stripe
|
|
3368
3154
|
|
|
3369
|
-
|
|
3370
|
-
one --agent flow execute <key> --allow-bash -i connectionKey=value
|
|
3155
|
+
Any connected platform can be a destination via passthrough actions.
|
|
3371
3156
|
|
|
3372
|
-
|
|
3373
|
-
one --agent flow execute <key> -v -i connectionKey=value
|
|
3374
|
-
|
|
3375
|
-
# List workflow runs
|
|
3376
|
-
one --agent flow runs [flowKey]
|
|
3377
|
-
|
|
3378
|
-
# Resume a paused/failed run
|
|
3379
|
-
one --agent flow resume <runId>
|
|
3380
|
-
\`\`\`
|
|
3157
|
+
## Debugging
|
|
3381
3158
|
|
|
3382
|
-
|
|
3383
|
-
|
|
3384
|
-
-
|
|
3385
|
-
|
|
3386
|
-
- Platform names are **kebab-case** (e.g., \`hub-spot\`, not \`HubSpot\`)
|
|
3387
|
-
- Connection keys are **inputs**, not hardcoded \u2014 makes workflows portable and shareable
|
|
3388
|
-
- Use \`$.input.*\` for input values, \`$.steps.*\` for step results
|
|
3389
|
-
- Action IDs in examples (like \`STRIPE_SEARCH_CUSTOMERS_ACTION_ID\`) are placeholders \u2014 always use \`one actions search\` to find the real IDs
|
|
3390
|
-
- **Parallel step outputs** are accessible both by index (\`$.steps.parallelStep.output[0]\`) and by substep ID (\`$.steps.substepId.response\`)
|
|
3391
|
-
- **Loop step outputs** include iteration details via \`$.steps.myLoop.response.iterations[0].innerStepId.response\`
|
|
3392
|
-
- **Code steps** support \`await require('crypto')\`, \`await require('buffer')\`, \`await require('url')\`, \`await require('path')\` \u2014 \`fs\`, \`http\`, \`child_process\`, etc. are blocked
|
|
3393
|
-
- **Bash steps** require \`--allow-bash\` flag for security
|
|
3394
|
-
- **State is persisted** after every step completion \u2014 resume picks up where it left off
|
|
3159
|
+
1. \`relay get <id>\` \u2014 verify endpoint is active with actions configured
|
|
3160
|
+
2. \`relay events --platform <p>\` \u2014 check events are arriving
|
|
3161
|
+
3. \`relay deliveries --event-id <id>\` \u2014 check delivery status and errors
|
|
3162
|
+
4. \`relay event <id>\` \u2014 inspect full payload to verify template paths
|
|
3395
3163
|
`;
|
|
3396
3164
|
var TOPICS = [
|
|
3397
|
-
{ topic: "overview", description: "Setup,
|
|
3165
|
+
{ topic: "overview", description: "Setup, features, and quick start for each" },
|
|
3398
3166
|
{ topic: "actions", description: "Search, read docs, and execute platform actions" },
|
|
3399
3167
|
{ topic: "flows", description: "Build and execute multi-step workflows" },
|
|
3168
|
+
{ topic: "relay", description: "Receive webhooks and forward to other platforms" },
|
|
3400
3169
|
{ topic: "all", description: "Complete guide (all topics combined)" }
|
|
3401
3170
|
];
|
|
3402
3171
|
function getGuideContent(topic) {
|
|
@@ -3407,10 +3176,12 @@ function getGuideContent(topic) {
|
|
|
3407
3176
|
return { title: "One CLI \u2014 Agent Guide: Actions", content: GUIDE_ACTIONS };
|
|
3408
3177
|
case "flows":
|
|
3409
3178
|
return { title: "One CLI \u2014 Agent Guide: Workflows", content: GUIDE_FLOWS };
|
|
3179
|
+
case "relay":
|
|
3180
|
+
return { title: "One CLI \u2014 Agent Guide: Relay", content: GUIDE_RELAY };
|
|
3410
3181
|
case "all":
|
|
3411
3182
|
return {
|
|
3412
3183
|
title: "One CLI \u2014 Agent Guide: Complete",
|
|
3413
|
-
content: [GUIDE_OVERVIEW, GUIDE_ACTIONS, GUIDE_FLOWS].join("\n---\n\n")
|
|
3184
|
+
content: [GUIDE_OVERVIEW, GUIDE_ACTIONS, GUIDE_FLOWS, GUIDE_RELAY].join("\n---\n\n")
|
|
3414
3185
|
};
|
|
3415
3186
|
}
|
|
3416
3187
|
}
|
|
@@ -3419,7 +3190,7 @@ function getAvailableTopics() {
|
|
|
3419
3190
|
}
|
|
3420
3191
|
|
|
3421
3192
|
// src/commands/guide.ts
|
|
3422
|
-
var VALID_TOPICS = ["overview", "actions", "flows", "all"];
|
|
3193
|
+
var VALID_TOPICS = ["overview", "actions", "flows", "relay", "all"];
|
|
3423
3194
|
async function guideCommand(topic = "all") {
|
|
3424
3195
|
if (!VALID_TOPICS.includes(topic)) {
|
|
3425
3196
|
error(
|
|
@@ -3432,14 +3203,14 @@ async function guideCommand(topic = "all") {
|
|
|
3432
3203
|
json({ topic, title, content, availableTopics });
|
|
3433
3204
|
return;
|
|
3434
3205
|
}
|
|
3435
|
-
intro2(
|
|
3206
|
+
intro2(pc9.bgCyan(pc9.black(" One Guide ")));
|
|
3436
3207
|
console.log();
|
|
3437
3208
|
console.log(content);
|
|
3438
|
-
console.log(
|
|
3209
|
+
console.log(pc9.dim("\u2500".repeat(60)));
|
|
3439
3210
|
console.log(
|
|
3440
|
-
|
|
3211
|
+
pc9.dim("Available topics: ") + availableTopics.map((t) => pc9.cyan(t.topic)).join(", ")
|
|
3441
3212
|
);
|
|
3442
|
-
console.log(
|
|
3213
|
+
console.log(pc9.dim(`Run ${pc9.cyan("one guide <topic>")} for a specific section.`));
|
|
3443
3214
|
}
|
|
3444
3215
|
|
|
3445
3216
|
// src/lib/platform-meta.ts
|
|
@@ -3587,18 +3358,30 @@ The \`--agent\` flag gives structured JSON output. Always include it right
|
|
|
3587
3358
|
after \`one\`:
|
|
3588
3359
|
one --agent <command>
|
|
3589
3360
|
|
|
3361
|
+
### IMPORTANT: Learn before you use
|
|
3362
|
+
Before using any feature (actions, flows, relay), you MUST read the
|
|
3363
|
+
corresponding skill documentation first. The skills are bundled with
|
|
3364
|
+
the CLI and teach you the correct workflow, required steps, and
|
|
3365
|
+
common mistakes to avoid. Never guess \u2014 read the skill, then act.
|
|
3366
|
+
|
|
3590
3367
|
### Quick reference:
|
|
3591
3368
|
- \`one --agent list\` \u2014 See connected platforms and connection keys
|
|
3592
3369
|
- \`one --agent actions search <platform> "<query>"\` \u2014 Find actions
|
|
3593
3370
|
- \`one --agent actions knowledge <platform> <actionId>\` \u2014 Read docs (REQUIRED before execute)
|
|
3594
3371
|
- \`one --agent actions execute <platform> <actionId> <connectionKey>\` \u2014 Execute action
|
|
3595
3372
|
- \`one --agent flow create\` \u2014 Build multi-step workflows
|
|
3373
|
+
- \`one --agent relay create\` \u2014 Set up webhook relay (receive events, forward to other platforms)
|
|
3596
3374
|
- \`one --agent guide\` \u2014 Full documentation
|
|
3597
3375
|
- \`one add <platform>\` \u2014 Connect a new platform (interactive, no --agent)
|
|
3598
3376
|
|
|
3599
3377
|
### Workflow: search -> knowledge -> execute
|
|
3600
3378
|
Always read the knowledge before executing. It tells you required parameters,
|
|
3601
3379
|
validation rules, and platform-specific details.
|
|
3380
|
+
|
|
3381
|
+
### Webhook Relay
|
|
3382
|
+
Use \`one relay\` to receive webhooks from platforms (Stripe, GitHub, etc.)
|
|
3383
|
+
and forward event data to other platforms using passthrough actions with
|
|
3384
|
+
Handlebars templates. No middleware needed.
|
|
3602
3385
|
\`\`\``);
|
|
3603
3386
|
sections.push(buildCurrentState(connections));
|
|
3604
3387
|
sections.push(`## How To Use the CLI
|
|
@@ -3624,6 +3407,17 @@ The \`--agent\` flag goes right after \`one\`, before the subcommand.
|
|
|
3624
3407
|
Use \`one flow create\` to build JSON workflows that chain actions across
|
|
3625
3408
|
platforms with conditions, loops, parallel execution, and transforms.
|
|
3626
3409
|
|
|
3410
|
+
### Webhook Relay:
|
|
3411
|
+
Use \`one relay create\` to receive webhooks from platforms (Stripe, GitHub,
|
|
3412
|
+
Airtable, Attio, Google Calendar) and forward event data to any connected
|
|
3413
|
+
platform using passthrough actions with Handlebars templates.
|
|
3414
|
+
|
|
3415
|
+
### IMPORTANT: Learn before you use
|
|
3416
|
+
Before using flows or relay, you MUST read the corresponding skill
|
|
3417
|
+
documentation first. The skills teach you the correct workflow, template
|
|
3418
|
+
syntax, required steps, and common mistakes. Never guess \u2014 read the
|
|
3419
|
+
skill, then act.
|
|
3420
|
+
|
|
3627
3421
|
Run \`one --agent guide\` for the complete reference documentation with examples.`);
|
|
3628
3422
|
sections.push(`## What to tell the user
|
|
3629
3423
|
|
|
@@ -3849,6 +3643,14 @@ program.name("one").option("--agent", "Machine-readable JSON output (no colors,
|
|
|
3849
3643
|
one flow execute <key> Execute a workflow
|
|
3850
3644
|
one flow validate <key> Validate a flow
|
|
3851
3645
|
|
|
3646
|
+
Webhook Relay:
|
|
3647
|
+
one relay create Create a relay endpoint for a connection
|
|
3648
|
+
one relay list List relay endpoints
|
|
3649
|
+
one relay activate <id> Activate with passthrough actions
|
|
3650
|
+
one relay event-types <platform> List supported event types
|
|
3651
|
+
one relay events List received webhook events
|
|
3652
|
+
one relay deliveries List delivery attempts
|
|
3653
|
+
|
|
3852
3654
|
Example \u2014 send an email through Gmail:
|
|
3853
3655
|
$ one list
|
|
3854
3656
|
# Find: gmail operational live::gmail::default::abc123
|
|
@@ -3943,7 +3745,38 @@ flow.command("resume <runId>").description("Resume a paused or failed workflow r
|
|
|
3943
3745
|
flow.command("runs [flowKey]").description("List workflow runs (optionally filtered by flow key)").action(async (flowKey) => {
|
|
3944
3746
|
await flowRunsCommand(flowKey);
|
|
3945
3747
|
});
|
|
3946
|
-
program.command("
|
|
3748
|
+
var relay = program.command("relay").alias("r").description("Receive webhooks from platforms and relay them via passthrough actions");
|
|
3749
|
+
relay.command("create").description("Create a new relay endpoint for a connection").requiredOption("--connection-key <key>", "Connection key for the source platform").option("--description <desc>", "Description of the relay endpoint").option("--event-filters <json>", `JSON array of event types to filter (e.g. '["customer.created"]')`).option("--tags <json>", "JSON array of tags").option("--create-webhook", "Automatically register the webhook with the source platform").action(async (options) => {
|
|
3750
|
+
await relayCreateCommand(options);
|
|
3751
|
+
});
|
|
3752
|
+
relay.command("list").alias("ls").description("List all relay endpoints").option("--limit <n>", "Max results per page").option("--page <n>", "Page number").action(async (options) => {
|
|
3753
|
+
await relayListCommand(options);
|
|
3754
|
+
});
|
|
3755
|
+
relay.command("get <id>").description("Get details of a relay endpoint").action(async (id) => {
|
|
3756
|
+
await relayGetCommand(id);
|
|
3757
|
+
});
|
|
3758
|
+
relay.command("update <id>").description("Update a relay endpoint").option("--description <desc>", "Update description").option("--active", "Set active").option("--no-active", "Set inactive").option("--event-filters <json>", "JSON array of event types").option("--tags <json>", "JSON array of tags").option("--actions <json>", "JSON array of actions (url, passthrough, or agent)").action(async (id, options) => {
|
|
3759
|
+
await relayUpdateCommand(id, options);
|
|
3760
|
+
});
|
|
3761
|
+
relay.command("delete <id>").description("Delete a relay endpoint").action(async (id) => {
|
|
3762
|
+
await relayDeleteCommand(id);
|
|
3763
|
+
});
|
|
3764
|
+
relay.command("activate <id>").description("Activate a relay endpoint with forwarding actions").requiredOption("--actions <json>", "JSON array of actions (url, passthrough, or agent)").option("--webhook-secret <secret>", "Webhook signing secret for signature verification").action(async (id, options) => {
|
|
3765
|
+
await relayActivateCommand(id, options);
|
|
3766
|
+
});
|
|
3767
|
+
relay.command("events").description("List received webhook events").option("--limit <n>", "Max results per page").option("--page <n>", "Page number").option("--platform <platform>", "Filter by platform").option("--event-type <type>", "Filter by event type").option("--after <iso>", "Events after this timestamp").option("--before <iso>", "Events before this timestamp").action(async (options) => {
|
|
3768
|
+
await relayEventsCommand(options);
|
|
3769
|
+
});
|
|
3770
|
+
relay.command("event <id>").description("Get details of a specific webhook event").action(async (id) => {
|
|
3771
|
+
await relayEventGetCommand(id);
|
|
3772
|
+
});
|
|
3773
|
+
relay.command("deliveries").description("List delivery attempts for an endpoint or event").option("--endpoint-id <id>", "Relay endpoint ID").option("--event-id <id>", "Relay event ID").action(async (options) => {
|
|
3774
|
+
await relayDeliveriesCommand(options);
|
|
3775
|
+
});
|
|
3776
|
+
relay.command("event-types <platform>").description("List supported webhook event types for a platform").action(async (platform) => {
|
|
3777
|
+
await relayEventTypesCommand(platform);
|
|
3778
|
+
});
|
|
3779
|
+
program.command("guide [topic]").description("Full CLI usage guide for agents (topics: overview, actions, flows, relay, all)").action(async (topic) => {
|
|
3947
3780
|
await guideCommand(topic);
|
|
3948
3781
|
});
|
|
3949
3782
|
program.command("onboard").description("Agent onboarding \u2014 teaches your agent what the One CLI can do").option("--step <number>", "Run a specific onboarding step (1, 2, or 3)").action(async (options) => {
|