vibespot 0.4.0 → 0.4.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -1
- package/assets/conversion-guide.md +2 -2
- package/dist/index.js +22 -13
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/ui/chat.js +64 -12
- package/ui/index.html +15 -4
- package/ui/styles.css +141 -17
package/README.md
CHANGED
|
@@ -6,6 +6,10 @@ AI-powered HubSpot CMS landing page builder — vibe coding & React converter.
|
|
|
6
6
|
≋ vibeSpot — Build HubSpot Landing Pages with AI
|
|
7
7
|
```
|
|
8
8
|
|
|
9
|
+
> **Before you start:** vibeSpot's in-app setup will walk you through configuration, but for the smoothest experience, install your preferred AI engine and the HubSpot CLI **before** running vibeSpot. The onboarding flow is still being refined — having these tools ready avoids extra back-and-forth.
|
|
10
|
+
>
|
|
11
|
+
> **Requirements:** Node.js 18+, HubSpot CLI 8+ (`npm install -g @hubspot/cli@latest`). HubSpot CLI versions below 8 are **not supported** — deprecated commands like `hs create website-theme` were removed in v8.
|
|
12
|
+
|
|
9
13
|
## What It Does
|
|
10
14
|
|
|
11
15
|
vibeSpot lets you build HubSpot landing pages by chatting with AI. Describe what you want, and it generates native HubSpot CMS modules — fully editable in the HubSpot page editor. No coding knowledge required.
|
|
@@ -115,4 +119,4 @@ Settings are saved in `~/.vibespot/config.json`:
|
|
|
115
119
|
|
|
116
120
|
## License
|
|
117
121
|
|
|
118
|
-
|
|
122
|
+
Personal use only — see [LICENSE](LICENSE) for details. Commercial licensing available on request.
|
|
@@ -222,7 +222,7 @@ This is where React props become HubSpot-editable fields. Every piece of text, i
|
|
|
222
222
|
| `"name": "name"` | `missing field name` | `name` is reserved — use `item_name`, `link_label`, etc. |
|
|
223
223
|
| `{% module %}` in module.html | `'module' is disabled in this context` | Cannot nest modules — use `{% form %}` for forms |
|
|
224
224
|
| `{{ now() }}` | `Could not resolve function 'now'` | Use `{{ local_dt }}` for current date/time |
|
|
225
|
-
| Partially uploaded module | Re-upload still fails | Run `hs remove <path>` first, then re-upload |
|
|
225
|
+
| Partially uploaded module | Re-upload still fails | Run `hs cms remove <path>` first, then re-upload |
|
|
226
226
|
| SVG in text field | SVG renders as escaped text | SVG markup in text fields is auto-escaped by HubL |
|
|
227
227
|
|
|
228
228
|
### Image Fields
|
|
@@ -618,7 +618,7 @@ For backgrounds with transparency (e.g., glassmorphism cards):
|
|
|
618
618
|
|
|
619
619
|
**Cause**: Partially uploaded module with invalid `fields.json` is cached on HubSpot.
|
|
620
620
|
|
|
621
|
-
**Fix**: `hs remove my-theme/modules/MyModule.module` then re-upload.
|
|
621
|
+
**Fix**: `hs cms remove my-theme/modules/MyModule.module` then re-upload.
|
|
622
622
|
|
|
623
623
|
### 5. Repeater Group Content Missing
|
|
624
624
|
|
package/dist/index.js
CHANGED
|
@@ -162,13 +162,14 @@ function saveConfig(config) {
|
|
|
162
162
|
}
|
|
163
163
|
|
|
164
164
|
// src/utils/detect.ts
|
|
165
|
+
var whichCmd = process.platform === "win32" ? "where" : "which";
|
|
165
166
|
function detectNode() {
|
|
166
167
|
const result = run("node --version");
|
|
167
168
|
return {
|
|
168
169
|
name: "Node.js",
|
|
169
170
|
found: result.success,
|
|
170
171
|
version: result.stdout.replace(/^v/, ""),
|
|
171
|
-
path: run(
|
|
172
|
+
path: run(`${whichCmd} node`).stdout
|
|
172
173
|
};
|
|
173
174
|
}
|
|
174
175
|
function detectGit() {
|
|
@@ -177,7 +178,7 @@ function detectGit() {
|
|
|
177
178
|
name: "Git",
|
|
178
179
|
found: result.success,
|
|
179
180
|
version: result.stdout.replace("git version ", ""),
|
|
180
|
-
path: run(
|
|
181
|
+
path: run(`${whichCmd} git`).stdout
|
|
181
182
|
};
|
|
182
183
|
}
|
|
183
184
|
function detectHubSpotCLI() {
|
|
@@ -186,7 +187,7 @@ function detectHubSpotCLI() {
|
|
|
186
187
|
name: "HubSpot CLI",
|
|
187
188
|
found: result.success,
|
|
188
189
|
version: result.stdout,
|
|
189
|
-
path: run(
|
|
190
|
+
path: run(`${whichCmd} hs`).stdout
|
|
190
191
|
};
|
|
191
192
|
}
|
|
192
193
|
function detectClaudeCode() {
|
|
@@ -214,7 +215,7 @@ function detectClaudeCode() {
|
|
|
214
215
|
name: "Claude Code",
|
|
215
216
|
found: true,
|
|
216
217
|
version: result.stdout,
|
|
217
|
-
path: run(
|
|
218
|
+
path: run(`${whichCmd} claude`).stdout,
|
|
218
219
|
authenticated,
|
|
219
220
|
authDetail
|
|
220
221
|
};
|
|
@@ -300,7 +301,7 @@ function detectGeminiCLI() {
|
|
|
300
301
|
name: "Gemini CLI",
|
|
301
302
|
found: true,
|
|
302
303
|
version: result.stdout,
|
|
303
|
-
path: run(
|
|
304
|
+
path: run(`${whichCmd} gemini`).stdout,
|
|
304
305
|
authenticated,
|
|
305
306
|
authDetail: authenticated ? "Authenticated" : "Run `gemini` to sign in with Google"
|
|
306
307
|
};
|
|
@@ -326,7 +327,7 @@ function detectCodexCLI() {
|
|
|
326
327
|
name: "OpenAI Codex CLI",
|
|
327
328
|
found: true,
|
|
328
329
|
version: result.stdout,
|
|
329
|
-
path: run(
|
|
330
|
+
path: run(`${whichCmd} codex`).stdout,
|
|
330
331
|
authenticated,
|
|
331
332
|
authDetail: detail
|
|
332
333
|
};
|
|
@@ -337,7 +338,7 @@ function detectGitHubCLI() {
|
|
|
337
338
|
name: "GitHub CLI",
|
|
338
339
|
found: result.success,
|
|
339
340
|
version: result.stdout.split("\n")[0]?.replace("gh version ", "").split(" ")[0] || "",
|
|
340
|
-
path: run(
|
|
341
|
+
path: run(`${whichCmd} gh`).stdout
|
|
341
342
|
};
|
|
342
343
|
}
|
|
343
344
|
function detectGitHubAuth() {
|
|
@@ -363,6 +364,10 @@ function nodeVersionOk(version) {
|
|
|
363
364
|
const major = parseInt(version.split(".")[0], 10);
|
|
364
365
|
return major >= 18;
|
|
365
366
|
}
|
|
367
|
+
function hsCliVersionOk(version) {
|
|
368
|
+
const major = parseInt(version.split(".")[0], 10);
|
|
369
|
+
return !isNaN(major) && major >= 8;
|
|
370
|
+
}
|
|
366
371
|
function detectEnvironment() {
|
|
367
372
|
const config = loadConfig();
|
|
368
373
|
const node = detectNode();
|
|
@@ -960,13 +965,13 @@ async function setupTheme() {
|
|
|
960
965
|
themePath = join5(workspaceDir, themeName);
|
|
961
966
|
const s = await spinner2();
|
|
962
967
|
s.start("Fetching theme from HubSpot...");
|
|
963
|
-
const result = run(`hs fetch "${themeName}" "${themePath}"`);
|
|
968
|
+
const result = run(`hs cms fetch "${themeName}" "${themePath}"`);
|
|
964
969
|
if (!result.success) {
|
|
965
970
|
s.stop("Fetch failed");
|
|
966
971
|
logError(
|
|
967
972
|
`Could not fetch theme "${themeName}". Check the name in HubSpot Design Manager.`
|
|
968
973
|
);
|
|
969
|
-
logError("Run `hs list /` to see available themes.");
|
|
974
|
+
logError("Run `hs cms list /` to see available themes.");
|
|
970
975
|
process.exit(1);
|
|
971
976
|
}
|
|
972
977
|
s.stop(`Theme fetched: ${theme.dim(themePath)}`);
|
|
@@ -980,7 +985,7 @@ async function setupTheme() {
|
|
|
980
985
|
const s = await spinner2();
|
|
981
986
|
s.start("Creating theme from boilerplate...");
|
|
982
987
|
const cwdBefore = new Set(readdirSync3(process.cwd()));
|
|
983
|
-
const result = run(`hs create website-theme "${themeName}"`);
|
|
988
|
+
const result = run(`hs cms create website-theme "${themeName}"`);
|
|
984
989
|
let createdAt = join5(process.cwd(), themeName);
|
|
985
990
|
if (!fileExists(createdAt)) {
|
|
986
991
|
const cwdAfter = readdirSync3(process.cwd());
|
|
@@ -994,7 +999,7 @@ async function setupTheme() {
|
|
|
994
999
|
const errMsg = result.stderr || result.stdout || "";
|
|
995
1000
|
logError(
|
|
996
1001
|
`Could not create theme "${themeName}".` + (errMsg ? `
|
|
997
|
-
${errMsg.slice(0, 300)}` : "") + "\nTry running manually: hs create website-theme my-theme"
|
|
1002
|
+
${errMsg.slice(0, 300)}` : "") + "\nTry running manually: hs cms create website-theme my-theme"
|
|
998
1003
|
);
|
|
999
1004
|
process.exit(1);
|
|
1000
1005
|
}
|
|
@@ -2996,6 +3001,10 @@ async function doctorCommand() {
|
|
|
2996
3001
|
if (!hs.found) {
|
|
2997
3002
|
logWarn("HubSpot CLI \u2014 not installed (only needed for deployment)");
|
|
2998
3003
|
log2(" Install: npm install -g @hubspot/cli");
|
|
3004
|
+
} else if (!hsCliVersionOk(hs.version)) {
|
|
3005
|
+
logWarn(`HubSpot CLI v${hs.version} \u2014 too old (need v8+)`);
|
|
3006
|
+
log2(" Update: npm install -g @hubspot/cli@latest");
|
|
3007
|
+
issues++;
|
|
2999
3008
|
} else {
|
|
3000
3009
|
logSuccess(`HubSpot CLI v${hs.version}`);
|
|
3001
3010
|
const auth = detectHubSpotAuth();
|
|
@@ -5438,7 +5447,7 @@ function handleSetupCreateRoute(req, res) {
|
|
|
5438
5447
|
rmSync5(themePath, { recursive: true, force: true });
|
|
5439
5448
|
}
|
|
5440
5449
|
const cwdBefore = new Set(readdirSync11(process.cwd()));
|
|
5441
|
-
execSync4(`hs create website-theme "${themeName}"`, {
|
|
5450
|
+
execSync4(`hs cms create website-theme "${themeName}"`, {
|
|
5442
5451
|
encoding: "utf-8",
|
|
5443
5452
|
stdio: "pipe"
|
|
5444
5453
|
});
|
|
@@ -5479,7 +5488,7 @@ function handleSetupFetchRoute(req, res) {
|
|
|
5479
5488
|
}
|
|
5480
5489
|
const themePath = join15(WORKSPACE_DIR, name);
|
|
5481
5490
|
ensureDir(WORKSPACE_DIR);
|
|
5482
|
-
execSync4(`hs fetch "${name}" "${themePath}"`, {
|
|
5491
|
+
execSync4(`hs cms fetch "${name}" "${themePath}"`, {
|
|
5483
5492
|
encoding: "utf-8",
|
|
5484
5493
|
stdio: "pipe"
|
|
5485
5494
|
});
|