@botonic/nx-plugin 2.23.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.
Files changed (206) hide show
  1. package/CHANGELOG.md +420 -0
  2. package/README.md +279 -0
  3. package/executors.json +55 -0
  4. package/generators.json +61 -0
  5. package/migrations.json +40 -0
  6. package/package.json +54 -0
  7. package/src/cursor-commands/update-bot.md +114 -0
  8. package/src/cursor-commands/update-botonic.md +63 -0
  9. package/src/executors/build-node-app/executor.d.ts +5 -0
  10. package/src/executors/build-node-app/executor.js +65 -0
  11. package/src/executors/build-node-app/schema.d.js +16 -0
  12. package/src/executors/build-node-app/schema.json +25 -0
  13. package/src/executors/delete-bot/executor.d.ts +5 -0
  14. package/src/executors/delete-bot/executor.js +112 -0
  15. package/src/executors/delete-bot/schema.d.js +16 -0
  16. package/src/executors/delete-bot/schema.json +35 -0
  17. package/src/executors/deploy-local-runtime/executor.d.ts +5 -0
  18. package/src/executors/deploy-local-runtime/executor.js +144 -0
  19. package/src/executors/deploy-local-runtime/schema.d.js +16 -0
  20. package/src/executors/deploy-local-runtime/schema.json +34 -0
  21. package/src/executors/deploy-netlify-snapshot/executor.d.ts +8 -0
  22. package/src/executors/deploy-netlify-snapshot/executor.js +79 -0
  23. package/src/executors/deploy-netlify-snapshot/schema.d.js +16 -0
  24. package/src/executors/deploy-netlify-snapshot/schema.json +31 -0
  25. package/src/executors/deploy-to-hubtype/executor.d.ts +5 -0
  26. package/src/executors/deploy-to-hubtype/executor.js +308 -0
  27. package/src/executors/deploy-to-hubtype/schema.d.js +16 -0
  28. package/src/executors/deploy-to-hubtype/schema.json +31 -0
  29. package/src/executors/e2e-webchat/botonic-package-publish.spec.ts +84 -0
  30. package/src/executors/e2e-webchat/executor.d.ts +5 -0
  31. package/src/executors/e2e-webchat/executor.js +134 -0
  32. package/src/executors/e2e-webchat/schema.d.js +16 -0
  33. package/src/executors/e2e-webchat/schema.json +35 -0
  34. package/src/executors/integrate-provider/executor.d.ts +5 -0
  35. package/src/executors/integrate-provider/executor.js +155 -0
  36. package/src/executors/integrate-provider/schema.d.js +16 -0
  37. package/src/executors/integrate-provider/schema.json +30 -0
  38. package/src/executors/login-to-hubtype/executor.d.ts +5 -0
  39. package/src/executors/login-to-hubtype/executor.js +79 -0
  40. package/src/executors/login-to-hubtype/schema.d.js +16 -0
  41. package/src/executors/login-to-hubtype/schema.json +25 -0
  42. package/src/executors/logout-from-hubtype/executor.d.ts +3 -0
  43. package/src/executors/logout-from-hubtype/executor.js +54 -0
  44. package/src/executors/logout-from-hubtype/schema.d.js +16 -0
  45. package/src/executors/logout-from-hubtype/schema.json +9 -0
  46. package/src/executors/run-lambda/executor.d.ts +5 -0
  47. package/src/executors/run-lambda/executor.js +65 -0
  48. package/src/executors/run-lambda/schema.d.js +16 -0
  49. package/src/executors/run-lambda/schema.json +20 -0
  50. package/src/executors/serve-bot/executor.d.ts +5 -0
  51. package/src/executors/serve-bot/executor.js +330 -0
  52. package/src/executors/serve-bot/schema.d.js +16 -0
  53. package/src/executors/serve-bot/schema.json +40 -0
  54. package/src/generators/action/files/__name__.spec.ts.template +15 -0
  55. package/src/generators/action/files/__name__.ts.template +15 -0
  56. package/src/generators/action/generator.d.ts +4 -0
  57. package/src/generators/action/generator.js +112 -0
  58. package/src/generators/action/schema.d.ts +7 -0
  59. package/src/generators/action/schema.js +16 -0
  60. package/src/generators/action/schema.json +43 -0
  61. package/src/generators/bot-app/files/.eslintrc.json.template +18 -0
  62. package/src/generators/bot-app/files/README.md.template +148 -0
  63. package/src/generators/bot-app/files/src/client/custom-messages/index.ts.template +2 -0
  64. package/src/generators/bot-app/files/src/client/webchat/index.html.template +35 -0
  65. package/src/generators/bot-app/files/src/client/webchat/index.tsx.template +107 -0
  66. package/src/generators/bot-app/files/src/client/webchat/styles.css.template +17 -0
  67. package/src/generators/bot-app/files/src/client/webchat/webchat-tokens-overrides.css.template +2 -0
  68. package/src/generators/bot-app/files/src/client/webviews/app.tsx.template +8 -0
  69. package/src/generators/bot-app/files/src/client/webviews/index.html.template +32 -0
  70. package/src/generators/bot-app/files/src/client/webviews/index.tsx.template +18 -0
  71. package/src/generators/bot-app/files/src/server/bot/actions/index.ts.template +2 -0
  72. package/src/generators/bot-app/files/src/server/bot/actions/not-found.ts.template +13 -0
  73. package/src/generators/bot-app/files/src/server/bot/actions/welcome.ts.template +13 -0
  74. package/src/generators/bot-app/files/src/server/bot/index.ts.template +43 -0
  75. package/src/generators/bot-app/files/src/server/bot/plugins/ai-agents/index.ts.template +30 -0
  76. package/src/generators/bot-app/files/src/server/bot/plugins/flow-builder/index.ts.template +28 -0
  77. package/src/generators/bot-app/files/src/server/bot/plugins/index.ts.template +11 -0
  78. package/src/generators/bot-app/files/src/server/bot/routes.ts.template +23 -0
  79. package/src/generators/bot-app/files/src/server/bot/tools/index.ts.template +5 -0
  80. package/src/generators/bot-app/files/src/server/bot/tracking.ts.template +35 -0
  81. package/src/generators/bot-app/files/src/server/bot/types.ts.template +4 -0
  82. package/src/generators/bot-app/files/src/server/bot/utils.ts.template +9 -0
  83. package/src/generators/bot-app/files/src/server/lambda/handler.js.template +24 -0
  84. package/src/generators/bot-app/files/src/server/lambda/package.json +20 -0
  85. package/src/generators/bot-app/files/src/server/lambda/template.yaml.template +20 -0
  86. package/src/generators/bot-app/files/src/shared/constants.ts.template +12 -0
  87. package/src/generators/bot-app/files/vite/base-client.config.ts.template +14 -0
  88. package/src/generators/bot-app/files/vite/base.config.ts.template +20 -0
  89. package/src/generators/bot-app/files/vite/build.config.ts.template +65 -0
  90. package/src/generators/bot-app/files/vite/node.config.ts.template +41 -0
  91. package/src/generators/bot-app/files/vite/plugins/move-html.plugin.ts.template +36 -0
  92. package/src/generators/bot-app/files/vite/webchat.config.ts.template +58 -0
  93. package/src/generators/bot-app/files/vite/webviews.config.ts.template +57 -0
  94. package/src/generators/bot-app/files/vite.config.ts.template +36 -0
  95. package/src/generators/bot-app/generator.d.ts +4 -0
  96. package/src/generators/bot-app/generator.js +294 -0
  97. package/src/generators/bot-app/schema.d.ts +6 -0
  98. package/src/generators/bot-app/schema.js +16 -0
  99. package/src/generators/bot-app/schema.json +36 -0
  100. package/src/generators/bot-app-migrations/migrate-fix-css-code-split/generator.d.ts +5 -0
  101. package/src/generators/bot-app-migrations/migrate-fix-css-code-split/generator.js +92 -0
  102. package/src/generators/bot-app-migrations/migrate-fix-css-code-split/schema.json +15 -0
  103. package/src/generators/bot-app-migrations/migrate-pnpm-compat/generator.d.ts +5 -0
  104. package/src/generators/bot-app-migrations/migrate-pnpm-compat/generator.js +97 -0
  105. package/src/generators/bot-app-migrations/migrate-pnpm-compat/schema.json +15 -0
  106. package/src/generators/bot-app-migrations/migrate-webchat-trigger/generator.d.ts +5 -0
  107. package/src/generators/bot-app-migrations/migrate-webchat-trigger/generator.js +165 -0
  108. package/src/generators/bot-app-migrations/migrate-webchat-trigger/schema.json +15 -0
  109. package/src/generators/custom-message/files/__name__-output.ts.template +21 -0
  110. package/src/generators/custom-message/files/__name__.spec.tsx.template +27 -0
  111. package/src/generators/custom-message/files/__name__.tsx.template +18 -0
  112. package/src/generators/custom-message/generator.d.ts +4 -0
  113. package/src/generators/custom-message/generator.js +235 -0
  114. package/src/generators/custom-message/schema.d.ts +7 -0
  115. package/src/generators/custom-message/schema.js +16 -0
  116. package/src/generators/custom-message/schema.json +44 -0
  117. package/src/generators/preset/files/.cursor/commands/update-bot.md +5 -0
  118. package/src/generators/preset/files/.cursor/commands/update-botonic.md +5 -0
  119. package/src/generators/preset/files/.cursor/scripts/update-bot/discover-bots.sh +67 -0
  120. package/src/generators/preset/files/.cursor/scripts/update-bot/find-migration-guides.sh +70 -0
  121. package/src/generators/preset/files/.cursor/skills/botonic-action/SKILL.md +167 -0
  122. package/src/generators/preset/files/.cursor/skills/botonic-custom-message/SKILL.md +231 -0
  123. package/src/generators/preset/files/.cursor/skills/botonic-webview/SKILL.md +179 -0
  124. package/src/generators/preset/files/.env.prod.template +2 -0
  125. package/src/generators/preset/files/.env.template +2 -0
  126. package/src/generators/preset/files/.npmrc.template +1 -0
  127. package/src/generators/preset/files/README.md.template +174 -0
  128. package/src/generators/preset/files/nx.json +66 -0
  129. package/src/generators/preset/files/package.json +26 -0
  130. package/src/generators/preset/files/tsconfig.base.json +27 -0
  131. package/src/generators/preset/files/tsconfig.base.json.template +27 -0
  132. package/src/generators/preset/files/tsconfig.json +9 -0
  133. package/src/generators/preset/generator.d.ts +4 -0
  134. package/src/generators/preset/generator.js +127 -0
  135. package/src/generators/preset/schema.d.ts +6 -0
  136. package/src/generators/preset/schema.js +16 -0
  137. package/src/generators/preset/schema.json +50 -0
  138. package/src/generators/remove-custom-message/generator.d.ts +4 -0
  139. package/src/generators/remove-custom-message/generator.js +259 -0
  140. package/src/generators/remove-custom-message/schema.d.ts +6 -0
  141. package/src/generators/remove-custom-message/schema.js +16 -0
  142. package/src/generators/remove-custom-message/schema.json +39 -0
  143. package/src/generators/shared/bot-app-utils.d.ts +25 -0
  144. package/src/generators/shared/bot-app-utils.js +209 -0
  145. package/src/generators/webview/files/__name__.spec.tsx.template +20 -0
  146. package/src/generators/webview/files/__name__.tsx.template +19 -0
  147. package/src/generators/webview/generator.d.ts +4 -0
  148. package/src/generators/webview/generator.js +179 -0
  149. package/src/generators/webview/schema.d.ts +5 -0
  150. package/src/generators/webview/schema.js +16 -0
  151. package/src/generators/webview/schema.json +34 -0
  152. package/src/index.d.ts +7 -0
  153. package/src/index.js +56 -0
  154. package/src/lib/api-service.d.ts +110 -0
  155. package/src/lib/api-service.js +591 -0
  156. package/src/lib/bot-config.d.ts +30 -0
  157. package/src/lib/bot-config.js +203 -0
  158. package/src/lib/cloudflared-tunnel.d.ts +29 -0
  159. package/src/lib/cloudflared-tunnel.js +95 -0
  160. package/src/lib/constants.d.ts +13 -0
  161. package/src/lib/constants.js +60 -0
  162. package/src/lib/credentials-handler.d.ts +40 -0
  163. package/src/lib/credentials-handler.js +115 -0
  164. package/src/lib/index.d.ts +10 -0
  165. package/src/lib/index.js +47 -0
  166. package/src/lib/interfaces.d.ts +49 -0
  167. package/src/lib/interfaces.js +16 -0
  168. package/src/lib/util/executor-helpers.d.ts +97 -0
  169. package/src/lib/util/executor-helpers.js +574 -0
  170. package/src/lib/util/file-system.d.ts +8 -0
  171. package/src/lib/util/file-system.js +65 -0
  172. package/src/lib/util/sam-container-cleanup.d.ts +11 -0
  173. package/src/lib/util/sam-container-cleanup.js +55 -0
  174. package/src/lib/util/sam-template.d.ts +9 -0
  175. package/src/lib/util/sam-template.js +71 -0
  176. package/src/lib/util/system.d.ts +1 -0
  177. package/src/lib/util/system.js +30 -0
  178. package/src/migrations/add-botonic-update-bots-skill/add-botonic-update-bots-skill.migration.d.ts +2 -0
  179. package/src/migrations/add-botonic-update-bots-skill/add-botonic-update-bots-skill.migration.js +52 -0
  180. package/src/migrations/add-botonic-update-bots-skill/add-botonic-update-bots-skill.migration.md +23 -0
  181. package/src/migrations/add-botonic-update-bots-skill/files/.cursor/commands/update-bot.md +5 -0
  182. package/src/migrations/add-botonic-update-bots-skill/files/.cursor/commands/update-botonic.md +5 -0
  183. package/src/migrations/add-botonic-update-bots-skill/files/.cursor/scripts/update-bot/discover-bots.sh +67 -0
  184. package/src/migrations/add-botonic-update-bots-skill/files/.cursor/scripts/update-bot/find-migration-guides.sh +70 -0
  185. package/src/migrations/add-botonic-update-bots-skill/schema.json +5 -0
  186. package/src/migrations/add-lilara-registry/add-lilara-registry.migration.d.ts +2 -0
  187. package/src/migrations/add-lilara-registry/add-lilara-registry.migration.js +49 -0
  188. package/src/migrations/add-lilara-registry/schema.json +5 -0
  189. package/src/migrations/fix-css-code-split/fix-css-code-split.migration.md +45 -0
  190. package/src/migrations/remove-codeartifact-registry/remove-codeartifact-registry.migration.d.ts +2 -0
  191. package/src/migrations/remove-codeartifact-registry/remove-codeartifact-registry.migration.js +59 -0
  192. package/src/migrations/remove-codeartifact-registry/schema.json +5 -0
  193. package/src/migrations/sync-pending-bot-migrations/schema.json +5 -0
  194. package/src/migrations/sync-pending-bot-migrations/sync-pending-bot-migrations.migration.d.ts +2 -0
  195. package/src/migrations/sync-pending-bot-migrations/sync-pending-bot-migrations.migration.js +137 -0
  196. package/src/migrations/sync-pending-bot-migrations/sync-pending-bot-migrations.migration.md +19 -0
  197. package/src/migrations/update-cursor-commands-to-stubs/schema.json +5 -0
  198. package/src/migrations/update-cursor-commands-to-stubs/update-cursor-commands-to-stubs.migration.d.ts +2 -0
  199. package/src/migrations/update-cursor-commands-to-stubs/update-cursor-commands-to-stubs.migration.js +61 -0
  200. package/src/migrations/update-pnpm-workspace-scripts/schema.json +4 -0
  201. package/src/migrations/update-pnpm-workspace-scripts/update-pnpm-workspace-scripts.migration.d.ts +2 -0
  202. package/src/migrations/update-pnpm-workspace-scripts/update-pnpm-workspace-scripts.migration.js +47 -0
  203. package/src/migrations/utils/migration-utils.d.ts +109 -0
  204. package/src/migrations/utils/migration-utils.js +448 -0
  205. package/src/plugin.d.ts +15 -0
  206. package/src/plugin.js +246 -0
