@joshualelon/clawdbot-skill-flow 0.2.1 → 0.2.3
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/index.ts
CHANGED
|
@@ -4,12 +4,16 @@
|
|
|
4
4
|
|
|
5
5
|
import type { ClawdbotPluginApi } from "clawdbot/plugin-sdk";
|
|
6
6
|
import { parseSkillFlowConfig } from "./src/config.js";
|
|
7
|
-
import { initSessionStore } from "./src/state/session-store.js";
|
|
7
|
+
import { initSessionStore, createSession, getSessionKey } from "./src/state/session-store.js";
|
|
8
8
|
import { createFlowStartCommand } from "./src/commands/flow-start.js";
|
|
9
9
|
import { createFlowStepCommand } from "./src/commands/flow-step.js";
|
|
10
10
|
import { createFlowCreateCommand } from "./src/commands/flow-create.js";
|
|
11
11
|
import { createFlowListCommand } from "./src/commands/flow-list.js";
|
|
12
12
|
import { createFlowDeleteCommand } from "./src/commands/flow-delete.js";
|
|
13
|
+
import { saveFlow, loadFlow, listFlows } from "./src/state/flow-store.js";
|
|
14
|
+
import { startFlow } from "./src/engine/executor.js";
|
|
15
|
+
import { FlowMetadataSchema } from "./src/validation.js";
|
|
16
|
+
import type { FlowMetadata } from "./src/types.js";
|
|
13
17
|
|
|
14
18
|
const plugin = {
|
|
15
19
|
id: "skill-flow",
|
|
@@ -25,9 +29,9 @@ const plugin = {
|
|
|
25
29
|
// Initialize session store with config
|
|
26
30
|
initSessionStore(config);
|
|
27
31
|
|
|
28
|
-
// Register commands
|
|
32
|
+
// Register commands (use underscores per Telegram requirements)
|
|
29
33
|
api.registerCommand({
|
|
30
|
-
name: "
|
|
34
|
+
name: "flow_start",
|
|
31
35
|
description: "Start a workflow",
|
|
32
36
|
acceptsArgs: true,
|
|
33
37
|
requireAuth: true,
|
|
@@ -35,7 +39,7 @@ const plugin = {
|
|
|
35
39
|
});
|
|
36
40
|
|
|
37
41
|
api.registerCommand({
|
|
38
|
-
name: "
|
|
42
|
+
name: "flow_step",
|
|
39
43
|
description: "Handle flow step transition (internal)",
|
|
40
44
|
acceptsArgs: true,
|
|
41
45
|
requireAuth: true,
|
|
@@ -43,7 +47,7 @@ const plugin = {
|
|
|
43
47
|
});
|
|
44
48
|
|
|
45
49
|
api.registerCommand({
|
|
46
|
-
name: "
|
|
50
|
+
name: "flow_create",
|
|
47
51
|
description: "Create a new flow from JSON",
|
|
48
52
|
acceptsArgs: true,
|
|
49
53
|
requireAuth: true,
|
|
@@ -51,7 +55,7 @@ const plugin = {
|
|
|
51
55
|
});
|
|
52
56
|
|
|
53
57
|
api.registerCommand({
|
|
54
|
-
name: "
|
|
58
|
+
name: "flow_list",
|
|
55
59
|
description: "List all available flows",
|
|
56
60
|
acceptsArgs: false,
|
|
57
61
|
requireAuth: true,
|
|
@@ -59,13 +63,116 @@ const plugin = {
|
|
|
59
63
|
});
|
|
60
64
|
|
|
61
65
|
api.registerCommand({
|
|
62
|
-
name: "
|
|
66
|
+
name: "flow_delete",
|
|
63
67
|
description: "Delete a flow",
|
|
64
68
|
acceptsArgs: true,
|
|
65
69
|
requireAuth: true,
|
|
66
70
|
handler: createFlowDeleteCommand(api),
|
|
67
71
|
});
|
|
68
72
|
|
|
73
|
+
// Register gateway methods for programmatic access
|
|
74
|
+
// @ts-expect-error - registerGatewayMethod exists at runtime, types will be available in future clawdbot release
|
|
75
|
+
api.registerGatewayMethod("skill-flow.create", async ({ params, respond }) => {
|
|
76
|
+
try {
|
|
77
|
+
const flow: FlowMetadata = FlowMetadataSchema.parse(params);
|
|
78
|
+
await saveFlow(api, flow);
|
|
79
|
+
api.logger.info(`Created flow "${flow.name}" via gateway method`);
|
|
80
|
+
respond(true, {
|
|
81
|
+
success: true,
|
|
82
|
+
flowName: flow.name,
|
|
83
|
+
message: `Flow "${flow.name}" created successfully`,
|
|
84
|
+
});
|
|
85
|
+
} catch (error) {
|
|
86
|
+
api.logger.error("Gateway method skill-flow.create failed:", error);
|
|
87
|
+
respond(false, {
|
|
88
|
+
error: error instanceof Error ? error.message : "Failed to create flow",
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
// @ts-expect-error - registerGatewayMethod exists at runtime, types will be available in future clawdbot release
|
|
94
|
+
api.registerGatewayMethod("skill-flow.list", async ({ respond }) => {
|
|
95
|
+
try {
|
|
96
|
+
const flows = await listFlows(api);
|
|
97
|
+
respond(true, {
|
|
98
|
+
flows: flows.map((f) => ({
|
|
99
|
+
name: f.name,
|
|
100
|
+
description: f.description,
|
|
101
|
+
version: f.version,
|
|
102
|
+
author: f.author,
|
|
103
|
+
})),
|
|
104
|
+
});
|
|
105
|
+
} catch (error) {
|
|
106
|
+
api.logger.error("Gateway method skill-flow.list failed:", error);
|
|
107
|
+
respond(false, {
|
|
108
|
+
error: error instanceof Error ? error.message : "Failed to list flows",
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
// @ts-expect-error - registerGatewayMethod exists at runtime, types will be available in future clawdbot release
|
|
114
|
+
api.registerGatewayMethod("skill-flow.start", async ({ params, respond }) => {
|
|
115
|
+
try {
|
|
116
|
+
const { flowName, senderId, channel } = params as {
|
|
117
|
+
flowName: string;
|
|
118
|
+
senderId: string;
|
|
119
|
+
channel: string;
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
if (!flowName || !senderId || !channel) {
|
|
123
|
+
respond(false, {
|
|
124
|
+
error: "Missing required parameters: flowName, senderId, channel",
|
|
125
|
+
});
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Load flow
|
|
130
|
+
const flow = await loadFlow(api, flowName);
|
|
131
|
+
if (!flow) {
|
|
132
|
+
respond(false, {
|
|
133
|
+
error: `Flow "${flowName}" not found`,
|
|
134
|
+
});
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Verify flow has steps
|
|
139
|
+
if (!flow.steps || flow.steps.length === 0) {
|
|
140
|
+
respond(false, {
|
|
141
|
+
error: `Flow "${flowName}" has no steps`,
|
|
142
|
+
});
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Create session
|
|
147
|
+
const session = createSession({
|
|
148
|
+
flowName: flow.name,
|
|
149
|
+
currentStepId: flow.steps[0]!.id,
|
|
150
|
+
senderId,
|
|
151
|
+
channel,
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
api.logger.info(
|
|
155
|
+
`Started flow "${flowName}" for user ${senderId} via gateway method (session: ${getSessionKey(senderId, flowName)})`
|
|
156
|
+
);
|
|
157
|
+
|
|
158
|
+
// Get the first step response
|
|
159
|
+
const response = startFlow(api, flow, session);
|
|
160
|
+
|
|
161
|
+
respond(true, {
|
|
162
|
+
success: true,
|
|
163
|
+
sessionId: getSessionKey(senderId, flowName),
|
|
164
|
+
flowName: flow.name,
|
|
165
|
+
message: `Flow "${flowName}" started`,
|
|
166
|
+
response,
|
|
167
|
+
});
|
|
168
|
+
} catch (error) {
|
|
169
|
+
api.logger.error("Gateway method skill-flow.start failed:", error);
|
|
170
|
+
respond(false, {
|
|
171
|
+
error: error instanceof Error ? error.message : "Failed to start flow",
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
|
|
69
176
|
api.logger.info("Skill Flow plugin registered successfully", {
|
|
70
177
|
sessionTimeoutMinutes: config.sessionTimeoutMinutes,
|
|
71
178
|
enableBuiltinHistory: config.enableBuiltinHistory,
|
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* /
|
|
2
|
+
* /flow_create command - Create a new flow
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import type { ClawdbotPluginApi } from "clawdbot/plugin-sdk";
|
|
@@ -13,7 +13,7 @@ export function createFlowCreateCommand(api: ClawdbotPluginApi) {
|
|
|
13
13
|
|
|
14
14
|
if (!input) {
|
|
15
15
|
return {
|
|
16
|
-
text: "Usage: /
|
|
16
|
+
text: "Usage: /flow_create import <json>\n\nExample:\n/flow_create import {...}",
|
|
17
17
|
};
|
|
18
18
|
}
|
|
19
19
|
|
|
@@ -22,7 +22,7 @@ export function createFlowCreateCommand(api: ClawdbotPluginApi) {
|
|
|
22
22
|
|
|
23
23
|
if (!importMatch) {
|
|
24
24
|
return {
|
|
25
|
-
text: "Currently only 'import' mode is supported.\n\nUsage: /
|
|
25
|
+
text: "Currently only 'import' mode is supported.\n\nUsage: /flow_create import <json>",
|
|
26
26
|
};
|
|
27
27
|
}
|
|
28
28
|
|
|
@@ -46,7 +46,7 @@ export function createFlowCreateCommand(api: ClawdbotPluginApi) {
|
|
|
46
46
|
api.logger.info(`Created flow "${flow.name}"`);
|
|
47
47
|
|
|
48
48
|
return {
|
|
49
|
-
text: `✅ Flow "${flow.name}" created successfully!\n\nStart it with: /
|
|
49
|
+
text: `✅ Flow "${flow.name}" created successfully!\n\nStart it with: /flow_start ${flow.name}`,
|
|
50
50
|
};
|
|
51
51
|
} catch (error) {
|
|
52
52
|
if (error instanceof SyntaxError) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* /
|
|
2
|
+
* /flow_delete command - Delete a flow
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import type { ClawdbotPluginApi } from "clawdbot/plugin-sdk";
|
|
@@ -11,7 +11,7 @@ export function createFlowDeleteCommand(api: ClawdbotPluginApi) {
|
|
|
11
11
|
|
|
12
12
|
if (!flowName) {
|
|
13
13
|
return {
|
|
14
|
-
text: "Usage: /
|
|
14
|
+
text: "Usage: /flow_delete <flow-name>\n\nExample: /flow_delete pushups",
|
|
15
15
|
};
|
|
16
16
|
}
|
|
17
17
|
|
|
@@ -20,7 +20,7 @@ export function createFlowDeleteCommand(api: ClawdbotPluginApi) {
|
|
|
20
20
|
|
|
21
21
|
if (!flow) {
|
|
22
22
|
return {
|
|
23
|
-
text: `Flow "${flowName}" not found.\n\nUse /
|
|
23
|
+
text: `Flow "${flowName}" not found.\n\nUse /flow_list to see available flows.`,
|
|
24
24
|
};
|
|
25
25
|
}
|
|
26
26
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* /
|
|
2
|
+
* /flow_list command - List all available flows
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import type { ClawdbotPluginApi } from "clawdbot/plugin-sdk";
|
|
@@ -11,7 +11,7 @@ export function createFlowListCommand(api: ClawdbotPluginApi) {
|
|
|
11
11
|
|
|
12
12
|
if (flows.length === 0) {
|
|
13
13
|
return {
|
|
14
|
-
text: "No flows found.\n\nCreate one with: /
|
|
14
|
+
text: "No flows found.\n\nCreate one with: /flow_create import {...}",
|
|
15
15
|
};
|
|
16
16
|
}
|
|
17
17
|
|
|
@@ -25,7 +25,7 @@ export function createFlowListCommand(api: ClawdbotPluginApi) {
|
|
|
25
25
|
message += ` 🕒 Cron: ${flow.triggers.cron}\n`;
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
message += ` Start: /
|
|
28
|
+
message += ` Start: /flow_start ${flow.name}\n\n`;
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
return { text: message };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* /
|
|
2
|
+
* /flow_start command - Start a flow
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import type { ClawdbotPluginApi } from "clawdbot/plugin-sdk";
|
|
@@ -18,7 +18,7 @@ export function createFlowStartCommand(api: ClawdbotPluginApi) {
|
|
|
18
18
|
// Validate input
|
|
19
19
|
if (!flowName) {
|
|
20
20
|
return {
|
|
21
|
-
text: "Usage: /
|
|
21
|
+
text: "Usage: /flow_start <flow-name>\n\nExample: /flow_start pushups\n\nUse /flow_list to see available flows.",
|
|
22
22
|
};
|
|
23
23
|
}
|
|
24
24
|
|
|
@@ -27,7 +27,7 @@ export function createFlowStartCommand(api: ClawdbotPluginApi) {
|
|
|
27
27
|
|
|
28
28
|
if (!flow) {
|
|
29
29
|
return {
|
|
30
|
-
text: `Flow "${flowName}" not found.\n\nUse /
|
|
30
|
+
text: `Flow "${flowName}" not found.\n\nUse /flow_list to see available flows.`,
|
|
31
31
|
};
|
|
32
32
|
}
|
|
33
33
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* /
|
|
2
|
+
* /flow_step command - Handle flow step transitions (called via Telegram callbacks)
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import type { ClawdbotPluginApi } from "clawdbot/plugin-sdk";
|
|
@@ -92,7 +92,7 @@ export function createFlowStepCommand(api: ClawdbotPluginApi) {
|
|
|
92
92
|
}
|
|
93
93
|
|
|
94
94
|
return {
|
|
95
|
-
text: `Session expired or not found.\n\nUse /
|
|
95
|
+
text: `Session expired or not found.\n\nUse /flow_start ${flowName} to restart the flow.`,
|
|
96
96
|
};
|
|
97
97
|
}
|
|
98
98
|
|
package/src/engine/renderer.ts
CHANGED
|
@@ -55,7 +55,7 @@ function renderTelegram(
|
|
|
55
55
|
for (let i = 0; i < buttons.length; i += 2) {
|
|
56
56
|
const row = buttons.slice(i, i + 2).map((btn) => ({
|
|
57
57
|
text: btn.text,
|
|
58
|
-
callback_data: `/
|
|
58
|
+
callback_data: `/flow_step ${flowName} ${step.id}:${btn.value}`,
|
|
59
59
|
}));
|
|
60
60
|
keyboard.push(row);
|
|
61
61
|
}
|
|
@@ -64,7 +64,7 @@ function renderTelegram(
|
|
|
64
64
|
keyboard = buttons.map((btn) => [
|
|
65
65
|
{
|
|
66
66
|
text: btn.text,
|
|
67
|
-
callback_data: `/
|
|
67
|
+
callback_data: `/flow_step ${flowName} ${step.id}:${btn.value}`,
|
|
68
68
|
},
|
|
69
69
|
]);
|
|
70
70
|
}
|