vibespot 0.4.4 → 0.5.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/assets/conversion-guide.md +28 -0
- package/assets/design-guide.md +1 -0
- package/assets/hubspot-rules.md +16 -3
- package/assets/humanify-guide.md +459 -0
- package/dist/index.js +99 -33
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/ui/chat.js +199 -55
- package/ui/dashboard.js +19 -0
- package/ui/field-editor.js +9 -7
- package/ui/index.html +58 -31
- package/ui/setup.js +117 -36
- package/ui/styles.css +678 -243
package/dist/index.js
CHANGED
|
@@ -1124,6 +1124,13 @@ function getHubspotRules() {
|
|
|
1124
1124
|
return "";
|
|
1125
1125
|
}
|
|
1126
1126
|
}
|
|
1127
|
+
function getHumanifyGuide() {
|
|
1128
|
+
try {
|
|
1129
|
+
return readFile(resolveAsset("humanify-guide.md"));
|
|
1130
|
+
} catch {
|
|
1131
|
+
return "";
|
|
1132
|
+
}
|
|
1133
|
+
}
|
|
1127
1134
|
function getPageTypeGuide(pageType) {
|
|
1128
1135
|
try {
|
|
1129
1136
|
const fullGuide = readFile(resolveAsset("page-types.md"));
|
|
@@ -1305,7 +1312,8 @@ var ClaudeCodeEngine = class {
|
|
|
1305
1312
|
const child = spawn("claude", args, {
|
|
1306
1313
|
cwd: themePath,
|
|
1307
1314
|
stdio: ["pipe", "pipe", "pipe"],
|
|
1308
|
-
env
|
|
1315
|
+
env,
|
|
1316
|
+
shell: true
|
|
1309
1317
|
});
|
|
1310
1318
|
child.stdout.on("data", (d) => {
|
|
1311
1319
|
stdout += d.toString();
|
|
@@ -1642,7 +1650,7 @@ ${guide}`;
|
|
|
1642
1650
|
|
|
1643
1651
|
// src/ai/claude-api.ts
|
|
1644
1652
|
import Anthropic from "@anthropic-ai/sdk";
|
|
1645
|
-
import { join as join7 } from "path";
|
|
1653
|
+
import { join as join7, basename as basename3 } from "path";
|
|
1646
1654
|
import { readdirSync as readdirSync5 } from "fs";
|
|
1647
1655
|
var ClaudeAPIEngine = class {
|
|
1648
1656
|
client;
|
|
@@ -1655,7 +1663,7 @@ var ClaudeAPIEngine = class {
|
|
|
1655
1663
|
async convert(opts) {
|
|
1656
1664
|
const { sourceDir, themePath, conversionGuide, onProgress } = opts;
|
|
1657
1665
|
const systemPrompt = buildSystemPrompt(conversionGuide);
|
|
1658
|
-
const dirName = sourceDir
|
|
1666
|
+
const dirName = basename3(sourceDir) || "page";
|
|
1659
1667
|
const pagePrefix = dirName.toLowerCase().replace(/[^a-z0-9]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "").slice(0, 15);
|
|
1660
1668
|
onProgress("css", "Analyzing design system...");
|
|
1661
1669
|
const indexCss = this.findAndReadCSS(sourceDir);
|
|
@@ -1835,7 +1843,8 @@ var GeminiCLIEngine = class {
|
|
|
1835
1843
|
const child = spawn2("gemini", ["-p", prompt], {
|
|
1836
1844
|
cwd: themePath,
|
|
1837
1845
|
stdio: ["pipe", "pipe", "pipe"],
|
|
1838
|
-
env: { ...process.env }
|
|
1846
|
+
env: { ...process.env },
|
|
1847
|
+
shell: true
|
|
1839
1848
|
});
|
|
1840
1849
|
let stdout = "";
|
|
1841
1850
|
let stderr = "";
|
|
@@ -1962,7 +1971,8 @@ var CodexCLIEngine = class {
|
|
|
1962
1971
|
const child = spawn3("codex", ["exec", "--full-auto", prompt], {
|
|
1963
1972
|
cwd: themePath,
|
|
1964
1973
|
stdio: ["pipe", "pipe", "pipe"],
|
|
1965
|
-
env: { ...process.env }
|
|
1974
|
+
env: { ...process.env },
|
|
1975
|
+
shell: true
|
|
1966
1976
|
});
|
|
1967
1977
|
let stdout = "";
|
|
1968
1978
|
let stderr = "";
|
|
@@ -2417,7 +2427,7 @@ function validateModuleMeta(themePath) {
|
|
|
2417
2427
|
}
|
|
2418
2428
|
|
|
2419
2429
|
// src/wizard/uploader.ts
|
|
2420
|
-
import { join as join12 } from "path";
|
|
2430
|
+
import { join as join12, basename as basename4 } from "path";
|
|
2421
2431
|
|
|
2422
2432
|
// src/server/auto-fix.ts
|
|
2423
2433
|
import { join as join11 } from "path";
|
|
@@ -2741,7 +2751,7 @@ function countUploadedFiles(output) {
|
|
|
2741
2751
|
}
|
|
2742
2752
|
async function runUpload(themePath) {
|
|
2743
2753
|
await intro2("Uploading to HubSpot");
|
|
2744
|
-
const themeName = themePath
|
|
2754
|
+
const themeName = basename4(themePath) || themePath;
|
|
2745
2755
|
const s = await spinner2();
|
|
2746
2756
|
const MAX_RETRIES = 3;
|
|
2747
2757
|
for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
|
|
@@ -2831,7 +2841,7 @@ The theme may work \u2014 check HubSpot Design Manager.`
|
|
|
2831
2841
|
// src/wizard/next-steps.ts
|
|
2832
2842
|
import { execSync as execSync2 } from "child_process";
|
|
2833
2843
|
import { rmSync as rmSync3 } from "fs";
|
|
2834
|
-
import { basename as
|
|
2844
|
+
import { basename as basename5 } from "path";
|
|
2835
2845
|
async function showNextSteps(opts) {
|
|
2836
2846
|
const { portalId, sourceDir, themePath, wasCloned } = opts;
|
|
2837
2847
|
await intro2("You're all set!");
|
|
@@ -2874,10 +2884,10 @@ Next steps:
|
|
|
2874
2884
|
}
|
|
2875
2885
|
const dirsToClean = [];
|
|
2876
2886
|
if (wasCloned && fileExists(sourceDir)) {
|
|
2877
|
-
dirsToClean.push({ path: sourceDir, label: `Cloned source (${
|
|
2887
|
+
dirsToClean.push({ path: sourceDir, label: `Cloned source (${basename5(sourceDir)})` });
|
|
2878
2888
|
}
|
|
2879
2889
|
if (fileExists(themePath)) {
|
|
2880
|
-
dirsToClean.push({ path: themePath, label: `Theme directory (${
|
|
2890
|
+
dirsToClean.push({ path: themePath, label: `Theme directory (${basename5(themePath)})` });
|
|
2881
2891
|
}
|
|
2882
2892
|
if (dirsToClean.length > 0) {
|
|
2883
2893
|
const cleanup = await confirm2({
|
|
@@ -3087,7 +3097,7 @@ import chalk2 from "chalk";
|
|
|
3087
3097
|
// src/server/server.ts
|
|
3088
3098
|
import { createServer } from "http";
|
|
3089
3099
|
import { readFileSync as readFileSync5, existsSync as existsSync5, readdirSync as readdirSync11, appendFileSync, rmSync as rmSync5, renameSync as renameSync2 } from "fs";
|
|
3090
|
-
import { join as join15, extname as extname2, basename as
|
|
3100
|
+
import { join as join15, extname as extname2, basename as basename7 } from "path";
|
|
3091
3101
|
import { homedir as homedir4 } from "os";
|
|
3092
3102
|
import { execSync as execSync4 } from "child_process";
|
|
3093
3103
|
import { WebSocketServer } from "ws";
|
|
@@ -3376,6 +3386,14 @@ function removeModule(moduleName) {
|
|
|
3376
3386
|
activeSession.updatedAt = Date.now();
|
|
3377
3387
|
syncFlatFieldsToTemplate();
|
|
3378
3388
|
}
|
|
3389
|
+
function detachModule(moduleName) {
|
|
3390
|
+
if (!activeSession) return;
|
|
3391
|
+
activeSession.moduleOrder = activeSession.moduleOrder.filter(
|
|
3392
|
+
(n) => n !== moduleName
|
|
3393
|
+
);
|
|
3394
|
+
activeSession.updatedAt = Date.now();
|
|
3395
|
+
syncFlatFieldsToTemplate();
|
|
3396
|
+
}
|
|
3379
3397
|
function updateFieldValue(moduleName, fieldPath, value) {
|
|
3380
3398
|
if (!activeSession) return;
|
|
3381
3399
|
const mod = activeSession.modules.find((m) => m.moduleName === moduleName);
|
|
@@ -3484,7 +3502,14 @@ function listSessions() {
|
|
|
3484
3502
|
return readdirSync10(SESSIONS_DIR).filter((f) => f.endsWith(".json")).map((f) => {
|
|
3485
3503
|
try {
|
|
3486
3504
|
const data = JSON.parse(readFileSync4(join14(SESSIONS_DIR, f), "utf-8"));
|
|
3487
|
-
|
|
3505
|
+
const templates = data.templates || [];
|
|
3506
|
+
return {
|
|
3507
|
+
id: data.id,
|
|
3508
|
+
themeName: data.themeName,
|
|
3509
|
+
updatedAt: data.updatedAt,
|
|
3510
|
+
moduleCount: templates.reduce((n, t) => n + (t.modules?.length || 0), 0),
|
|
3511
|
+
templateCount: templates.length
|
|
3512
|
+
};
|
|
3488
3513
|
} catch {
|
|
3489
3514
|
return null;
|
|
3490
3515
|
}
|
|
@@ -4364,19 +4389,28 @@ If the change affects shared CSS or JS, include those too.`;
|
|
|
4364
4389
|
## Page Type Context
|
|
4365
4390
|
${pageTypeSection}` : "";
|
|
4366
4391
|
let brandPrompt = "";
|
|
4367
|
-
if (!editMode
|
|
4368
|
-
if (brandAssets
|
|
4392
|
+
if (!editMode) {
|
|
4393
|
+
if (brandAssets?.styleguide) {
|
|
4369
4394
|
brandPrompt += `
|
|
4370
4395
|
|
|
4371
4396
|
## Brand Style Guide
|
|
4372
4397
|
${brandAssets.styleguide}`;
|
|
4373
4398
|
}
|
|
4374
|
-
if (brandAssets
|
|
4399
|
+
if (brandAssets?.brandvoice) {
|
|
4375
4400
|
brandPrompt += `
|
|
4376
4401
|
|
|
4377
4402
|
## Brand Voice
|
|
4378
4403
|
${brandAssets.brandvoice}`;
|
|
4379
4404
|
}
|
|
4405
|
+
if (brandAssets?.humanify !== false) {
|
|
4406
|
+
const humanifyGuide = getHumanifyGuide();
|
|
4407
|
+
if (humanifyGuide) {
|
|
4408
|
+
brandPrompt += `
|
|
4409
|
+
|
|
4410
|
+
## Anti-AI Copy Rules (Humanify)
|
|
4411
|
+
${humanifyGuide}`;
|
|
4412
|
+
}
|
|
4413
|
+
}
|
|
4380
4414
|
}
|
|
4381
4415
|
if (editMode) {
|
|
4382
4416
|
return core + pageTypePrompt + `
|
|
@@ -4714,7 +4748,8 @@ function spawnCLI(bin, args, prompt, onChunk) {
|
|
|
4714
4748
|
delete env.CLAUDECODE;
|
|
4715
4749
|
const child = spawn4(bin, args, {
|
|
4716
4750
|
stdio: ["pipe", "pipe", "pipe"],
|
|
4717
|
-
env
|
|
4751
|
+
env,
|
|
4752
|
+
shell: true
|
|
4718
4753
|
});
|
|
4719
4754
|
let stdout = "";
|
|
4720
4755
|
let stderr = "";
|
|
@@ -5295,8 +5330,12 @@ function handleModulesRoute(method, req, res) {
|
|
|
5295
5330
|
}
|
|
5296
5331
|
if (method === "DELETE") {
|
|
5297
5332
|
readBody(req, (body) => {
|
|
5298
|
-
const { moduleName } = JSON.parse(body);
|
|
5299
|
-
|
|
5333
|
+
const { moduleName, deleteEntirely } = JSON.parse(body);
|
|
5334
|
+
if (deleteEntirely) {
|
|
5335
|
+
removeModule(moduleName);
|
|
5336
|
+
} else {
|
|
5337
|
+
detachModule(moduleName);
|
|
5338
|
+
}
|
|
5300
5339
|
saveSession();
|
|
5301
5340
|
jsonResponse(res, 200, { ok: true });
|
|
5302
5341
|
});
|
|
@@ -5410,7 +5449,15 @@ function handleSetupInfoRoute(res) {
|
|
|
5410
5449
|
if (entry.isDirectory()) {
|
|
5411
5450
|
const themeJson = join15(WORKSPACE_DIR, entry.name, "theme.json");
|
|
5412
5451
|
if (existsSync5(themeJson)) {
|
|
5413
|
-
|
|
5452
|
+
let moduleCount = 0;
|
|
5453
|
+
const modulesDir = join15(WORKSPACE_DIR, entry.name, "modules");
|
|
5454
|
+
if (existsSync5(modulesDir)) {
|
|
5455
|
+
try {
|
|
5456
|
+
moduleCount = readdirSync11(modulesDir, { withFileTypes: true }).filter((e) => e.isDirectory()).length;
|
|
5457
|
+
} catch {
|
|
5458
|
+
}
|
|
5459
|
+
}
|
|
5460
|
+
localThemes.push({ name: entry.name, moduleCount });
|
|
5414
5461
|
}
|
|
5415
5462
|
}
|
|
5416
5463
|
}
|
|
@@ -5524,7 +5571,7 @@ function handleSetupOpenRoute(req, res) {
|
|
|
5524
5571
|
jsonResponse(res, 400, { error: `Theme folder not found: ${themePath}` });
|
|
5525
5572
|
return;
|
|
5526
5573
|
}
|
|
5527
|
-
const themeName =
|
|
5574
|
+
const themeName = basename7(fullPath);
|
|
5528
5575
|
createSession(fullPath, themeName);
|
|
5529
5576
|
scanThemeFromDisk(fullPath);
|
|
5530
5577
|
saveSession();
|
|
@@ -5867,17 +5914,19 @@ function handleSettingsCLIAuthRoute(req, res) {
|
|
|
5867
5914
|
const key = apiKey.trim();
|
|
5868
5915
|
process.env.OPENAI_API_KEY = key;
|
|
5869
5916
|
saveConfig({ openaiApiKey: key });
|
|
5870
|
-
|
|
5871
|
-
|
|
5872
|
-
|
|
5873
|
-
|
|
5874
|
-
|
|
5875
|
-
|
|
5917
|
+
if (process.platform !== "win32") {
|
|
5918
|
+
const profileLine = `export OPENAI_API_KEY="${key}"`;
|
|
5919
|
+
const shellProfile = process.env.SHELL?.includes("zsh") ? join15(homedir4(), ".zshrc") : join15(homedir4(), ".bashrc");
|
|
5920
|
+
try {
|
|
5921
|
+
const existing = existsSync5(shellProfile) ? readFileSync5(shellProfile, "utf-8") : "";
|
|
5922
|
+
if (!existing.includes("OPENAI_API_KEY")) {
|
|
5923
|
+
appendFileSync(shellProfile, `
|
|
5876
5924
|
# Added by vibeSpot
|
|
5877
5925
|
${profileLine}
|
|
5878
5926
|
`);
|
|
5927
|
+
}
|
|
5928
|
+
} catch {
|
|
5879
5929
|
}
|
|
5880
|
-
} catch {
|
|
5881
5930
|
}
|
|
5882
5931
|
jsonResponse(res, 200, { ok: true, message: "API key saved" });
|
|
5883
5932
|
} else {
|
|
@@ -6049,7 +6098,8 @@ function handleDashboardRoute(res) {
|
|
|
6049
6098
|
})),
|
|
6050
6099
|
brandAssets: {
|
|
6051
6100
|
hasStyleguide: !!session.brandAssets?.styleguide,
|
|
6052
|
-
hasBrandvoice: !!session.brandAssets?.brandvoice
|
|
6101
|
+
hasBrandvoice: !!session.brandAssets?.brandvoice,
|
|
6102
|
+
humanify: session.brandAssets?.humanify !== false
|
|
6053
6103
|
}
|
|
6054
6104
|
});
|
|
6055
6105
|
}
|
|
@@ -6208,15 +6258,26 @@ function handleBrandAssetsRoute(method, req, res) {
|
|
|
6208
6258
|
readBody(req, (body) => {
|
|
6209
6259
|
try {
|
|
6210
6260
|
const { type, content } = JSON.parse(body);
|
|
6211
|
-
if (!type
|
|
6212
|
-
jsonResponse(res, 400, { error: "type
|
|
6261
|
+
if (!type) {
|
|
6262
|
+
jsonResponse(res, 400, { error: "type is required" });
|
|
6263
|
+
return;
|
|
6264
|
+
}
|
|
6265
|
+
if (!session.brandAssets) session.brandAssets = {};
|
|
6266
|
+
if (type === "humanify") {
|
|
6267
|
+
session.brandAssets.humanify = content === "on";
|
|
6268
|
+
session.updatedAt = Date.now();
|
|
6269
|
+
saveSession();
|
|
6270
|
+
jsonResponse(res, 200, { ok: true });
|
|
6271
|
+
return;
|
|
6272
|
+
}
|
|
6273
|
+
if (!content) {
|
|
6274
|
+
jsonResponse(res, 400, { error: "content is required" });
|
|
6213
6275
|
return;
|
|
6214
6276
|
}
|
|
6215
6277
|
if (type !== "styleguide" && type !== "brandvoice") {
|
|
6216
6278
|
jsonResponse(res, 400, { error: `Invalid type: ${type}. Must be "styleguide" or "brandvoice"` });
|
|
6217
6279
|
return;
|
|
6218
6280
|
}
|
|
6219
|
-
if (!session.brandAssets) session.brandAssets = {};
|
|
6220
6281
|
session.brandAssets[type] = content;
|
|
6221
6282
|
session.updatedAt = Date.now();
|
|
6222
6283
|
const assetDir = join15(session.themePath, ".vibespot");
|
|
@@ -6508,8 +6569,13 @@ async function vibeCommand() {
|
|
|
6508
6569
|
console.log(accent(` v ${url}`));
|
|
6509
6570
|
console.log(dim(" Press Ctrl+C to stop\n"));
|
|
6510
6571
|
try {
|
|
6511
|
-
|
|
6512
|
-
|
|
6572
|
+
if (process.platform === "darwin") {
|
|
6573
|
+
execSync5(`open "${url}"`, { stdio: "ignore" });
|
|
6574
|
+
} else if (process.platform === "win32") {
|
|
6575
|
+
execSync5(`cmd /c start "" "${url}"`, { stdio: "ignore" });
|
|
6576
|
+
} else {
|
|
6577
|
+
execSync5(`xdg-open "${url}"`, { stdio: "ignore" });
|
|
6578
|
+
}
|
|
6513
6579
|
} catch {
|
|
6514
6580
|
}
|
|
6515
6581
|
await new Promise((resolve) => {
|