@@ -0,0 +1,330 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+ var executor_exports = {};
30
+ __export(executor_exports, {
31
+ default: () => serveBotExecutor
32
+ });
33
+ module.exports = __toCommonJS(executor_exports);
34
+ var import_child_process = require("child_process");
35
+ var import_fs = require("fs");
36
+ var import_path = require("path");
37
+ var readline = __toESM(require("readline"));
38
+ var import_cloudflared_tunnel = require("../../lib/cloudflared-tunnel");
39
+ var import_executor_helpers = require("../../lib/util/executor-helpers");
40
+ var import_sam_container_cleanup = require("../../lib/util/sam-container-cleanup");
41
+ const colors = {
42
+ bot: "\x1B[36m",
43
+ // Cyan
44
+ lambda: "\x1B[33m",
45
+ // Yellow
46
+ webchat: "\x1B[32m",
47
+ // Green
48
+ webviews: "\x1B[35m",
49
+ // Magenta
50
+ reset: "\x1B[0m",
51
+ dim: "\x1B[2m",
52
+ bold: "\x1B[1m"
53
+ };
54
+ function getAppIdFromEnvFile(projectRoot) {
55
+ const envFilePath = (0, import_path.join)(projectRoot, ".env.local");
56
+ if (!(0, import_fs.existsSync)(envFilePath)) {
57
+ return null;
58
+ }
59
+ try {
60
+ const envContent = (0, import_fs.readFileSync)(envFilePath, "utf8");
61
+ const lines = envContent.split("\n");
62
+ const appIdKey = "VITE_HUBTYPE_APP_ID";
63
+ for (const line of lines) {
64
+ if (line.startsWith(`${appIdKey}=`)) {
65
+ return line.split("=")[1]?.trim();
66
+ }
67
+ }
68
+ return null;
69
+ } catch (error) {
70
+ const errorMessage = error instanceof Error ? error.message : String(error);
71
+ console.warn(`\u26A0\uFE0F Could not read .env.local file: ${errorMessage}`);
72
+ return null;
73
+ }
74
+ }
75
+ function prefixOutput(stream, prefix, color) {
76
+ if (!stream) return;
77
+ const rl = readline.createInterface({ input: stream });
78
+ rl.on("line", (line) => {
79
+ const timestamp = (/* @__PURE__ */ new Date()).toLocaleTimeString("en-US", { hour12: false });
80
+ console.log(
81
+ `${colors.dim}${timestamp}${colors.reset} ${color}[${prefix}]${colors.reset} ${line}`
82
+ );
83
+ });
84
+ }
85
+ function spawnProcess(command, name, color, cwd) {
86
+ const child = (0, import_child_process.spawn)("sh", ["-c", command], {
87
+ cwd,
88
+ stdio: ["ignore", "pipe", "pipe"],
89
+ env: { ...process.env, FORCE_COLOR: "1" }
90
+ });
91
+ prefixOutput(child.stdout, name, color);
92
+ prefixOutput(child.stderr, name, color);
93
+ return { name, color, process: child };
94
+ }
95
+ async function serveBotExecutor(options, context) {
96
+ if (!context.projectName) {
97
+ throw new Error("Project name is required");
98
+ }
99
+ const projectRoot = context.projectsConfigurations?.projects?.[context.projectName]?.root;
100
+ if (!projectRoot) {
101
+ throw new Error(`Could not find project root for ${context.projectName}`);
102
+ }
103
+ const configuration = options.configuration || "prod";
104
+ const fullProjectRoot = (0, import_path.join)(context.root, projectRoot);
105
+ const configPath = (0, import_path.join)(context.root, projectRoot, "vite.config.ts");
106
+ const appId = getAppIdFromEnvFile(fullProjectRoot);
107
+ if (!appId) {
108
+ console.warn(
109
+ `\u26A0\uFE0F VITE_HUBTYPE_APP_ID not found in .env.local \u2014 will be set automatically after deploy`
110
+ );
111
+ }
112
+ console.log(`${colors.dim}Clearing Vite cache...${colors.reset}`);
113
+ const viteCacheDirs = [
114
+ (0, import_path.join)(context.root, "node_modules", ".vite"),
115
+ (0, import_path.join)(fullProjectRoot, "node_modules", ".vite"),
116
+ (0, import_path.join)(fullProjectRoot, ".vite")
117
+ ];
118
+ for (const dir of viteCacheDirs) {
119
+ try {
120
+ if ((0, import_fs.existsSync)(dir)) {
121
+ (0, import_child_process.execSync)(`rm -rf "${dir}"`, { stdio: "pipe" });
122
+ }
123
+ } catch {
124
+ }
125
+ }
126
+ console.log(`${colors.dim}Vite cache cleared.${colors.reset}`);
127
+ const cleanupResult = (0, import_sam_container_cleanup.cleanupPreviousSamContainersByLabel)(fullProjectRoot);
128
+ if (cleanupResult === "removed") {
129
+ console.log(
130
+ `${colors.dim}[lambda] Removed previous run's container (reused slot).${colors.reset}`
131
+ );
132
+ } else if (cleanupResult === "none") {
133
+ console.log(
134
+ `${colors.dim}[lambda] No previous Lambda container to clean up.${colors.reset}`
135
+ );
136
+ }
137
+ const useTunnel = true;
138
+ const tunnelPort = options.tunnelPort ?? 3001;
139
+ let effectiveLambdaEndpoint = options.lambdaEndpoint;
140
+ let startLambda = !options.skipLambda && !effectiveLambdaEndpoint;
141
+ let tunnelBotId;
142
+ let tunnelDeployResult;
143
+ if (useTunnel) {
144
+ await (0, import_executor_helpers.ensureHubtypeLoginBeforeTunnel)(context, fullProjectRoot, {
145
+ env: options.env,
146
+ configuration
147
+ });
148
+ await (0, import_executor_helpers.ensureLocalRuntimeBotBeforeTunnel)(context, fullProjectRoot, {
149
+ env: options.env,
150
+ configuration
151
+ });
152
+ console.log(
153
+ `${colors.dim}Starting tunnel flow (Lambda + cloudflared + deploy_local_runtime)...${colors.reset}
154
+ `
155
+ );
156
+ }
157
+ const processes = [];
158
+ try {
159
+ if (useTunnel) {
160
+ const lambdaPath = (0, import_path.join)(fullProjectRoot, "src/server/lambda");
161
+ const lambdaCommand = "sam local start-lambda --warm-containers EAGER --skip-pull-image";
162
+ processes.push(
163
+ spawnProcess(lambdaCommand, "lambda", colors.lambda, lambdaPath)
164
+ );
165
+ await new Promise((resolve) => setTimeout(resolve, 2e3));
166
+ console.log(
167
+ `${colors.dim}Starting Cloudflare tunnel (cloudflared)...${colors.reset}`
168
+ );
169
+ const { url: tunnelUrl, process: cloudflaredProcess } = await (0, import_cloudflared_tunnel.startCloudflaredTunnel)(tunnelPort);
170
+ processes.push({
171
+ name: "tunnel",
172
+ color: colors.lambda,
173
+ process: cloudflaredProcess
174
+ });
175
+ console.log(`${colors.dim}Tunnel URL: ${tunnelUrl}${colors.reset}
176
+ `);
177
+ console.log(
178
+ `${colors.dim}Registering tunnel with backend (deploy_local_runtime)...${colors.reset}`
179
+ );
180
+ const deployResult = await (0, import_executor_helpers.performDeployLocalRuntimeWithEndpoint)(
181
+ context,
182
+ fullProjectRoot,
183
+ tunnelUrl,
184
+ { env: options.env, configuration }
185
+ );
186
+ tunnelBotId = deployResult.botId;
187
+ tunnelDeployResult = {
188
+ targetEnvironment: deployResult.targetEnvironment,
189
+ environmentVariables: deployResult.environmentVariables
190
+ };
191
+ effectiveLambdaEndpoint = tunnelUrl;
192
+ startLambda = false;
193
+ }
194
+ } catch (tunnelError) {
195
+ const msg = tunnelError instanceof Error ? tunnelError.message : String(tunnelError);
196
+ console.error(`\u274C Tunnel flow failed: ${msg}`);
197
+ return { success: false };
198
+ }
199
+ let effectiveAppId = appId;
200
+ if (useTunnel) {
201
+ const latestAppId = (0, import_executor_helpers.getAppIdFromEnvFileForConfig)(
202
+ fullProjectRoot,
203
+ configuration
204
+ );
205
+ if (latestAppId) effectiveAppId = latestAppId;
206
+ }
207
+ if (configuration !== "local" && effectiveAppId) {
208
+ await (0, import_executor_helpers.writeAppIdToEnvFile)(fullProjectRoot, effectiveAppId, configuration);
209
+ if (tunnelBotId) {
210
+ (0, import_executor_helpers.writeEnvVarToEnvFile)(
211
+ fullProjectRoot,
212
+ "VITE_HUBTYPE_BOT_ID",
213
+ tunnelBotId,
214
+ configuration
215
+ );
216
+ }
217
+ }
218
+ const useExternalLambda = Boolean(effectiveLambdaEndpoint);
219
+ if (!useTunnel) {
220
+ startLambda = !options.skipLambda && !useExternalLambda;
221
+ }
222
+ console.log(`
223
+ ${colors.bold}\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557
224
+ \u2551 \u{1F680} Botonic Dev Server \u2551
225
+ \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D${colors.reset}
226
+
227
+ ${colors.dim}Project:${colors.reset} ${context.projectName}
228
+ ${colors.dim}Configuration:${colors.reset} ${configuration}
229
+ ${colors.dim}App ID:${colors.reset} ${effectiveAppId}
230
+ ${useExternalLambda ? `${colors.dim}Lambda (external):${colors.reset} ${effectiveLambdaEndpoint}
231
+ ` : ""}
232
+ ${colors.bot}[bot]${colors.reset} - Node/Lambda build watcher
233
+ ${startLambda ? `${colors.lambda}[lambda]${colors.reset} - AWS SAM local lambda server` : useExternalLambda ? `${colors.lambda}[lambda]${colors.reset} - Using external endpoint (no Docker)` : ""}
234
+ ${colors.webchat}[webchat]${colors.reset} - Webchat Vite dev server
235
+ ${colors.webviews}[webviews]${colors.reset} - Webviews Vite dev server
236
+ `);
237
+ if (useExternalLambda && !useTunnel) {
238
+ console.log(
239
+ `${colors.dim}\u{1F4A1} Ensure you have run deploy_local_runtime with this URL so the backend can invoke your Lambda.${colors.reset}
240
+ `
241
+ );
242
+ }
243
+ for (const dir of viteCacheDirs) {
244
+ try {
245
+ if ((0, import_fs.existsSync)(dir)) {
246
+ (0, import_child_process.execSync)(`rm -rf "${dir}"`, { stdio: "pipe" });
247
+ }
248
+ } catch {
249
+ }
250
+ }
251
+ try {
252
+ const buildCommand = `VITE_CJS_IGNORE_WARNING=true BUILD_TARGET=node vite build --config ${configPath} --watch`;
253
+ processes.push(
254
+ spawnProcess(buildCommand, "bot", colors.bot, fullProjectRoot)
255
+ );
256
+ await new Promise((resolve) => setTimeout(resolve, 3e3));
257
+ if (startLambda) {
258
+ const lambdaPath = (0, import_path.join)(fullProjectRoot, "src/server/lambda");
259
+ const lambdaCommand = "sam local start-lambda --warm-containers EAGER --skip-pull-image";
260
+ processes.push(
261
+ spawnProcess(lambdaCommand, "lambda", colors.lambda, lambdaPath)
262
+ );
263
+ await new Promise((resolve) => setTimeout(resolve, 2e3));
264
+ }
265
+ const noOpenEnv = options.open === false ? "VITE_SERVE_OPEN=false " : "";
266
+ const viteEnvAppId = `VITE_HUBTYPE_APP_ID=${effectiveAppId}`;
267
+ const viteEnvBotId = tunnelBotId != null ? ` VITE_HUBTYPE_BOT_ID=${tunnelBotId}` : "";
268
+ const webchatCommand = `${noOpenEnv}${viteEnvAppId}${viteEnvBotId} TARGET_APP=webchat MODE=${configuration} vite --config ${configPath}`;
269
+ processes.push(
270
+ spawnProcess(webchatCommand, "webchat", colors.webchat, fullProjectRoot)
271
+ );
272
+ if (!options.skipWebviews) {
273
+ const webviewsCommand = `${noOpenEnv}${viteEnvAppId}${viteEnvBotId} TARGET_APP=webviews MODE=${configuration} vite --config ${configPath}`;
274
+ processes.push(
275
+ spawnProcess(
276
+ webviewsCommand,
277
+ "webviews",
278
+ colors.webviews,
279
+ fullProjectRoot
280
+ )
281
+ );
282
+ }
283
+ let cleanupCalled = false;
284
+ const cleanup = () => {
285
+ if (cleanupCalled) return;
286
+ cleanupCalled = true;
287
+ console.log(
288
+ `
289
+ ${colors.bold}\u{1F6D1} Shutting down all processes...${colors.reset}`
290
+ );
291
+ processes.forEach(({ name, color, process: proc }) => {
292
+ console.log(`${color}[${name}]${colors.reset} Stopping...`);
293
+ proc.kill("SIGTERM");
294
+ });
295
+ };
296
+ process.on("SIGINT", cleanup);
297
+ process.on("SIGTERM", cleanup);
298
+ process.on("exit", cleanup);
299
+ return new Promise((resolve) => {
300
+ let exitCount = 0;
301
+ const totalProcesses = processes.length;
302
+ processes.forEach(({ name, color, process: proc }) => {
303
+ proc.on("exit", (code) => {
304
+ console.log(
305
+ `${color}[${name}]${colors.reset} Process exited with code ${code}`
306
+ );
307
+ exitCount++;
308
+ if (code !== 0 && code !== null) {
309
+ cleanup();
310
+ resolve({ success: false });
311
+ }
312
+ if (exitCount === totalProcesses) {
313
+ resolve({ success: true });
314
+ }
315
+ });
316
+ proc.on("error", (error) => {
317
+ console.error(
318
+ `${color}[${name}]${colors.reset} Error: ${error.message}`
319
+ );
320
+ cleanup();
321
+ resolve({ success: false });
322
+ });
323
+ });
324
+ });
325
+ } catch (error) {
326
+ const errorMessage = error instanceof Error ? error.message : String(error);
327
+ console.error(`\u274C Error starting dev server:`, errorMessage);
328
+ return { success: false };
329
+ }
330
+ }
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __copyProps = (to, from, except, desc) => {
7
+ if (from && typeof from === "object" || typeof from === "function") {
8
+ for (let key of __getOwnPropNames(from))
9
+ if (!__hasOwnProp.call(to, key) && key !== except)
10
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
11
+ }
12
+ return to;
13
+ };
14
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
15
+ var schema_d_exports = {};
16
+ module.exports = __toCommonJS(schema_d_exports);
@@ -0,0 +1,40 @@
1
+ {
2
+ "$schema": "https://json-schema.org/schema",
3
+ "version": 2,
4
+ "title": "ServeBot executor",
5
+ "description": "Serve Botonic app with all processes (build, lambda, webchat, webviews) running in parallel with labeled output",
6
+ "type": "object",
7
+ "properties": {
8
+ "configuration": {
9
+ "type": "string",
10
+ "description": "Configuration/environment to use",
11
+ "enum": ["local", "dev", "dev2", "qa", "prod"],
12
+ "default": "local"
13
+ },
14
+ "skipWebviews": {
15
+ "type": "boolean",
16
+ "description": "Skip starting the webviews server",
17
+ "default": false
18
+ },
19
+ "skipLambda": {
20
+ "type": "boolean",
21
+ "description": "Skip starting the lambda server (useful if running lambda externally)",
22
+ "default": false
23
+ },
24
+ "lambdaEndpoint": {
25
+ "type": "string",
26
+ "description": "Use an external Lambda endpoint (e.g. ngrok URL) instead of starting sam local start-lambda. When set, the Lambda server is not started (it is already running elsewhere). Also run deploy_local_runtime with this URL so the backend can invoke your Lambda."
27
+ },
28
+ "open": {
29
+ "type": "boolean",
30
+ "description": "Open browser for webchat dev server",
31
+ "default": true
32
+ },
33
+ "tunnelPort": {
34
+ "type": "number",
35
+ "description": "Local port the Lambda listens on (used for cloudflared --url). Default 3001.",
36
+ "default": 3001
37
+ }
38
+ },
39
+ "required": []
40
+ }
@@ -0,0 +1,15 @@
1
+ import { describe, expect, it, vi } from 'vitest'
2
+
3
+ import { <%= className %> } from './<%= fileName %>'
4
+
5
+ describe('<%= className %>', () => {
6
+ it('should call sendMessage and return OK', async () => {
7
+ const sendMessage = vi.fn().mockResolvedValue(undefined)
8
+ const mockContext = { sendMessage } as any
9
+
10
+ const result = await <%= className %>(mockContext)
11
+
12
+ expect(sendMessage).toHaveBeenCalledOnce()
13
+ expect(result).toEqual({ status: 200, response: 'OK' })
14
+ })
15
+ })
@@ -0,0 +1,15 @@
1
+ import { BotContext, BotServerMessageFactory } from '@botonic/shared'
2
+
3
+ export async function <%= className %>({ sendMessage }: BotContext) {
4
+ // TODO: Implement your action logic here
5
+ await sendMessage(
6
+ BotServerMessageFactory.createText({
7
+ text: 'Hello from <%= className %>!',
8
+ })
9
+ )
10
+
11
+ return {
12
+ status: 200,
13
+ response: 'OK',
14
+ }
15
+ }
@@ -0,0 +1,4 @@
1
+ import { Tree } from '@nx/devkit';
2
+ import type { ActionGeneratorSchema } from './schema';
3
+ export default function (tree: Tree, options: ActionGeneratorSchema): Promise<void>;
4
+ export { ActionGeneratorSchema };
@@ -0,0 +1,112 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var generator_exports = {};
20
+ __export(generator_exports, {
21
+ default: () => generator_default
22
+ });
23
+ module.exports = __toCommonJS(generator_exports);
24
+ var import_devkit = require("@nx/devkit");
25
+ var import_bot_app_utils = require("../shared/bot-app-utils");
26
+ const MODULE_DIR = __dirname;
27
+ function normalizeOptions(tree, options) {
28
+ const { projectRoot, sourceRoot } = (0, import_bot_app_utils.validateBotAppProject)(
29
+ tree,
30
+ options.project
31
+ );
32
+ const paths = (0, import_bot_app_utils.resolveStandardPaths)(sourceRoot);
33
+ const name = (0, import_devkit.names)(options.name);
34
+ const fileName = name.fileName;
35
+ const className = name.className;
36
+ return {
37
+ ...options,
38
+ projectName: options.project,
39
+ projectRoot,
40
+ fileName,
41
+ className,
42
+ actionsPath: paths.actionsPath,
43
+ routesPath: paths.routesPath,
44
+ resolvedRouteMatcher: options.routeMatcher ?? fileName
45
+ };
46
+ }
47
+ function addFilesToProject(tree, options) {
48
+ const name = (0, import_devkit.names)(options.name);
49
+ const templateOptions = {
50
+ ...options,
51
+ ...name,
52
+ name: name.fileName
53
+ // __name__ in filenames must be kebab-case
54
+ };
55
+ (0, import_devkit.generateFiles)(
56
+ tree,
57
+ (0, import_devkit.joinPathFragments)(MODULE_DIR, "files"),
58
+ options.actionsPath,
59
+ templateOptions
60
+ );
61
+ if (options.skipTests) {
62
+ const testFilePath = `${options.actionsPath}/${options.fileName}.spec.ts`;
63
+ if (tree.exists(testFilePath)) {
64
+ tree.delete(testFilePath);
65
+ }
66
+ }
67
+ }
68
+ function updateActionsIndex(tree, options) {
69
+ (0, import_bot_app_utils.addExportToIndex)(
70
+ tree,
71
+ `${options.actionsPath}/index.ts`,
72
+ `export * from './${options.fileName}'`
73
+ );
74
+ }
75
+ function updateRoutes(tree, options) {
76
+ if (options.skipRoute) {
77
+ return;
78
+ }
79
+ (0, import_bot_app_utils.addActionImportToRoutes)(tree, options.routesPath, options.className);
80
+ (0, import_bot_app_utils.insertRouteBeforeFlowBuilder)(tree, options.routesPath, [
81
+ ` {`,
82
+ ` text: '${options.resolvedRouteMatcher}',`,
83
+ ` action: async () => await ${options.className}(botContext),`,
84
+ ` },`
85
+ ]);
86
+ }
87
+ async function generator_default(tree, options) {
88
+ console.log(`Creating action: ${options.name}`);
89
+ const normalizedOptions = normalizeOptions(tree, options);
90
+ console.log(`Project: ${normalizedOptions.projectName}`);
91
+ console.log(`Location: ${normalizedOptions.actionsPath}`);
92
+ addFilesToProject(tree, normalizedOptions);
93
+ updateActionsIndex(tree, normalizedOptions);
94
+ updateRoutes(tree, normalizedOptions);
95
+ await (0, import_devkit.formatFiles)(tree);
96
+ console.log(`
97
+ Successfully created action: ${normalizedOptions.className}`);
98
+ console.log(`Next steps:`);
99
+ console.log(
100
+ ` 1. Implement the logic in: ${normalizedOptions.actionsPath}/${normalizedOptions.fileName}.ts`
101
+ );
102
+ if (!options.skipRoute) {
103
+ console.log(
104
+ ` 2. Test by sending '${normalizedOptions.resolvedRouteMatcher}' in the webchat`
105
+ );
106
+ }
107
+ if (!options.skipTests) {
108
+ console.log(
109
+ ` 3. Update the tests in: ${normalizedOptions.actionsPath}/${normalizedOptions.fileName}.spec.ts`
110
+ );
111
+ }
112
+ }
@@ -0,0 +1,7 @@
1
+ export interface ActionGeneratorSchema {
2
+ name: string;
3
+ project: string;
4
+ skipTests?: boolean;
5
+ skipRoute?: boolean;
6
+ routeMatcher?: string;
7
+ }
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __copyProps = (to, from, except, desc) => {
7
+ if (from && typeof from === "object" || typeof from === "function") {
8
+ for (let key of __getOwnPropNames(from))
9
+ if (!__hasOwnProp.call(to, key) && key !== except)
10
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
11
+ }
12
+ return to;
13
+ };
14
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
15
+ var schema_exports = {};
16
+ module.exports = __toCommonJS(schema_exports);
@@ -0,0 +1,43 @@
1
+ {
2
+ "$schema": "http://json-schema.org/schema",
3
+ "cli": "nx",
4
+ "$id": "Action",
5
+ "title": "Create a bot action for Botonic",
6
+ "description": "Generate a server-side bot action with automatic registration in routes.",
7
+ "type": "object",
8
+ "properties": {
9
+ "name": {
10
+ "type": "string",
11
+ "description": "The name of the action.",
12
+ "$default": {
13
+ "$source": "argv",
14
+ "index": 0
15
+ },
16
+ "x-prompt": "What name would you like to use for the action?",
17
+ "pattern": "^[a-zA-Z].*$"
18
+ },
19
+ "project": {
20
+ "type": "string",
21
+ "description": "The name of the botonic project to add the action to.",
22
+ "x-prompt": "Which botonic project should this action be added to?",
23
+ "$default": {
24
+ "$source": "projectName"
25
+ }
26
+ },
27
+ "skipTests": {
28
+ "type": "boolean",
29
+ "description": "Skip generating test files.",
30
+ "default": false
31
+ },
32
+ "skipRoute": {
33
+ "type": "boolean",
34
+ "description": "Skip registering a route for this action in routes.ts.",
35
+ "default": false
36
+ },
37
+ "routeMatcher": {
38
+ "type": "string",
39
+ "description": "The text matcher for the route (defaults to the kebab-case action name)."
40
+ }
41
+ },
42
+ "required": ["name", "project"]
43
+ }
@@ -0,0 +1,18 @@
1
+ {
2
+ "extends": ["../../.eslintrc.json"],
3
+ "ignorePatterns": ["!**/*", "**/node_modules/**", "node_modules", "dist"],
4
+ "overrides": [
5
+ {
6
+ "files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
7
+ "rules": {}
8
+ },
9
+ {
10
+ "files": ["*.ts", "*.tsx"],
11
+ "rules": {}
12
+ },
13
+ {
14
+ "files": ["*.js", "*.jsx"],
15
+ "rules": {}
16
+ }
17
+ ]
18
+ }