@botonic/nx-plugin 2.28.0 β 2.30.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/CHANGELOG.md +29 -0
- package/migrations.json +8 -1
- package/package.json +3 -2
- package/src/executors/deploy-local-runtime/executor.js +10 -6
- package/src/executors/serve-bot/schema.json +2 -3
- package/src/generators/bot-app/files/src/client/webchat/index.tsx.template +2 -0
- package/src/generators/bot-app/files/src/client/webchat/webchat.tsx.template +111 -0
- package/src/generators/bot-app/files/src/server/bot/plugins/flow-builder/index.ts.template +13 -4
- package/src/generators/bot-app/files/src/server/bot/plugins/index.ts.template +0 -3
- package/src/generators/bot-app/files/src/server/lambda/handler.js.template +1 -1
- package/src/generators/bot-app/files/src/server/lambda/package.json +3 -3
- package/src/generators/bot-app/files/vite/botonic-ssr-deps.ts.template +56 -0
- package/src/generators/bot-app/files/vite/node.config.ts.template +7 -4
- package/src/generators/bot-app/files/vite/webchat.config.ts.template +20 -1
- package/src/generators/bot-app/generator.js +6 -5
- package/src/generators/bot-app/lilara-version.json +1 -1
- package/src/generators/preset/files/.claude/skills/botonic-bot-update/SKILL.md +160 -0
- package/src/generators/preset/files/.claude/{commands/update-botonic.md β skills/botonic-update/SKILL.md} +11 -2
- package/src/lib/bot-config.d.ts +10 -7
- package/src/lib/bot-config.js +5 -1
- package/src/lib/util/executor-helpers.d.ts +10 -3
- package/src/lib/util/executor-helpers.js +39 -6
- package/src/migrations/install-claude-update-skills/install-claude-update-skills.migration.d.ts +2 -0
- package/src/migrations/install-claude-update-skills/install-claude-update-skills.migration.js +290 -0
- package/src/plugin.js +1 -1
- package/src/generators/bot-app/files/src/server/bot/tracking.ts.template +0 -35
- package/src/generators/preset/files/.claude/commands/update-bot.md +0 -114
- package/src/generators/preset/files/.cursor/commands/update-bot.md +0 -3
- package/src/generators/preset/files/.cursor/commands/update-botonic.md +0 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,32 @@
|
|
|
1
|
+
## 2.30.0 (2026-06-11)
|
|
2
|
+
|
|
3
|
+
### π Features
|
|
4
|
+
|
|
5
|
+
- update botonic-basic-template ([#932](https://github.com/metis-ai/hubtype-product/pull/932))
|
|
6
|
+
- update plugins to last botonicV0 changes #BLT-2370 ([#920](https://github.com/metis-ai/hubtype-product/pull/920))
|
|
7
|
+
- **@botonic/dx-bundling:** derive Lambda noExternal deps programmatically ([#918](https://github.com/metis-ai/hubtype-product/pull/918))
|
|
8
|
+
- support botonic v2 preview in flow builder ([#916](https://github.com/metis-ai/hubtype-product/pull/916))
|
|
9
|
+
- wire plugin-hubtype-analytics into bot apps ([#909](https://github.com/metis-ai/hubtype-product/pull/909))
|
|
10
|
+
|
|
11
|
+
### π©Ή Fixes
|
|
12
|
+
|
|
13
|
+
- allow multiple, only picking webchat app id ([#896](https://github.com/metis-ai/hubtype-product/pull/896))
|
|
14
|
+
|
|
15
|
+
### β€οΈ Thank You
|
|
16
|
+
|
|
17
|
+
- Marc Rabat @vanbasten17
|
|
18
|
+
- Oriol RaventΓ³s @Iru89
|
|
19
|
+
|
|
20
|
+
## 2.29.0 (2026-05-12)
|
|
21
|
+
|
|
22
|
+
### π Features
|
|
23
|
+
|
|
24
|
+
- **botonic:** v2 refinements - update skills, serve-bot defaults, staging bot warning ([#888](https://github.com/metis-ai/hubtype-product/pull/888))
|
|
25
|
+
|
|
26
|
+
### β€οΈ Thank You
|
|
27
|
+
|
|
28
|
+
- David Hidalgo @Davidhidalgo
|
|
29
|
+
|
|
1
30
|
## 2.28.0 (2026-05-06)
|
|
2
31
|
|
|
3
32
|
### π Features
|
package/migrations.json
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
1
|
{
|
|
2
|
-
"generators": {
|
|
2
|
+
"generators": {
|
|
3
|
+
"install-claude-update-skills": {
|
|
4
|
+
"version": "2.29.0",
|
|
5
|
+
"description": "Replace .cursor/.claude command stubs with .claude/skills/botonic-update and .claude/skills/botonic-bot-update",
|
|
6
|
+
"cli": "nx",
|
|
7
|
+
"implementation": "./src/migrations/install-claude-update-skills/install-claude-update-skills.migration"
|
|
8
|
+
}
|
|
9
|
+
}
|
|
3
10
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@botonic/nx-plugin",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.30.0",
|
|
4
4
|
"description": "Nx plugin for creating Botonic bot applications",
|
|
5
5
|
"main": "./src/index.js",
|
|
6
6
|
"types": "./src/index.d.ts",
|
|
@@ -42,7 +42,8 @@
|
|
|
42
42
|
"fs-extra": "^11.1.1",
|
|
43
43
|
"qs": "^6.11.0",
|
|
44
44
|
"yaml": "^2.6.1",
|
|
45
|
-
"zip-a-folder": "^1.1.0"
|
|
45
|
+
"zip-a-folder": "^1.1.0",
|
|
46
|
+
"zod": "^4.4.3"
|
|
46
47
|
},
|
|
47
48
|
"peerDependencies": {
|
|
48
49
|
"nx": ">=21.0.0"
|
|
@@ -130,12 +130,16 @@ async function deployLocalRuntime(botonicApiService, projectRoot, params) {
|
|
|
130
130
|
lambdaEndpoint
|
|
131
131
|
});
|
|
132
132
|
const allProviders = await botonicApiService.getProviders();
|
|
133
|
-
const appId = allProviders.data
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
133
|
+
const appId = (0, import_executor_helpers.getActiveTestWebchatProviderAppId)(allProviders.data?.results);
|
|
134
|
+
if (!appId) {
|
|
135
|
+
console.error(
|
|
136
|
+
"\u274C No active test webchat provider found. Local runtime needs a webchat test provider on this bot."
|
|
137
|
+
);
|
|
138
|
+
} else {
|
|
139
|
+
console.log("\u2705 Local runtime deployment completed!");
|
|
140
|
+
updateEnvLocal(projectRoot, appId);
|
|
141
|
+
console.log(`\u{1F194} APP_ID: ${appId}`);
|
|
142
|
+
}
|
|
139
143
|
} catch (error) {
|
|
140
144
|
console.error("\u274C Local runtime deployment failed");
|
|
141
145
|
console.error(`${String(error)}`);
|
|
@@ -7,9 +7,8 @@
|
|
|
7
7
|
"properties": {
|
|
8
8
|
"configuration": {
|
|
9
9
|
"type": "string",
|
|
10
|
-
"description": "Configuration/environment to use",
|
|
11
|
-
"enum": ["local", "dev", "dev2", "qa", "prod"]
|
|
12
|
-
"default": "local"
|
|
10
|
+
"description": "Configuration/environment to use. Defaults to 'prod' in generated workspaces; set defaultConfiguration: 'local' in project.json for development repos.",
|
|
11
|
+
"enum": ["local", "dev", "dev2", "qa", "prod"]
|
|
13
12
|
},
|
|
14
13
|
"skipWebviews": {
|
|
15
14
|
"type": "boolean",
|
|
@@ -66,8 +66,10 @@ function App({
|
|
|
66
66
|
<WebchatTrigger
|
|
67
67
|
appId={webchatConfig.appId}
|
|
68
68
|
position='bottom-right'
|
|
69
|
+
loader={() => import('./webchat')}
|
|
69
70
|
onReady={handleReady}
|
|
70
71
|
webchatConfig={{
|
|
72
|
+
...webchatConfig,
|
|
71
73
|
avatarConfig,
|
|
72
74
|
customMessages,
|
|
73
75
|
title: options.title || '<%= className %>',
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import type { WebchatController } from '@botonic/webchat-core'
|
|
2
|
+
import type {
|
|
3
|
+
WebchatCompositionExtras,
|
|
4
|
+
WebchatCompositionProps,
|
|
5
|
+
} from '@botonic/webchat-react'
|
|
6
|
+
import {
|
|
7
|
+
useWebchatContext,
|
|
8
|
+
WebchatContainer,
|
|
9
|
+
WebchatHeader,
|
|
10
|
+
WebchatInput,
|
|
11
|
+
WebchatMessages,
|
|
12
|
+
WebchatProvider,
|
|
13
|
+
} from '@botonic/webchat-react'
|
|
14
|
+
import { useEffect, useRef } from 'react'
|
|
15
|
+
|
|
16
|
+
function WebchatContent({
|
|
17
|
+
isOpen,
|
|
18
|
+
onClose,
|
|
19
|
+
onControllerReady,
|
|
20
|
+
title,
|
|
21
|
+
placeholder,
|
|
22
|
+
showBranding,
|
|
23
|
+
}: {
|
|
24
|
+
isOpen: boolean
|
|
25
|
+
onClose: () => void
|
|
26
|
+
onControllerReady: (controller: WebchatController) => void
|
|
27
|
+
title?: string
|
|
28
|
+
placeholder?: string
|
|
29
|
+
showBranding?: boolean
|
|
30
|
+
}) {
|
|
31
|
+
const { controller } = useWebchatContext()
|
|
32
|
+
const hasNotifiedRef = useRef(false)
|
|
33
|
+
|
|
34
|
+
useEffect(() => {
|
|
35
|
+
if (controller && !hasNotifiedRef.current) {
|
|
36
|
+
hasNotifiedRef.current = true
|
|
37
|
+
onControllerReady(controller)
|
|
38
|
+
}
|
|
39
|
+
}, [controller, onControllerReady])
|
|
40
|
+
|
|
41
|
+
useEffect(() => {
|
|
42
|
+
if (!controller) return
|
|
43
|
+
const snapshot = controller.machine.getSnapshot()
|
|
44
|
+
const currentIsOpen = snapshot.context.isOpen ?? false
|
|
45
|
+
if (isOpen && !currentIsOpen) {
|
|
46
|
+
controller.open()
|
|
47
|
+
} else if (!isOpen && currentIsOpen) {
|
|
48
|
+
controller.close()
|
|
49
|
+
}
|
|
50
|
+
}, [isOpen, controller])
|
|
51
|
+
|
|
52
|
+
const handleClose = () => {
|
|
53
|
+
controller?.close()
|
|
54
|
+
onClose()
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return (
|
|
58
|
+
<WebchatContainer layout='default'>
|
|
59
|
+
<WebchatHeader title={title} onClose={handleClose} />
|
|
60
|
+
<WebchatMessages variant='default' />
|
|
61
|
+
<WebchatInput
|
|
62
|
+
placeholder={placeholder}
|
|
63
|
+
showBranding={showBranding ?? true}
|
|
64
|
+
variant='default'
|
|
65
|
+
/>
|
|
66
|
+
</WebchatContainer>
|
|
67
|
+
)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export default function Webchat({
|
|
71
|
+
appId,
|
|
72
|
+
isOpen,
|
|
73
|
+
onClose,
|
|
74
|
+
onControllerReady,
|
|
75
|
+
...extras
|
|
76
|
+
}: WebchatCompositionProps) {
|
|
77
|
+
// `WebchatCompositionProps` exposes extras via a `[key: string]: unknown`
|
|
78
|
+
// index signature, so assert the concrete shape once instead of per field.
|
|
79
|
+
const {
|
|
80
|
+
title,
|
|
81
|
+
placeholder,
|
|
82
|
+
showBranding,
|
|
83
|
+
customMessages = {},
|
|
84
|
+
avatarConfig,
|
|
85
|
+
webchatClientSettings,
|
|
86
|
+
enableResponsiveHeroHeader,
|
|
87
|
+
storage,
|
|
88
|
+
previewUtils,
|
|
89
|
+
} = extras as WebchatCompositionExtras
|
|
90
|
+
|
|
91
|
+
return (
|
|
92
|
+
<WebchatProvider
|
|
93
|
+
appId={appId}
|
|
94
|
+
customMessages={customMessages}
|
|
95
|
+
avatarConfig={avatarConfig}
|
|
96
|
+
webchatClientSettings={webchatClientSettings}
|
|
97
|
+
enableResponsiveHeroHeader={enableResponsiveHeroHeader}
|
|
98
|
+
storage={storage}
|
|
99
|
+
previewUtils={previewUtils}
|
|
100
|
+
>
|
|
101
|
+
<WebchatContent
|
|
102
|
+
isOpen={isOpen}
|
|
103
|
+
onClose={onClose}
|
|
104
|
+
onControllerReady={onControllerReady}
|
|
105
|
+
title={title}
|
|
106
|
+
placeholder={placeholder}
|
|
107
|
+
showBranding={showBranding}
|
|
108
|
+
/>
|
|
109
|
+
</WebchatProvider>
|
|
110
|
+
)
|
|
111
|
+
}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
+
import { BotonicContext } from '@botonic/core'
|
|
1
2
|
import { AiAgentArgs } from '@botonic/plugin-ai-agents'
|
|
3
|
+
import { BotonicPluginHubtypeAnalytics } from '@botonic/plugin-hubtype-analytics'
|
|
2
4
|
import {
|
|
3
5
|
BotonicPluginFlowBuilder,
|
|
4
6
|
BotonicPluginFlowBuilderOptions,
|
|
5
7
|
FlowBuilderJSONVersion,
|
|
6
8
|
} from '@botonic/plugin-flow-builder'
|
|
7
|
-
import {
|
|
9
|
+
import { EventAction, HtEventProps } from '@botonic/shared'
|
|
8
10
|
|
|
9
|
-
import { trackEventToHubtypeAnalytics } from '../../tracking'
|
|
10
11
|
import { isLambdaLocal } from '../../utils'
|
|
11
12
|
import { getAiAgentResponse } from '../ai-agents'
|
|
12
13
|
|
|
@@ -14,8 +15,16 @@ export const flowBuilderConfig: BotonicPluginFlowBuilderOptions = {
|
|
|
14
15
|
flowVersion: isLambdaLocal()
|
|
15
16
|
? FlowBuilderJSONVersion.DRAFT
|
|
16
17
|
: FlowBuilderJSONVersion.LATEST,
|
|
17
|
-
trackEvent: async (
|
|
18
|
-
|
|
18
|
+
trackEvent: async (
|
|
19
|
+
context: BotonicContext,
|
|
20
|
+
eventAction: EventAction,
|
|
21
|
+
args: Omit<HtEventProps, 'action'>
|
|
22
|
+
): Promise<void> => {
|
|
23
|
+
const analyticsPlugin = new BotonicPluginHubtypeAnalytics()
|
|
24
|
+
await analyticsPlugin.trackEvent(context, {
|
|
25
|
+
action: eventAction,
|
|
26
|
+
...args,
|
|
27
|
+
} as HtEventProps)
|
|
19
28
|
},
|
|
20
29
|
getAiAgentResponse: async (
|
|
21
30
|
botonicContext: BotonicContext,
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { BotonicPluginHubtypeAnalytics } from '@botonic/plugin-hubtype-analytics'
|
|
2
|
-
|
|
3
1
|
import { aiAgentsPlugin } from './ai-agents'
|
|
4
2
|
import { flowBuilderPlugin } from './flow-builder'
|
|
5
3
|
|
|
@@ -7,5 +5,4 @@ export const plugins = {
|
|
|
7
5
|
flowBuilder: flowBuilderPlugin,
|
|
8
6
|
// AI Agents plugin is only loaded if AZURE_OPENAI_API_KEY or OPENAI_API_KEY is set
|
|
9
7
|
...(aiAgentsPlugin && { aiAgents: aiAgentsPlugin }),
|
|
10
|
-
hubtypeAnalytics: new BotonicPluginHubtypeAnalytics(),
|
|
11
8
|
}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
/*
|
|
4
4
|
In lambda functions, it only have access to all files the first time it's invoked,
|
|
5
5
|
and placed into memory, after that it only calls the function that have the information
|
|
6
|
-
|
|
6
|
+
loaded in memory. For this reason, we initialize the bot the first time, and then we
|
|
7
7
|
only execute the input function
|
|
8
8
|
|
|
9
9
|
https://docs.aws.amazon.com/lambda/latest/dg/nodejs-prog-model-handler.html
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { readFileSync, readdirSync } from 'fs'
|
|
2
|
+
import { resolve } from 'path'
|
|
3
|
+
|
|
4
|
+
// Build-only tools β never needed at Lambda runtime.
|
|
5
|
+
const BUILD_ONLY_DEPS = new Set(['tslib', 'vite', 'vitest'])
|
|
6
|
+
|
|
7
|
+
// Browser/UI-only packages pulled in by client-side @botonic/* packages
|
|
8
|
+
// (webchat-react, webchat-core). They are never imported by the server entry.
|
|
9
|
+
const BROWSER_ONLY_DEPS = new Set([
|
|
10
|
+
'react',
|
|
11
|
+
'react-dom',
|
|
12
|
+
'react-aria',
|
|
13
|
+
'@xstate/react',
|
|
14
|
+
'@lilara/foundations',
|
|
15
|
+
'@lilara/ui-web-react',
|
|
16
|
+
'class-variance-authority',
|
|
17
|
+
'react-markdown',
|
|
18
|
+
'rehype-external-links',
|
|
19
|
+
'remark-breaks',
|
|
20
|
+
'remark-gfm',
|
|
21
|
+
])
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Collects all third-party dependencies declared by the @botonic/* packages
|
|
25
|
+
* installed in this app's node_modules. The result is used in the Lambda node
|
|
26
|
+
* build's `ssr.noExternal` so that these packages are bundled into the artifact,
|
|
27
|
+
* where no node_modules are available at runtime.
|
|
28
|
+
*
|
|
29
|
+
* Deriving the list from the installed @botonic/* package.json files keeps it
|
|
30
|
+
* correct as plugins add new dependencies, instead of a hand-maintained array.
|
|
31
|
+
*/
|
|
32
|
+
export function getBotonicThirdPartyDeps(appRoot: string): string[] {
|
|
33
|
+
const botonicDir = resolve(appRoot, 'node_modules/@botonic')
|
|
34
|
+
const thirdParty = new Set<string>()
|
|
35
|
+
for (const name of readdirSync(botonicDir)) {
|
|
36
|
+
try {
|
|
37
|
+
const pkgPath = resolve(botonicDir, name, 'package.json')
|
|
38
|
+
const pkg = JSON.parse(readFileSync(pkgPath, 'utf8'))
|
|
39
|
+
for (const dep of Object.keys({
|
|
40
|
+
...pkg.dependencies,
|
|
41
|
+
...pkg.peerDependencies,
|
|
42
|
+
})) {
|
|
43
|
+
if (
|
|
44
|
+
!dep.startsWith('@botonic/') &&
|
|
45
|
+
!BUILD_ONLY_DEPS.has(dep) &&
|
|
46
|
+
!BROWSER_ONLY_DEPS.has(dep)
|
|
47
|
+
) {
|
|
48
|
+
thirdParty.add(dep)
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
} catch {
|
|
52
|
+
// skip packages without a readable package.json
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return [...thirdParty]
|
|
56
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { resolve } from 'path'
|
|
2
2
|
import type { UserConfig } from 'vite'
|
|
3
3
|
|
|
4
|
+
import { getBotonicThirdPartyDeps } from './botonic-ssr-deps'
|
|
4
5
|
import { BUILD_CONFIG } from './build.config'
|
|
5
6
|
|
|
6
7
|
const projectRoot = resolve(__dirname, '..')
|
|
@@ -12,11 +13,13 @@ export function getNodeConfig(): UserConfig {
|
|
|
12
13
|
root: projectRoot,
|
|
13
14
|
cacheDir: resolve(projectRoot, BUILD_CONFIG.CACHE_DIR.node),
|
|
14
15
|
|
|
15
|
-
//
|
|
16
|
-
// By default
|
|
17
|
-
//
|
|
16
|
+
// Bundle all @botonic/* packages and their third-party deps into the Lambda
|
|
17
|
+
// artifact. By default Vite SSR externalizes node_modules, but Lambda has no
|
|
18
|
+
// node_modules at runtime so everything must be self-contained.
|
|
19
|
+
// Third-party deps are derived programmatically from the @botonic/* package.json
|
|
20
|
+
// files so this list stays correct as plugins add new dependencies.
|
|
18
21
|
ssr: {
|
|
19
|
-
noExternal: [/@botonic
|
|
22
|
+
noExternal: [/@botonic\/.*/, ...getBotonicThirdPartyDeps(projectRoot)],
|
|
20
23
|
},
|
|
21
24
|
|
|
22
25
|
build: {
|
|
@@ -9,6 +9,25 @@ const projectRoot = resolve(__dirname, '..')
|
|
|
9
9
|
const output = BUILD_CONFIG.OUTPUT.webchat
|
|
10
10
|
const server = BUILD_CONFIG.SERVER.webchat
|
|
11
11
|
|
|
12
|
+
/**
|
|
13
|
+
* Returns the Vite `base` for the webchat bundle.
|
|
14
|
+
*
|
|
15
|
+
* Why this matters: the dashboard's flow-builder preview panel
|
|
16
|
+
* (`PreviewWebchatAppV2`) loads this bundle cross-origin from the bot's Netlify
|
|
17
|
+
* deploy while running on a different origin (localhost:4200 in dev, the
|
|
18
|
+
* dashboard domain in prod). With an absolute base ('/'), Vite resolves the
|
|
19
|
+
* bundle's dynamically-imported chunks as `/chunk.js` against the *host page's*
|
|
20
|
+
* origin β so the preview requests them from the dashboard origin and they 404.
|
|
21
|
+
*
|
|
22
|
+
* A relative base ('') makes those chunks resolve against the entry module's own
|
|
23
|
+
* origin (import.meta.url = Netlify) instead, so the preview loads the whole
|
|
24
|
+
* bundle from Netlify with no chunk 404s and no service-worker proxy. The dev
|
|
25
|
+
* server keeps '/' so its own HMR/asset paths keep working.
|
|
26
|
+
*/
|
|
27
|
+
function getCrossOriginSafeBase(command: 'serve' | 'build'): string {
|
|
28
|
+
return command === 'build' ? '' : '/'
|
|
29
|
+
}
|
|
30
|
+
|
|
12
31
|
export function getWebchatConfig(command: 'serve' | 'build'): UserConfig {
|
|
13
32
|
const openPath =
|
|
14
33
|
command === 'serve' && process.env.LOG_VIEWER_PORT
|
|
@@ -26,7 +45,7 @@ export function getWebchatConfig(command: 'serve' | 'build'): UserConfig {
|
|
|
26
45
|
cacheDir: resolve(projectRoot, BUILD_CONFIG.CACHE_DIR.webchat),
|
|
27
46
|
publicDir: resolve(projectRoot, BUILD_CONFIG.PUBLIC_DIR),
|
|
28
47
|
appType: 'spa',
|
|
29
|
-
base:
|
|
48
|
+
base: getCrossOriginSafeBase(command),
|
|
30
49
|
|
|
31
50
|
server: {
|
|
32
51
|
port: server.port,
|
|
@@ -158,10 +158,11 @@ function createPackageJson(tree, options, botonicVersion, lilaraVersion) {
|
|
|
158
158
|
"@lilara/ui-web": lilaraVersion,
|
|
159
159
|
"@lilara/ui-web-react": lilaraVersion,
|
|
160
160
|
react: "18.3.1",
|
|
161
|
-
"react-dom": "18.3.1"
|
|
161
|
+
"react-dom": "18.3.1",
|
|
162
|
+
zod: "^4.4.3"
|
|
162
163
|
},
|
|
163
164
|
devDependencies: {
|
|
164
|
-
"@nx/vite": "21.6.
|
|
165
|
+
"@nx/vite": "21.6.11",
|
|
165
166
|
"@types/node": "22.13.0",
|
|
166
167
|
"@types/react": "18.3.1",
|
|
167
168
|
"@types/react-dom": "18.3.0",
|
|
@@ -169,7 +170,7 @@ function createPackageJson(tree, options, botonicVersion, lilaraVersion) {
|
|
|
169
170
|
"@vitejs/plugin-react-swc": "^3.5.0",
|
|
170
171
|
typescript: "5.7.3",
|
|
171
172
|
vite: "7.1.9",
|
|
172
|
-
vitest: "
|
|
173
|
+
vitest: "4.1.1"
|
|
173
174
|
}
|
|
174
175
|
};
|
|
175
176
|
(0, import_devkit.writeJson)(tree, `${options.projectRoot}/package.json`, packageJson);
|
|
@@ -257,7 +258,7 @@ function addBotonicDependencies(tree, botonicVersion) {
|
|
|
257
258
|
},
|
|
258
259
|
// devDependencies
|
|
259
260
|
{
|
|
260
|
-
"@nx/vite": "21.6.
|
|
261
|
+
"@nx/vite": "21.6.11",
|
|
261
262
|
"@types/node": "22.13.0",
|
|
262
263
|
"@types/react": "18.3.1",
|
|
263
264
|
"@types/react-dom": "18.3.0",
|
|
@@ -265,7 +266,7 @@ function addBotonicDependencies(tree, botonicVersion) {
|
|
|
265
266
|
"@vitejs/plugin-react-swc": "3.5.0",
|
|
266
267
|
typescript: "5.7.3",
|
|
267
268
|
vite: "7.1.9",
|
|
268
|
-
vitest: "
|
|
269
|
+
vitest: "4.1.1"
|
|
269
270
|
}
|
|
270
271
|
);
|
|
271
272
|
}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: botonic-bot-update
|
|
3
|
+
description: >
|
|
4
|
+
Update a single Botonic bot app to the current workspace version β applies pending bot-app
|
|
5
|
+
generators and bumps @botonic/* dependencies. Use when user says "update bot",
|
|
6
|
+
"apply bot migrations", or "update <bot-name>". Run /botonic-update first to upgrade the
|
|
7
|
+
workspace itself.
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Update Botonic Bot
|
|
11
|
+
|
|
12
|
+
## Workflow: Update Bot App to Current Workspace Version
|
|
13
|
+
|
|
14
|
+
### Step 0: Detect Package Manager
|
|
15
|
+
|
|
16
|
+
Check which package manager the workspace uses:
|
|
17
|
+
|
|
18
|
+
- If `pnpm-lock.yaml` exists β use `pnpm`
|
|
19
|
+
- Else β use `npm`
|
|
20
|
+
|
|
21
|
+
Use the detected package manager for all subsequent commands.
|
|
22
|
+
|
|
23
|
+
### Step 1: Get Target Version
|
|
24
|
+
|
|
25
|
+
Read `node_modules/@botonic/nx-plugin/package.json` β `.version` field.
|
|
26
|
+
This is the version the workspace was updated to and the target for this bot.
|
|
27
|
+
|
|
28
|
+
If the file does not exist, tell user: "Could not find @botonic/nx-plugin in node_modules. Run /botonic-update first to install the latest version."
|
|
29
|
+
|
|
30
|
+
### Step 2: Discover Bots
|
|
31
|
+
|
|
32
|
+
Run `bash .claude/scripts/update-bot/discover-bots.sh` from the workspace root.
|
|
33
|
+
Expected output: JSON list of bots with name, path, current `@botonic/core` version.
|
|
34
|
+
|
|
35
|
+
### Step 3: Ask Which Bot
|
|
36
|
+
|
|
37
|
+
Present the bot list to the user. Ask which SINGLE bot to update.
|
|
38
|
+
**CRITICAL**: Never accept more than one bot. If user asks for multiple, explain why and ask them to pick one.
|
|
39
|
+
|
|
40
|
+
### Step 4: Check Bot's Current State
|
|
41
|
+
|
|
42
|
+
Read the selected bot's `package.json` (at `<bot-path>/package.json`):
|
|
43
|
+
|
|
44
|
+
- Extract the current `@botonic/core` version (strip `^` / `~` prefixes for comparison).
|
|
45
|
+
|
|
46
|
+
Read `.botonic/pending-bot-migrations.json` if it exists:
|
|
47
|
+
|
|
48
|
+
- Filter entries where `appliedTo` does NOT include `<bot-name>`.
|
|
49
|
+
|
|
50
|
+
Determine:
|
|
51
|
+
|
|
52
|
+
- `hasVersionGap`: bot's `@botonic/core` version β target version
|
|
53
|
+
- `hasPendingMigrations`: any filtered pending migration entries exist
|
|
54
|
+
|
|
55
|
+
If **neither** is true, report: "`<bot-name>` is already at v`<target>` with no pending migrations. All up to date." and stop.
|
|
56
|
+
|
|
57
|
+
### Step 5: Ask Target Version (only when pending migrations exist)
|
|
58
|
+
|
|
59
|
+
If `hasPendingMigrations`:
|
|
60
|
+
|
|
61
|
+
- Show distinct `version` values from the pending migrations (sorted ascending).
|
|
62
|
+
- Ask the user: "Which version would you like to update to?" (default: latest in list).
|
|
63
|
+
- Only apply migrations whose `version` β€ chosen target version.
|
|
64
|
+
|
|
65
|
+
If there are **no** pending migrations (version gap only), skip this step β use the target version from Step 1.
|
|
66
|
+
|
|
67
|
+
### Step 6: Check Git State
|
|
68
|
+
|
|
69
|
+
Run `git status --porcelain`. If output is non-empty, STOP.
|
|
70
|
+
Tell user: "Please commit or stash changes before updating."
|
|
71
|
+
|
|
72
|
+
### Step 7: Create Branch
|
|
73
|
+
|
|
74
|
+
`git checkout -b update/<bot-name>-to-v<target>`
|
|
75
|
+
|
|
76
|
+
### Step 8: Apply Pending Migrations (if any)
|
|
77
|
+
|
|
78
|
+
For each pending migration (in version order, filtered to `version` β€ target):
|
|
79
|
+
|
|
80
|
+
1. Run: `<package-manager> nx g <generator> --project=<bot-name>`
|
|
81
|
+
2. If `migrationGuide` path exists, READ it. Follow verification checklist and manual steps.
|
|
82
|
+
3. `git add -A && git commit -m "chore(<bot-name>): apply <generator-name>"`
|
|
83
|
+
4. Mark bot as applied: update `.botonic/pending-bot-migrations.json` β add `<bot-name>` to the `appliedTo` array for this entry.
|
|
84
|
+
5. `git add .botonic/pending-bot-migrations.json && git commit --amend --no-edit`
|
|
85
|
+
|
|
86
|
+
### Step 9: Bump @botonic/\* Versions
|
|
87
|
+
|
|
88
|
+
Check if the bot's `@botonic/core` version (after any migrations) still differs from the target version.
|
|
89
|
+
|
|
90
|
+
If it does, edit `<bot-path>/package.json`:
|
|
91
|
+
|
|
92
|
+
- Update **all** `@botonic/*` entries in `dependencies`, `devDependencies`, and `peerDependencies` to the exact target version (no `^` or `~`).
|
|
93
|
+
|
|
94
|
+
`git add <bot-path>/package.json && git commit -m "chore(<bot-name>): bump @botonic/* to v<target>"`
|
|
95
|
+
|
|
96
|
+
Skip this step only if the versions already match.
|
|
97
|
+
|
|
98
|
+
### Step 10: Final Verification
|
|
99
|
+
|
|
100
|
+
- `nx build <bot-name>`
|
|
101
|
+
- Report: list all commits made, any remaining manual steps from migration guides
|
|
102
|
+
- Suggest: `nx serve-bot <bot-name>` for manual testing
|
|
103
|
+
|
|
104
|
+
## Examples
|
|
105
|
+
|
|
106
|
+
### Example 1: Bot with pending migrations and a version gap
|
|
107
|
+
|
|
108
|
+
User says: "Update my-bot" (currently on v2.17.0, workspace on v2.19.0, 2 pending migrations)
|
|
109
|
+
|
|
110
|
+
1. Target version: 2.19.0 (from node_modules)
|
|
111
|
+
2. discover-bots.sh β my-bot on v2.17.0
|
|
112
|
+
3. Check state: hasVersionGap=true, hasPendingMigrations=true (v2.18.0, v2.19.0)
|
|
113
|
+
4. Ask target: "Available versions: 2.18.0, 2.19.0. Update to which? [default: 2.19.0]"
|
|
114
|
+
5. Branch: update/my-bot-to-v2.19.0
|
|
115
|
+
6. Apply v2.18.0 generator β commit β mark applied
|
|
116
|
+
7. Apply v2.19.0 generator β commit β mark applied
|
|
117
|
+
8. Bump @botonic/\* to 2.19.0 in package.json β commit
|
|
118
|
+
9. Report: "Done. 2 generators applied + version bumped to v2.19.0."
|
|
119
|
+
|
|
120
|
+
### Example 2: New version with no bot-app migrations (version gap only)
|
|
121
|
+
|
|
122
|
+
User says: "Update my-bot" (currently on v2.17.0, workspace on v2.18.0, no pending migrations)
|
|
123
|
+
|
|
124
|
+
1. Target version: 2.18.0 (from node_modules)
|
|
125
|
+
2. discover-bots.sh β my-bot on v2.17.0
|
|
126
|
+
3. Check state: hasVersionGap=true, hasPendingMigrations=false
|
|
127
|
+
4. No version selection prompt needed
|
|
128
|
+
5. Branch: update/my-bot-to-v2.18.0
|
|
129
|
+
6. Skip Step 8 (no migrations)
|
|
130
|
+
7. Bump @botonic/\* to 2.18.0 in package.json β commit
|
|
131
|
+
8. Report: "Done. No migrations needed β @botonic/\* bumped to v2.18.0."
|
|
132
|
+
|
|
133
|
+
### Example 3: Bot already up to date
|
|
134
|
+
|
|
135
|
+
User says: "Update customer-bot" (on v2.19.0, workspace on v2.19.0, no pending migrations)
|
|
136
|
+
|
|
137
|
+
1. Target version: 2.19.0
|
|
138
|
+
2. Check state: hasVersionGap=false, hasPendingMigrations=false
|
|
139
|
+
3. Report: "customer-bot is already at v2.19.0 with no pending migrations. All up to date."
|
|
140
|
+
|
|
141
|
+
### Example 4: Multiple bots requested (refuse)
|
|
142
|
+
|
|
143
|
+
User says: "Update all bots"
|
|
144
|
+
Response: "I update one bot at a time to ensure each migration is properly verified. Which bot would you like to start with? [list bots]"
|
|
145
|
+
|
|
146
|
+
## Troubleshooting
|
|
147
|
+
|
|
148
|
+
### Error: Generator reports "already up to date"
|
|
149
|
+
|
|
150
|
+
Cause: The bot code was already manually updated before running the generator.
|
|
151
|
+
Solution: The generator is idempotent and skipped correctly. Mark it as applied and continue to the version bump step.
|
|
152
|
+
|
|
153
|
+
### Error: Build fails after generator
|
|
154
|
+
|
|
155
|
+
Cause: Custom bot code uses removed/changed APIs.
|
|
156
|
+
Solution:
|
|
157
|
+
|
|
158
|
+
1. Read the migration guide "What it cannot handle" section
|
|
159
|
+
2. Follow "Manual migration steps" for custom patterns
|
|
160
|
+
3. Check TypeScript: `npx tsc --noEmit`
|
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: botonic-update
|
|
3
|
+
description: >
|
|
4
|
+
Update the Botonic workspace to the latest version by running nx migrate. Use when user says
|
|
5
|
+
"update botonic", "upgrade botonic", "update workspace", or wants to update @botonic/nx-plugin
|
|
6
|
+
to the latest version. If pending bot migrations are queued afterward, instruct user to run
|
|
7
|
+
/botonic-bot-update per bot.
|
|
8
|
+
---
|
|
9
|
+
|
|
1
10
|
# Update Botonic Workspace
|
|
2
11
|
|
|
3
12
|
## Workflow: Update Botonic to Latest Version
|
|
@@ -47,7 +56,7 @@ If output says "no migrations to run" and `package.json` was already at the late
|
|
|
47
56
|
|
|
48
57
|
This runs any workspace-level migrations shipped by the target `@botonic/nx-plugin` version.
|
|
49
58
|
|
|
50
|
-
If that version also queues bot-app generators, it may write `.botonic/pending-bot-migrations.json` for `/
|
|
59
|
+
If that version also queues bot-app generators, it may write `.botonic/pending-bot-migrations.json` for `/botonic-bot-update`.
|
|
51
60
|
|
|
52
61
|
### Step 6: Commit
|
|
53
62
|
|
|
@@ -62,4 +71,4 @@ Report:
|
|
|
62
71
|
- New version installed
|
|
63
72
|
- Any workspace changes applied
|
|
64
73
|
- Whether `.botonic/pending-bot-migrations.json` was created and how many generators are pending
|
|
65
|
-
- If generators are pending, instruct user to run `/
|
|
74
|
+
- If generators are pending, instruct user to run `/botonic-bot-update` to apply them per bot
|
package/src/lib/bot-config.d.ts
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
export interface ToolConfigJSON {
|
|
2
|
+
name: string;
|
|
3
|
+
schema?: Record<string, unknown>;
|
|
4
|
+
description: string;
|
|
5
|
+
}
|
|
6
|
+
export interface WebviewConfigJSON {
|
|
7
|
+
name: string;
|
|
8
|
+
}
|
|
1
9
|
export interface BotConfigJSON {
|
|
2
10
|
build_info: {
|
|
3
11
|
node_version: string;
|
|
@@ -7,14 +15,9 @@ export interface BotConfigJSON {
|
|
|
7
15
|
packages: Record<string, {
|
|
8
16
|
version: string;
|
|
9
17
|
}>;
|
|
10
|
-
tools:
|
|
11
|
-
name: string;
|
|
12
|
-
description: string;
|
|
13
|
-
}>;
|
|
18
|
+
tools: ToolConfigJSON[];
|
|
14
19
|
payloads: string[];
|
|
15
|
-
webviews:
|
|
16
|
-
name: string;
|
|
17
|
-
}>;
|
|
20
|
+
webviews: WebviewConfigJSON[];
|
|
18
21
|
}
|
|
19
22
|
export declare class BotConfig {
|
|
20
23
|
static get(projectRoot: string): Promise<BotConfigJSON>;
|
package/src/lib/bot-config.js
CHANGED
|
@@ -35,6 +35,7 @@ var childProcess = __toESM(require("child_process"));
|
|
|
35
35
|
var import_fs = require("fs");
|
|
36
36
|
var import_path = require("path");
|
|
37
37
|
var util = __toESM(require("util"));
|
|
38
|
+
var import_zod = require("zod");
|
|
38
39
|
const CONSTANTS_PATH = "src/shared/constants";
|
|
39
40
|
const TOOLS_PATH = "src/server/bot/tools";
|
|
40
41
|
class BotConfig {
|
|
@@ -108,7 +109,10 @@ class BotConfig {
|
|
|
108
109
|
return toolsModule.customTools.map(
|
|
109
110
|
(tool) => ({
|
|
110
111
|
name: tool.name,
|
|
111
|
-
description: tool.description
|
|
112
|
+
description: tool.description,
|
|
113
|
+
schema: import_zod.z.toJSONSchema(tool.schema, {
|
|
114
|
+
target: "draft-07"
|
|
115
|
+
})
|
|
112
116
|
})
|
|
113
117
|
);
|
|
114
118
|
}
|
|
@@ -70,11 +70,18 @@ export declare function writeLocalRuntimeBotToAppFolder(projectRoot: string, bot
|
|
|
70
70
|
* Removes the app folder .botonic.json so the next run will prompt to create/select a new bot (e.g. after 404 when bot was deleted).
|
|
71
71
|
*/
|
|
72
72
|
export declare function removeAppBotonicJson(projectRoot: string): void;
|
|
73
|
+
export declare function ensureLocalRuntimeBot(botonicApiService: BotonicAPIService): Promise<void>;
|
|
74
|
+
export type ProviderAccountListItem = {
|
|
75
|
+
id: string;
|
|
76
|
+
provider?: string;
|
|
77
|
+
is_test?: boolean;
|
|
78
|
+
is_active?: boolean;
|
|
79
|
+
};
|
|
73
80
|
/**
|
|
74
|
-
*
|
|
75
|
-
*
|
|
81
|
+
* APP_ID for local runtime must be the webchat test provider β not WhatsApp
|
|
82
|
+
* or other channels, which may also be test+active on the same bot.
|
|
76
83
|
*/
|
|
77
|
-
export declare function
|
|
84
|
+
export declare function getActiveTestWebchatProviderAppId(results: ProviderAccountListItem[] | undefined): string | undefined;
|
|
78
85
|
export interface PerformDeployLocalRuntimeOptions {
|
|
79
86
|
email?: string;
|
|
80
87
|
password?: string;
|
|
@@ -26,6 +26,7 @@ __export(executor_helpers_exports, {
|
|
|
26
26
|
ensureLocalRuntimeBot: () => ensureLocalRuntimeBot,
|
|
27
27
|
ensureLocalRuntimeBotBeforeTunnel: () => ensureLocalRuntimeBotBeforeTunnel,
|
|
28
28
|
findMatchingConfigurationKey: () => findMatchingConfigurationKey,
|
|
29
|
+
getActiveTestWebchatProviderAppId: () => getActiveTestWebchatProviderAppId,
|
|
29
30
|
getAppIdFromEnvFile: () => getAppIdFromEnvFile,
|
|
30
31
|
getAppIdFromEnvFileForConfig: () => getAppIdFromEnvFileForConfig,
|
|
31
32
|
getAvailableBots: () => getAvailableBots,
|
|
@@ -416,6 +417,22 @@ function removeAppBotonicJson(projectRoot) {
|
|
|
416
417
|
(0, import_fs.unlinkSync)(path);
|
|
417
418
|
}
|
|
418
419
|
}
|
|
420
|
+
async function promptConfirmStagingBot(botName) {
|
|
421
|
+
console.log(
|
|
422
|
+
`
|
|
423
|
+
\u26A0\uFE0F Bot "${botName}" will be created as a staging bot on the Hubtype platform.`
|
|
424
|
+
);
|
|
425
|
+
console.log(
|
|
426
|
+
` To create a production bot, use the Hubtype dashboard or the deploy-to-hubtype command instead.
|
|
427
|
+
`
|
|
428
|
+
);
|
|
429
|
+
const confirmation = await (0, import_enquirer.prompt)({
|
|
430
|
+
type: "confirm",
|
|
431
|
+
name: "confirm_staging",
|
|
432
|
+
message: "\u{1F6A6} Do you want to proceed?"
|
|
433
|
+
});
|
|
434
|
+
return confirmation.confirm_staging;
|
|
435
|
+
}
|
|
419
436
|
async function ensureLocalRuntimeBot(botonicApiService) {
|
|
420
437
|
if (botonicApiService.hasLocalRuntimeBot()) {
|
|
421
438
|
return;
|
|
@@ -436,6 +453,9 @@ async function ensureLocalRuntimeBot(botonicApiService) {
|
|
|
436
453
|
}
|
|
437
454
|
});
|
|
438
455
|
const name = response2.bot_name.trim();
|
|
456
|
+
if (!await promptConfirmStagingBot(name)) {
|
|
457
|
+
throw new Error("Bot creation cancelled.");
|
|
458
|
+
}
|
|
439
459
|
await createNewBotWithName(botonicApiService, name);
|
|
440
460
|
return;
|
|
441
461
|
}
|
|
@@ -467,6 +487,9 @@ async function ensureLocalRuntimeBot(botonicApiService) {
|
|
|
467
487
|
}
|
|
468
488
|
});
|
|
469
489
|
const name = nameResponse.bot_name.trim();
|
|
490
|
+
if (!await promptConfirmStagingBot(name)) {
|
|
491
|
+
throw new Error("Bot creation cancelled.");
|
|
492
|
+
}
|
|
470
493
|
await createNewBotWithName(botonicApiService, name);
|
|
471
494
|
return;
|
|
472
495
|
}
|
|
@@ -478,6 +501,12 @@ async function ensureLocalRuntimeBot(botonicApiService) {
|
|
|
478
501
|
throw new Error("Bot selection failed");
|
|
479
502
|
}
|
|
480
503
|
}
|
|
504
|
+
const WEBCHAT_PROVIDER = "webchat";
|
|
505
|
+
function getActiveTestWebchatProviderAppId(results) {
|
|
506
|
+
return results?.find(
|
|
507
|
+
(p) => Boolean(p.is_test) && Boolean(p.is_active) && p.provider === WEBCHAT_PROVIDER
|
|
508
|
+
)?.id;
|
|
509
|
+
}
|
|
481
510
|
async function performDeployLocalRuntimeWithEndpoint(context, projectRoot, endpoint, options = {}) {
|
|
482
511
|
const { targetEnvironment, environmentVariables } = resolveHubtypeEnvironment(
|
|
483
512
|
context,
|
|
@@ -512,15 +541,18 @@ async function performDeployLocalRuntimeWithEndpoint(context, projectRoot, endpo
|
|
|
512
541
|
lambdaEndpoint: endpoint
|
|
513
542
|
});
|
|
514
543
|
const providersResp = await botonicApiService.getProviders();
|
|
515
|
-
const appId =
|
|
516
|
-
|
|
517
|
-
)
|
|
544
|
+
const appId = getActiveTestWebchatProviderAppId(
|
|
545
|
+
providersResp.data.results
|
|
546
|
+
);
|
|
547
|
+
if (!appId) {
|
|
548
|
+
throw new Error(
|
|
549
|
+
"No active test webchat provider found for this bot. Local runtime requires a webchat test provider account."
|
|
550
|
+
);
|
|
551
|
+
}
|
|
518
552
|
const resolvedTargetEnv = TARGET_ENV_NAMES.includes(
|
|
519
553
|
targetEnvironment
|
|
520
554
|
) ? targetEnvironment : "local";
|
|
521
|
-
|
|
522
|
-
await writeAppIdToEnvFile(projectRoot, appId, resolvedTargetEnv);
|
|
523
|
-
}
|
|
555
|
+
await writeAppIdToEnvFile(projectRoot, appId, resolvedTargetEnv);
|
|
524
556
|
botonicApiService.saveAllCredentials();
|
|
525
557
|
return {
|
|
526
558
|
botId: botonicApiService.botInfo().id,
|
|
@@ -550,6 +582,7 @@ async function performDeployLocalRuntimeWithEndpoint(context, projectRoot, endpo
|
|
|
550
582
|
ensureLocalRuntimeBot,
|
|
551
583
|
ensureLocalRuntimeBotBeforeTunnel,
|
|
552
584
|
findMatchingConfigurationKey,
|
|
585
|
+
getActiveTestWebchatProviderAppId,
|
|
553
586
|
getAppIdFromEnvFile,
|
|
554
587
|
getAppIdFromEnvFileForConfig,
|
|
555
588
|
getAvailableBots,
|
|
@@ -0,0 +1,290 @@
|
|
|
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 install_claude_update_skills_migration_exports = {};
|
|
20
|
+
__export(install_claude_update_skills_migration_exports, {
|
|
21
|
+
default: () => installClaudeUpdateSkills
|
|
22
|
+
});
|
|
23
|
+
module.exports = __toCommonJS(install_claude_update_skills_migration_exports);
|
|
24
|
+
var import_devkit = require("@nx/devkit");
|
|
25
|
+
const BOTONIC_BOT_UPDATE_SKILL = `---
|
|
26
|
+
name: botonic-bot-update
|
|
27
|
+
description: >
|
|
28
|
+
Update a single Botonic bot app to the current workspace version \u2014 applies pending bot-app
|
|
29
|
+
generators and bumps @botonic/* dependencies. Use when user says "update bot",
|
|
30
|
+
"apply bot migrations", or "update <bot-name>". Run /botonic-update first to upgrade the
|
|
31
|
+
workspace itself.
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
# Update Botonic Bot
|
|
35
|
+
|
|
36
|
+
## Workflow: Update Bot App to Current Workspace Version
|
|
37
|
+
|
|
38
|
+
### Step 0: Detect Package Manager
|
|
39
|
+
|
|
40
|
+
Check which package manager the workspace uses:
|
|
41
|
+
|
|
42
|
+
- If \`pnpm-lock.yaml\` exists \u2192 use \`pnpm\`
|
|
43
|
+
- Else \u2192 use \`npm\`
|
|
44
|
+
|
|
45
|
+
Use the detected package manager for all subsequent commands.
|
|
46
|
+
|
|
47
|
+
### Step 1: Get Target Version
|
|
48
|
+
|
|
49
|
+
Read \`node_modules/@botonic/nx-plugin/package.json\` \u2192 \`.version\` field.
|
|
50
|
+
This is the version the workspace was updated to and the target for this bot.
|
|
51
|
+
|
|
52
|
+
If the file does not exist, tell user: "Could not find @botonic/nx-plugin in node_modules. Run /botonic-update first to install the latest version."
|
|
53
|
+
|
|
54
|
+
### Step 2: Discover Bots
|
|
55
|
+
|
|
56
|
+
Run \`bash .claude/scripts/update-bot/discover-bots.sh\` from the workspace root.
|
|
57
|
+
Expected output: JSON list of bots with name, path, current \`@botonic/core\` version.
|
|
58
|
+
|
|
59
|
+
### Step 3: Ask Which Bot
|
|
60
|
+
|
|
61
|
+
Present the bot list to the user. Ask which SINGLE bot to update.
|
|
62
|
+
**CRITICAL**: Never accept more than one bot. If user asks for multiple, explain why and ask them to pick one.
|
|
63
|
+
|
|
64
|
+
### Step 4: Check Bot's Current State
|
|
65
|
+
|
|
66
|
+
Read the selected bot's \`package.json\` (at \`<bot-path>/package.json\`):
|
|
67
|
+
- Extract the current \`@botonic/core\` version (strip \`^\` / \`~\` prefixes for comparison).
|
|
68
|
+
|
|
69
|
+
Read \`.botonic/pending-bot-migrations.json\` if it exists:
|
|
70
|
+
- Filter entries where \`appliedTo\` does NOT include \`<bot-name>\`.
|
|
71
|
+
|
|
72
|
+
Determine:
|
|
73
|
+
- \`hasVersionGap\`: bot's \`@botonic/core\` version \u2260 target version
|
|
74
|
+
- \`hasPendingMigrations\`: any filtered pending migration entries exist
|
|
75
|
+
|
|
76
|
+
If **neither** is true, report: "\`<bot-name>\` is already at v\`<target>\` with no pending migrations. All up to date." and stop.
|
|
77
|
+
|
|
78
|
+
### Step 5: Ask Target Version (only when pending migrations exist)
|
|
79
|
+
|
|
80
|
+
If \`hasPendingMigrations\`:
|
|
81
|
+
- Show distinct \`version\` values from the pending migrations (sorted ascending).
|
|
82
|
+
- Ask the user: "Which version would you like to update to?" (default: latest in list).
|
|
83
|
+
- Only apply migrations whose \`version\` \u2264 chosen target version.
|
|
84
|
+
|
|
85
|
+
If there are **no** pending migrations (version gap only), skip this step \u2014 use the target version from Step 1.
|
|
86
|
+
|
|
87
|
+
### Step 6: Check Git State
|
|
88
|
+
|
|
89
|
+
Run \`git status --porcelain\`. If output is non-empty, STOP.
|
|
90
|
+
Tell user: "Please commit or stash changes before updating."
|
|
91
|
+
|
|
92
|
+
### Step 7: Create Branch
|
|
93
|
+
|
|
94
|
+
\`git checkout -b update/<bot-name>-to-v<target>\`
|
|
95
|
+
|
|
96
|
+
### Step 8: Apply Pending Migrations (if any)
|
|
97
|
+
|
|
98
|
+
For each pending migration (in version order, filtered to \`version\` \u2264 target):
|
|
99
|
+
|
|
100
|
+
1. Run: \`<package-manager> nx g <generator> --project=<bot-name>\`
|
|
101
|
+
2. If \`migrationGuide\` path exists, READ it. Follow verification checklist and manual steps.
|
|
102
|
+
3. \`git add -A && git commit -m "chore(<bot-name>): apply <generator-name>"\`
|
|
103
|
+
4. Mark bot as applied: update \`.botonic/pending-bot-migrations.json\` \u2014 add \`<bot-name>\` to the \`appliedTo\` array for this entry.
|
|
104
|
+
5. \`git add .botonic/pending-bot-migrations.json && git commit --amend --no-edit\`
|
|
105
|
+
|
|
106
|
+
### Step 9: Bump @botonic/* Versions
|
|
107
|
+
|
|
108
|
+
Check if the bot's \`@botonic/core\` version (after any migrations) still differs from the target version.
|
|
109
|
+
|
|
110
|
+
If it does, edit \`<bot-path>/package.json\`:
|
|
111
|
+
- Update **all** \`@botonic/*\` entries in \`dependencies\`, \`devDependencies\`, and \`peerDependencies\` to the exact target version (no \`^\` or \`~\`).
|
|
112
|
+
|
|
113
|
+
\`git add <bot-path>/package.json && git commit -m "chore(<bot-name>): bump @botonic/* to v<target>"\`
|
|
114
|
+
|
|
115
|
+
Skip this step only if the versions already match.
|
|
116
|
+
|
|
117
|
+
### Step 10: Final Verification
|
|
118
|
+
|
|
119
|
+
- \`nx build <bot-name>\`
|
|
120
|
+
- Report: list all commits made, any remaining manual steps from migration guides
|
|
121
|
+
- Suggest: \`nx serve-bot <bot-name>\` for manual testing
|
|
122
|
+
|
|
123
|
+
## Examples
|
|
124
|
+
|
|
125
|
+
### Example 1: Bot with pending migrations and a version gap
|
|
126
|
+
|
|
127
|
+
User says: "Update my-bot" (currently on v2.17.0, workspace on v2.19.0, 2 pending migrations)
|
|
128
|
+
|
|
129
|
+
1. Target version: 2.19.0 (from node_modules)
|
|
130
|
+
2. discover-bots.sh \u2192 my-bot on v2.17.0
|
|
131
|
+
3. Check state: hasVersionGap=true, hasPendingMigrations=true (v2.18.0, v2.19.0)
|
|
132
|
+
4. Ask target: "Available versions: 2.18.0, 2.19.0. Update to which? [default: 2.19.0]"
|
|
133
|
+
5. Branch: update/my-bot-to-v2.19.0
|
|
134
|
+
6. Apply v2.18.0 generator \u2192 commit \u2192 mark applied
|
|
135
|
+
7. Apply v2.19.0 generator \u2192 commit \u2192 mark applied
|
|
136
|
+
8. Bump @botonic/* to 2.19.0 in package.json \u2192 commit
|
|
137
|
+
9. Report: "Done. 2 generators applied + version bumped to v2.19.0."
|
|
138
|
+
|
|
139
|
+
### Example 2: New version with no bot-app migrations (version gap only)
|
|
140
|
+
|
|
141
|
+
User says: "Update my-bot" (currently on v2.17.0, workspace on v2.18.0, no pending migrations)
|
|
142
|
+
|
|
143
|
+
1. Target version: 2.18.0 (from node_modules)
|
|
144
|
+
2. discover-bots.sh \u2192 my-bot on v2.17.0
|
|
145
|
+
3. Check state: hasVersionGap=true, hasPendingMigrations=false
|
|
146
|
+
4. No version selection prompt needed
|
|
147
|
+
5. Branch: update/my-bot-to-v2.18.0
|
|
148
|
+
6. Skip Step 8 (no migrations)
|
|
149
|
+
7. Bump @botonic/* to 2.18.0 in package.json \u2192 commit
|
|
150
|
+
8. Report: "Done. No migrations needed \u2014 @botonic/* bumped to v2.18.0."
|
|
151
|
+
|
|
152
|
+
### Example 3: Bot already up to date
|
|
153
|
+
|
|
154
|
+
User says: "Update customer-bot" (on v2.19.0, workspace on v2.19.0, no pending migrations)
|
|
155
|
+
|
|
156
|
+
1. Target version: 2.19.0
|
|
157
|
+
2. Check state: hasVersionGap=false, hasPendingMigrations=false
|
|
158
|
+
3. Report: "customer-bot is already at v2.19.0 with no pending migrations. All up to date."
|
|
159
|
+
|
|
160
|
+
### Example 4: Multiple bots requested (refuse)
|
|
161
|
+
|
|
162
|
+
User says: "Update all bots"
|
|
163
|
+
Response: "I update one bot at a time to ensure each migration is properly verified. Which bot would you like to start with? [list bots]"
|
|
164
|
+
|
|
165
|
+
## Troubleshooting
|
|
166
|
+
|
|
167
|
+
### Error: Generator reports "already up to date"
|
|
168
|
+
|
|
169
|
+
Cause: The bot code was already manually updated before running the generator.
|
|
170
|
+
Solution: The generator is idempotent and skipped correctly. Mark it as applied and continue to the version bump step.
|
|
171
|
+
|
|
172
|
+
### Error: Build fails after generator
|
|
173
|
+
|
|
174
|
+
Cause: Custom bot code uses removed/changed APIs.
|
|
175
|
+
Solution:
|
|
176
|
+
|
|
177
|
+
1. Read the migration guide "What it cannot handle" section
|
|
178
|
+
2. Follow "Manual migration steps" for custom patterns
|
|
179
|
+
3. Check TypeScript: \`npx tsc --noEmit\`
|
|
180
|
+
`;
|
|
181
|
+
const BOTONIC_UPDATE_SKILL = `---
|
|
182
|
+
name: botonic-update
|
|
183
|
+
description: >
|
|
184
|
+
Update the Botonic workspace to the latest version by running nx migrate. Use when user says
|
|
185
|
+
"update botonic", "upgrade botonic", "update workspace", or wants to update @botonic/nx-plugin
|
|
186
|
+
to the latest version. If pending bot migrations are queued afterward, instruct user to run
|
|
187
|
+
/botonic-bot-update per bot.
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
# Update Botonic Workspace
|
|
191
|
+
|
|
192
|
+
## Workflow: Update Botonic to Latest Version
|
|
193
|
+
|
|
194
|
+
### Step 0: Detect Package Manager
|
|
195
|
+
|
|
196
|
+
Check which package manager the workspace uses:
|
|
197
|
+
|
|
198
|
+
- If \`pnpm-lock.yaml\` exists \u2192 use \`pnpm\`
|
|
199
|
+
- Else \u2192 use \`npm\`
|
|
200
|
+
|
|
201
|
+
Use the detected package manager for all subsequent commands.
|
|
202
|
+
|
|
203
|
+
### Step 1: Check Current State
|
|
204
|
+
|
|
205
|
+
Run \`npm view @botonic/nx-plugin version\` to get the latest available version.
|
|
206
|
+
Check \`node_modules/@botonic/nx-plugin/package.json\` for the currently installed version.
|
|
207
|
+
|
|
208
|
+
If already on latest, report "already up to date" and stop.
|
|
209
|
+
|
|
210
|
+
### Step 2: Check Git State
|
|
211
|
+
|
|
212
|
+
Run \`git status --porcelain\`. If output is non-empty, STOP.
|
|
213
|
+
Tell user: "Please commit or stash changes before updating."
|
|
214
|
+
|
|
215
|
+
### Step 3: Run Nx Migrate
|
|
216
|
+
|
|
217
|
+
\`\`\`
|
|
218
|
+
npx nx migrate @botonic/nx-plugin@latest
|
|
219
|
+
\`\`\`
|
|
220
|
+
|
|
221
|
+
This updates \`package.json\` and creates \`migrations.json\`.
|
|
222
|
+
|
|
223
|
+
If output says "no migrations to run" and \`package.json\` was already at the latest version, stop and report "already up to date".
|
|
224
|
+
|
|
225
|
+
### Step 4: Install Dependencies
|
|
226
|
+
|
|
227
|
+
\`\`\`
|
|
228
|
+
<package-manager> install
|
|
229
|
+
\`\`\`
|
|
230
|
+
|
|
231
|
+
### Step 5: Run Workspace Migrations
|
|
232
|
+
|
|
233
|
+
\`\`\`
|
|
234
|
+
<package-manager> nx migrate --run-migrations
|
|
235
|
+
\`\`\`
|
|
236
|
+
|
|
237
|
+
This runs any workspace-level migrations shipped by the target \`@botonic/nx-plugin\` version.
|
|
238
|
+
|
|
239
|
+
If that version also queues bot-app generators, it may write \`.botonic/pending-bot-migrations.json\` for \`/botonic-bot-update\`.
|
|
240
|
+
|
|
241
|
+
### Step 6: Commit
|
|
242
|
+
|
|
243
|
+
\`\`\`
|
|
244
|
+
git add -A && git commit -m "chore: update @botonic/nx-plugin to v<version>"
|
|
245
|
+
\`\`\`
|
|
246
|
+
|
|
247
|
+
### Step 7: Report
|
|
248
|
+
|
|
249
|
+
Report:
|
|
250
|
+
|
|
251
|
+
- New version installed
|
|
252
|
+
- Any workspace changes applied
|
|
253
|
+
- Whether \`.botonic/pending-bot-migrations.json\` was created and how many generators are pending
|
|
254
|
+
- If generators are pending, instruct user to run \`/botonic-bot-update\` to apply them per bot
|
|
255
|
+
`;
|
|
256
|
+
const OLD_FILES = [
|
|
257
|
+
".cursor/commands/update-bot.md",
|
|
258
|
+
".cursor/commands/update-botonic.md",
|
|
259
|
+
".claude/commands/update-bot.md",
|
|
260
|
+
".claude/commands/update-botonic.md"
|
|
261
|
+
];
|
|
262
|
+
async function installClaudeUpdateSkills(tree) {
|
|
263
|
+
let removedCount = 0;
|
|
264
|
+
for (const filePath of OLD_FILES) {
|
|
265
|
+
if (tree.exists(filePath)) {
|
|
266
|
+
tree.delete(filePath);
|
|
267
|
+
removedCount++;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
tree.write(
|
|
271
|
+
".claude/skills/botonic-bot-update/SKILL.md",
|
|
272
|
+
BOTONIC_BOT_UPDATE_SKILL
|
|
273
|
+
);
|
|
274
|
+
tree.write(".claude/skills/botonic-update/SKILL.md", BOTONIC_UPDATE_SKILL);
|
|
275
|
+
await (0, import_devkit.formatFiles)(tree);
|
|
276
|
+
if (removedCount > 0) {
|
|
277
|
+
import_devkit.logger.info(
|
|
278
|
+
` \u2705 Removed ${removedCount} old command stub(s) (.cursor/commands/, .claude/commands/)`
|
|
279
|
+
);
|
|
280
|
+
}
|
|
281
|
+
import_devkit.logger.info(
|
|
282
|
+
` \u2705 Installed .claude/skills/botonic-bot-update/SKILL.md (was /update-bot)`
|
|
283
|
+
);
|
|
284
|
+
import_devkit.logger.info(
|
|
285
|
+
` \u2705 Installed .claude/skills/botonic-update/SKILL.md (was /update-botonic)`
|
|
286
|
+
);
|
|
287
|
+
import_devkit.logger.info(
|
|
288
|
+
` \u2139\uFE0F Use /botonic-bot-update to apply pending bot migrations and /botonic-update to upgrade the workspace`
|
|
289
|
+
);
|
|
290
|
+
}
|
package/src/plugin.js
CHANGED
|
@@ -102,7 +102,7 @@ const configurations = {
|
|
|
102
102
|
dev: {
|
|
103
103
|
configuration: "dev",
|
|
104
104
|
env: {
|
|
105
|
-
VITE_HUBTYPE_CLIENT_ID: "
|
|
105
|
+
VITE_HUBTYPE_CLIENT_ID: "WlvymZ703Y5zGnmaCZ9Da5vf0lNX08jFvgC4pRMT",
|
|
106
106
|
VITE_HUBTYPE_API_URL: "https://api.dev.dev.dev.hubtype.com",
|
|
107
107
|
VITE_PUSHER_API_PREFIX: "dev-dev-dev"
|
|
108
108
|
}
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
BotonicPluginHubtypeAnalytics,
|
|
3
|
-
EventAction,
|
|
4
|
-
HtEventProps,
|
|
5
|
-
} from '@botonic/plugin-hubtype-analytics'
|
|
6
|
-
import { BotonicContext } from '@botonic/core'
|
|
7
|
-
|
|
8
|
-
import { BotPlugins } from './types'
|
|
9
|
-
|
|
10
|
-
export async function trackEventToHubtypeAnalytics(
|
|
11
|
-
botonicContext: BotonicContext<BotPlugins>,
|
|
12
|
-
eventName: EventAction,
|
|
13
|
-
args: Omit<HtEventProps, 'action'>
|
|
14
|
-
): Promise<void> {
|
|
15
|
-
const hubtypeAnalyticsPlugin = botonicContext.plugins.hubtypeAnalytics
|
|
16
|
-
const htEventProps = {
|
|
17
|
-
action: eventName,
|
|
18
|
-
...args,
|
|
19
|
-
} as HtEventProps
|
|
20
|
-
|
|
21
|
-
if (
|
|
22
|
-
!hubtypeAnalyticsPlugin ||
|
|
23
|
-
!(hubtypeAnalyticsPlugin instanceof BotonicPluginHubtypeAnalytics)
|
|
24
|
-
) {
|
|
25
|
-
console.log('Hubtype Analytics Plugin not found')
|
|
26
|
-
return
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
const response = await hubtypeAnalyticsPlugin.trackEvent(
|
|
30
|
-
botonicContext,
|
|
31
|
-
htEventProps
|
|
32
|
-
)
|
|
33
|
-
console.log('TrackEvent Response', response, args)
|
|
34
|
-
return
|
|
35
|
-
}
|
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
# Update Botonic Bot
|
|
2
|
-
|
|
3
|
-
## Workflow: Apply Pending Bot Migrations
|
|
4
|
-
|
|
5
|
-
### Step 0: Detect Package Manager
|
|
6
|
-
|
|
7
|
-
Check which package manager the workspace uses:
|
|
8
|
-
|
|
9
|
-
- If `pnpm-lock.yaml` exists β use `pnpm`
|
|
10
|
-
- Else β use `npm`
|
|
11
|
-
|
|
12
|
-
Use the detected package manager for all subsequent commands.
|
|
13
|
-
|
|
14
|
-
### Step 1: Check Pending Migrations
|
|
15
|
-
|
|
16
|
-
Read `.botonic/pending-bot-migrations.json`.
|
|
17
|
-
|
|
18
|
-
If the file does not exist, tell user: "No pending bot migrations found. Run /update-botonic first to update the workspace."
|
|
19
|
-
|
|
20
|
-
If the `pending` array is empty, tell user: "All bot migrations are already applied."
|
|
21
|
-
|
|
22
|
-
### Step 2: Discover Bots
|
|
23
|
-
|
|
24
|
-
Run `bash .claude/scripts/update-bot/discover-bots.sh` from the workspace root.
|
|
25
|
-
Expected output: JSON list of bots with name, path, current version.
|
|
26
|
-
|
|
27
|
-
### Step 3: Ask Which Bot
|
|
28
|
-
|
|
29
|
-
Present the bot list to the user. Ask which SINGLE bot to update.
|
|
30
|
-
**CRITICAL**: Never accept more than one bot. If user asks for multiple, explain why and ask them to pick one.
|
|
31
|
-
|
|
32
|
-
### Step 4: Ask Target Version
|
|
33
|
-
|
|
34
|
-
Show the distinct `version` values from all pending migrations (sorted ascending, e.g. `2.16.0`, `2.17.0`, `2.18.0`).
|
|
35
|
-
|
|
36
|
-
Ask the user: "Which version would you like to update to?" (default: the latest version in the list).
|
|
37
|
-
|
|
38
|
-
Only apply migrations whose `version` β€ the chosen target version.
|
|
39
|
-
|
|
40
|
-
### Step 5: Find Pending Migrations for Selected Bot
|
|
41
|
-
|
|
42
|
-
Filter `.botonic/pending-bot-migrations.json` entries where ALL of:
|
|
43
|
-
|
|
44
|
-
- `appliedTo` does NOT include `<bot-name>`, AND
|
|
45
|
-
- `version` β€ chosen target version
|
|
46
|
-
|
|
47
|
-
If none, report: "<bot-name> has no pending migrations up to v<target>. All up to date."
|
|
48
|
-
|
|
49
|
-
### Step 6: Check Git State
|
|
50
|
-
|
|
51
|
-
Run `git status --porcelain`. If output is non-empty, STOP.
|
|
52
|
-
Tell user: "Please commit or stash changes before updating."
|
|
53
|
-
|
|
54
|
-
### Step 7: Create Branch
|
|
55
|
-
|
|
56
|
-
`git checkout -b update/<bot-name>-pending-migrations`
|
|
57
|
-
|
|
58
|
-
### Step 8: Apply Each Pending Generator
|
|
59
|
-
|
|
60
|
-
For each pending migration (in version order, filtered to `version` β€ target):
|
|
61
|
-
|
|
62
|
-
1. Run: `<package-manager> nx g <generator> --project=<bot-name>`
|
|
63
|
-
2. If `migrationGuide` path exists, READ it. Follow verification checklist and manual steps.
|
|
64
|
-
3. `git add -A && git commit -m "chore(<bot-name>): apply <generator-name>"`
|
|
65
|
-
4. Mark bot as applied: update `.botonic/pending-bot-migrations.json` β add `<bot-name>` to the `appliedTo` array for this entry.
|
|
66
|
-
5. `git add .botonic/pending-bot-migrations.json && git commit --amend --no-edit`
|
|
67
|
-
|
|
68
|
-
### Step 9: Final Verification
|
|
69
|
-
|
|
70
|
-
- `nx build <bot-name>`
|
|
71
|
-
- Report: list all commits, any remaining manual steps from migration guides
|
|
72
|
-
- Suggest: `nx serve-bot <bot-name>` for manual testing
|
|
73
|
-
|
|
74
|
-
## Examples
|
|
75
|
-
|
|
76
|
-
### Example 1: Bot with two pending migrations
|
|
77
|
-
|
|
78
|
-
User says: "Update my-bot"
|
|
79
|
-
|
|
80
|
-
1. Read pending-bot-migrations.json β 2 entries (v2.0.1, v2.1.0), my-bot not in appliedTo for either
|
|
81
|
-
2. discover-bots.sh β my-bot on v2.0.0
|
|
82
|
-
3. Ask target: "Available versions: 2.0.1, 2.1.0. Update to which? [default: 2.1.0]" β user picks 2.1.0
|
|
83
|
-
4. Branch: update/my-bot-pending-migrations
|
|
84
|
-
5. Run first pending generator (v2.0.1) β read guide if present β commit β mark applied
|
|
85
|
-
6. Run second pending generator (v2.1.0) β commit β mark applied
|
|
86
|
-
7. Report: "Done. 2 generators applied to my-bot up to v2.1.0."
|
|
87
|
-
|
|
88
|
-
### Example 2: Bot already up to date
|
|
89
|
-
|
|
90
|
-
User says: "Update customer-bot"
|
|
91
|
-
|
|
92
|
-
1. Read pending-bot-migrations.json β customer-bot is in appliedTo for all entries
|
|
93
|
-
2. Report: "customer-bot has no pending migrations. All up to date."
|
|
94
|
-
|
|
95
|
-
### Example 3: Multiple bots requested (refuse)
|
|
96
|
-
|
|
97
|
-
User says: "Update all bots"
|
|
98
|
-
Response: "I update one bot at a time to ensure each migration is properly verified. Which bot would you like to start with? [list bots]"
|
|
99
|
-
|
|
100
|
-
## Troubleshooting
|
|
101
|
-
|
|
102
|
-
### Error: Generator reports "already up to date"
|
|
103
|
-
|
|
104
|
-
Cause: The bot code was already manually updated before running the generator.
|
|
105
|
-
Solution: The generator is idempotent and skipped correctly. Mark it as applied and continue.
|
|
106
|
-
|
|
107
|
-
### Error: Build fails after generator
|
|
108
|
-
|
|
109
|
-
Cause: Custom bot code uses removed/changed APIs.
|
|
110
|
-
Solution:
|
|
111
|
-
|
|
112
|
-
1. Read the migration guide "What it cannot handle" section
|
|
113
|
-
2. Follow "Manual migration steps" for custom patterns
|
|
114
|
-
3. Check TypeScript: `npx tsc --noEmit`
|