vibebusiness 1.2.89 → 1.2.91

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 (113) hide show
  1. package/.next/standalone/.next/BUILD_ID +1 -1
  2. package/.next/standalone/.next/app-build-manifest.json +37 -37
  3. package/.next/standalone/.next/app-path-routes-manifest.json +1 -1
  4. package/.next/standalone/.next/build-manifest.json +2 -2
  5. package/.next/standalone/.next/prerender-manifest.json +1 -1
  6. package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  7. package/.next/standalone/.next/server/app/_not-found.html +1 -1
  8. package/.next/standalone/.next/server/app/_not-found.rsc +1 -1
  9. package/.next/standalone/.next/server/app/api/analyze/route.js.nft.json +1 -1
  10. package/.next/standalone/.next/server/app/api/briefing/route.js.nft.json +1 -1
  11. package/.next/standalone/.next/server/app/api/config/route.js.nft.json +1 -1
  12. package/.next/standalone/.next/server/app/api/epics/[id]/ideas/route.js.nft.json +1 -1
  13. package/.next/standalone/.next/server/app/api/epics/[id]/route.js.nft.json +1 -1
  14. package/.next/standalone/.next/server/app/api/epics/route.js.nft.json +1 -1
  15. package/.next/standalone/.next/server/app/api/goals/[id]/kpis/route.js.nft.json +1 -1
  16. package/.next/standalone/.next/server/app/api/goals/[id]/route.js.nft.json +1 -1
  17. package/.next/standalone/.next/server/app/api/goals/route.js.nft.json +1 -1
  18. package/.next/standalone/.next/server/app/api/hypotheses/[id]/route.js.nft.json +1 -1
  19. package/.next/standalone/.next/server/app/api/hypotheses/route.js.nft.json +1 -1
  20. package/.next/standalone/.next/server/app/api/ideas/[id]/card/route.js.nft.json +1 -1
  21. package/.next/standalone/.next/server/app/api/ideas/[id]/comments/route.js.nft.json +1 -1
  22. package/.next/standalone/.next/server/app/api/ideas/[id]/implement/route.js.nft.json +1 -1
  23. package/.next/standalone/.next/server/app/api/ideas/[id]/route.js.nft.json +1 -1
  24. package/.next/standalone/.next/server/app/api/ideas/[id]/transition/route.js +4 -1
  25. package/.next/standalone/.next/server/app/api/ideas/[id]/transition/route.js.nft.json +1 -1
  26. package/.next/standalone/.next/server/app/api/ideas/route.js.nft.json +1 -1
  27. package/.next/standalone/.next/server/app/api/implementations/route.js.nft.json +1 -1
  28. package/.next/standalone/.next/server/app/api/kpis/refresh/route.js.nft.json +1 -1
  29. package/.next/standalone/.next/server/app/api/social/[id]/publish/route.js.nft.json +1 -1
  30. package/.next/standalone/.next/server/app/api/social/[id]/route.js.nft.json +1 -1
  31. package/.next/standalone/.next/server/app/api/social/route.js.nft.json +1 -1
  32. package/.next/standalone/.next/server/app/briefing/page_client-reference-manifest.js +1 -1
  33. package/.next/standalone/.next/server/app/goals/[id]/page_client-reference-manifest.js +1 -1
  34. package/.next/standalone/.next/server/app/goals/page.js.nft.json +1 -1
  35. package/.next/standalone/.next/server/app/goals/page_client-reference-manifest.js +1 -1
  36. package/.next/standalone/.next/server/app/hypotheses/[id]/page_client-reference-manifest.js +1 -1
  37. package/.next/standalone/.next/server/app/hypotheses/page.js.nft.json +1 -1
  38. package/.next/standalone/.next/server/app/hypotheses/page_client-reference-manifest.js +1 -1
  39. package/.next/standalone/.next/server/app/ideas/[id]/page.js.nft.json +1 -1
  40. package/.next/standalone/.next/server/app/ideas/[id]/page_client-reference-manifest.js +1 -1
  41. package/.next/standalone/.next/server/app/index.html +1 -1
  42. package/.next/standalone/.next/server/app/index.rsc +1 -1
  43. package/.next/standalone/.next/server/app/kanban/page.js.nft.json +1 -1
  44. package/.next/standalone/.next/server/app/kanban/page_client-reference-manifest.js +1 -1
  45. package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  46. package/.next/standalone/.next/server/app/roadmap/[id]/page_client-reference-manifest.js +1 -1
  47. package/.next/standalone/.next/server/app/roadmap/investors/page.js.nft.json +1 -1
  48. package/.next/standalone/.next/server/app/roadmap/investors/page_client-reference-manifest.js +1 -1
  49. package/.next/standalone/.next/server/app/roadmap/page.js.nft.json +1 -1
  50. package/.next/standalone/.next/server/app/roadmap/page_client-reference-manifest.js +1 -1
  51. package/.next/standalone/.next/server/app/roadmap/public/page.js.nft.json +1 -1
  52. package/.next/standalone/.next/server/app/roadmap/public/page_client-reference-manifest.js +1 -1
  53. package/.next/standalone/.next/server/app/sessions/page.js.nft.json +1 -1
  54. package/.next/standalone/.next/server/app/sessions/page_client-reference-manifest.js +1 -1
  55. package/.next/standalone/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  56. package/.next/standalone/.next/server/app/settings.html +1 -1
  57. package/.next/standalone/.next/server/app/settings.rsc +1 -1
  58. package/.next/standalone/.next/server/app/social/page_client-reference-manifest.js +1 -1
  59. package/.next/standalone/.next/server/app/social.html +1 -1
  60. package/.next/standalone/.next/server/app/social.rsc +2 -2
  61. package/.next/standalone/.next/server/app/updates/[id]/page.js.nft.json +1 -1
  62. package/.next/standalone/.next/server/app/updates/[id]/page_client-reference-manifest.js +1 -1
  63. package/.next/standalone/.next/server/app/updates/new/page_client-reference-manifest.js +1 -1
  64. package/.next/standalone/.next/server/app/updates/new.html +1 -1
  65. package/.next/standalone/.next/server/app/updates/new.rsc +2 -2
  66. package/.next/standalone/.next/server/app/updates/page.js.nft.json +1 -1
  67. package/.next/standalone/.next/server/app/updates/page_client-reference-manifest.js +1 -1
  68. package/.next/standalone/.next/server/app-paths-manifest.json +17 -17
  69. package/.next/standalone/.next/server/chunks/7151.js +7 -7
  70. package/.next/standalone/.next/server/pages/404.html +1 -1
  71. package/.next/standalone/.next/server/pages/500.html +1 -1
  72. package/.next/standalone/.next/server/pages-manifest.json +1 -1
  73. package/.next/standalone/.next/server/server-reference-manifest.json +1 -1
  74. package/.next/standalone/data/codebase-snapshot.json +44 -61
  75. package/.next/standalone/data/ideas.json +729 -0
  76. package/.next/standalone/data/sessions.json +32 -0
  77. package/.next/standalone/package.json +1 -1
  78. package/.next/standalone/scripts/analyze.ts +35 -4
  79. package/.next/standalone/templates/commands/growth-activate.md +64 -0
  80. package/.next/standalone/templates/commands/vision.md +68 -0
  81. package/.next/static/chunks/147-271b001e9a7f5e6c.js +1 -0
  82. package/.next/static/chunks/159-82cfa8b54cbd2c11.js +1 -0
  83. package/.next/static/chunks/47-bab84ed5cfb8fd9d.js +1 -0
  84. package/.next/static/chunks/879-ae588e66e8e0b1d0.js +1 -0
  85. package/.next/static/chunks/app/briefing/page-a38c83adfb5ef570.js +1 -0
  86. package/.next/static/chunks/app/goals/[id]/page-ce4e225f25e7294d.js +1 -0
  87. package/.next/static/chunks/app/ideas/[id]/page-6b28cf279c62a569.js +1 -0
  88. package/.next/static/chunks/app/roadmap/[id]/page-381809badf3910a3.js +1 -0
  89. package/.next/static/chunks/app/social/page-2d71af5da2476063.js +1 -0
  90. package/.next/static/chunks/app/updates/new/page-0acea8b7d66043a5.js +1 -0
  91. package/dist/scripts/analyze.js +525 -76
  92. package/dist/scripts/chat.js +10 -0
  93. package/dist/scripts/generate-idea.js +3 -0
  94. package/dist/scripts/heartbeat.js +1896 -353
  95. package/dist/scripts/implement.js +3 -0
  96. package/dist/scripts/init.js +3 -0
  97. package/dist/scripts/scan.js +3 -0
  98. package/dist/scripts/social-routine.js +3 -0
  99. package/package.json +1 -1
  100. package/templates/commands/growth-activate.md +64 -0
  101. package/templates/commands/vision.md +68 -0
  102. package/.next/static/chunks/147-b00f2ac2bbec93ae.js +0 -1
  103. package/.next/static/chunks/159-4ce492ccac6de8f7.js +0 -1
  104. package/.next/static/chunks/47-eba0f8b4f9b17641.js +0 -1
  105. package/.next/static/chunks/879-7fbd95e93ddc4636.js +0 -1
  106. package/.next/static/chunks/app/briefing/page-683aba0c52e910d7.js +0 -1
  107. package/.next/static/chunks/app/goals/[id]/page-40818dc7e710eeda.js +0 -1
  108. package/.next/static/chunks/app/ideas/[id]/page-5f33e0ecf590ddec.js +0 -1
  109. package/.next/static/chunks/app/roadmap/[id]/page-9ba8a537e30c633c.js +0 -1
  110. package/.next/static/chunks/app/social/page-21daeca0cf8af46b.js +0 -1
  111. package/.next/static/chunks/app/updates/new/page-ac5b966024ce0ddc.js +0 -1
  112. /package/.next/static/{UaMf1fmArAE78vyk_zQVK → ixOS0rCuseEALBC-pPhha}/_buildManifest.js +0 -0
  113. /package/.next/static/{UaMf1fmArAE78vyk_zQVK → ixOS0rCuseEALBC-pPhha}/_ssgManifest.js +0 -0
@@ -103,7 +103,7 @@ var require_package = __commonJS({
103
103
  var require_main = __commonJS({
104
104
  "node_modules/dotenv/lib/main.js"(exports2, module2) {
105
105
  "use strict";
106
- var fs5 = require("fs");
106
+ var fs7 = require("fs");
107
107
  var path4 = require("path");
108
108
  var os = require("os");
109
109
  var crypto3 = require("crypto");
@@ -242,7 +242,7 @@ var require_main = __commonJS({
242
242
  if (options && options.path && options.path.length > 0) {
243
243
  if (Array.isArray(options.path)) {
244
244
  for (const filepath of options.path) {
245
- if (fs5.existsSync(filepath)) {
245
+ if (fs7.existsSync(filepath)) {
246
246
  possibleVaultPath = filepath.endsWith(".vault") ? filepath : `${filepath}.vault`;
247
247
  }
248
248
  }
@@ -252,7 +252,7 @@ var require_main = __commonJS({
252
252
  } else {
253
253
  possibleVaultPath = path4.resolve(process.cwd(), ".env.vault");
254
254
  }
255
- if (fs5.existsSync(possibleVaultPath)) {
255
+ if (fs7.existsSync(possibleVaultPath)) {
256
256
  return possibleVaultPath;
257
257
  }
258
258
  return null;
@@ -305,7 +305,7 @@ var require_main = __commonJS({
305
305
  const parsedAll = {};
306
306
  for (const path5 of optionPaths) {
307
307
  try {
308
- const parsed = DotenvModule.parse(fs5.readFileSync(path5, { encoding }));
308
+ const parsed = DotenvModule.parse(fs7.readFileSync(path5, { encoding }));
309
309
  DotenvModule.populate(parsedAll, parsed, options);
310
310
  } catch (e) {
311
311
  if (debug) {
@@ -494,7 +494,7 @@ module.exports = __toCommonJS(analyze_exports);
494
494
 
495
495
  // scripts/analyze.ts
496
496
  var import_child_process2 = require("child_process");
497
- var fs4 = __toESM(require("fs"));
497
+ var fs6 = __toESM(require("fs"));
498
498
  var path3 = __toESM(require("path"));
499
499
 
500
500
  // node_modules/uuid/dist/esm-node/rng.js
@@ -1241,8 +1241,198 @@ function detectBYOKKeys() {
1241
1241
  }
1242
1242
  return null;
1243
1243
  }
1244
+ function detectProvider(config) {
1245
+ const cli = detectClaudeCLI(config?.claudePath);
1246
+ if (cli.found) {
1247
+ return {
1248
+ provider: "claude-cli",
1249
+ version: cli.version,
1250
+ message: `Found Claude Code CLI${cli.version ? ` (${cli.version})` : ""}. Using your Claude subscription for AI reasoning.`
1251
+ };
1252
+ }
1253
+ const byok = detectBYOKKeys();
1254
+ if (byok) {
1255
+ const providerNames = {
1256
+ "claude-cli": "Claude CLI",
1257
+ "anthropic-api": "Anthropic API",
1258
+ "openai-api": "OpenAI API",
1259
+ "google-api": "Google AI API"
1260
+ };
1261
+ return {
1262
+ provider: byok.provider,
1263
+ message: `Using ${providerNames[byok.provider]} key for AI reasoning.`
1264
+ };
1265
+ }
1266
+ return {
1267
+ provider: "claude-cli",
1268
+ // default, will fail at invocation
1269
+ message: "No AI provider found. Install Claude Code CLI or set an API key (ANTHROPIC_API_KEY, OPENAI_API_KEY, or GOOGLE_API_KEY)."
1270
+ };
1271
+ }
1244
1272
  var CONFIG_DIR = path.join(process.env.HOME || "", ".ai-analyst");
1245
1273
  var PROVIDER_CONFIG_FILE = path.join(CONFIG_DIR, "provider.json");
1274
+ function loadProviderConfig() {
1275
+ try {
1276
+ if (fs2.existsSync(PROVIDER_CONFIG_FILE)) {
1277
+ return JSON.parse(fs2.readFileSync(PROVIDER_CONFIG_FILE, "utf-8"));
1278
+ }
1279
+ } catch {
1280
+ }
1281
+ return null;
1282
+ }
1283
+ function invokeClaudeCLI(options, claudePath) {
1284
+ const bin = claudePath || "claude";
1285
+ const args = ["--print"];
1286
+ if (options.model) {
1287
+ args.push("--model", options.model);
1288
+ }
1289
+ if (options.jsonSchema) {
1290
+ args.push("--output-format", "json", "--json-schema", JSON.stringify(options.jsonSchema));
1291
+ }
1292
+ if (options.claudeFlags) {
1293
+ args.push(...options.claudeFlags);
1294
+ }
1295
+ const useStdin = options.useStdin !== false && options.prompt.length > 1e4;
1296
+ if (!useStdin) {
1297
+ args.push("-p", options.prompt);
1298
+ }
1299
+ const startTime = Date.now();
1300
+ const timeoutMs = options.timeoutMs || 3e5;
1301
+ return new Promise((resolve) => {
1302
+ const child = (0, import_child_process.spawn)(bin, args, {
1303
+ cwd: options.cwd || process.cwd(),
1304
+ env: process.env,
1305
+ stdio: useStdin ? ["pipe", "pipe", "pipe"] : ["ignore", "pipe", "pipe"]
1306
+ });
1307
+ let stdout = "";
1308
+ let stderr = "";
1309
+ child.stdout?.on("data", (data) => {
1310
+ stdout += data.toString();
1311
+ });
1312
+ child.stderr?.on("data", (data) => {
1313
+ stderr += data.toString();
1314
+ });
1315
+ if (useStdin && child.stdin) {
1316
+ child.stdin.write(options.prompt);
1317
+ child.stdin.end();
1318
+ }
1319
+ const timeout = setTimeout(() => {
1320
+ child.kill("SIGTERM");
1321
+ resolve({
1322
+ output: stdout,
1323
+ provider: "claude-cli",
1324
+ durationMs: Date.now() - startTime,
1325
+ error: `Timeout after ${timeoutMs}ms`
1326
+ });
1327
+ }, timeoutMs);
1328
+ child.on("close", (code) => {
1329
+ clearTimeout(timeout);
1330
+ resolve({
1331
+ output: stdout.trim(),
1332
+ provider: "claude-cli",
1333
+ durationMs: Date.now() - startTime,
1334
+ error: code !== 0 ? `Claude CLI exited with code ${code}: ${stderr}` : void 0
1335
+ });
1336
+ });
1337
+ child.on("error", (err) => {
1338
+ clearTimeout(timeout);
1339
+ resolve({
1340
+ output: "",
1341
+ provider: "claude-cli",
1342
+ durationMs: Date.now() - startTime,
1343
+ error: `Failed to spawn Claude CLI: ${err.message}`
1344
+ });
1345
+ });
1346
+ });
1347
+ }
1348
+ async function invokeAnthropicAPI(options) {
1349
+ const startTime = Date.now();
1350
+ const apiKey = process.env.ANTHROPIC_API_KEY;
1351
+ if (!apiKey) {
1352
+ return {
1353
+ output: "",
1354
+ provider: "anthropic-api",
1355
+ durationMs: 0,
1356
+ error: "ANTHROPIC_API_KEY not set"
1357
+ };
1358
+ }
1359
+ try {
1360
+ const model = options.model || "claude-sonnet-4-6";
1361
+ let prompt = options.prompt;
1362
+ if (options.jsonSchema) {
1363
+ prompt += `
1364
+
1365
+ IMPORTANT: Respond with valid JSON matching this schema:
1366
+ ${JSON.stringify(options.jsonSchema, null, 2)}
1367
+
1368
+ Output ONLY the JSON object, no markdown code blocks or other text.`;
1369
+ } else if (options.expectJson) {
1370
+ prompt += "\n\nIMPORTANT: Respond with valid JSON only. No markdown code blocks or other text.";
1371
+ }
1372
+ const response = await fetch("https://api.anthropic.com/v1/messages", {
1373
+ method: "POST",
1374
+ headers: {
1375
+ "Content-Type": "application/json",
1376
+ "x-api-key": apiKey,
1377
+ "anthropic-version": "2023-06-01"
1378
+ },
1379
+ body: JSON.stringify({
1380
+ model,
1381
+ max_tokens: 16384,
1382
+ messages: [{ role: "user", content: prompt }]
1383
+ }),
1384
+ signal: AbortSignal.timeout(options.timeoutMs || 3e5)
1385
+ });
1386
+ if (!response.ok) {
1387
+ const errorText = await response.text();
1388
+ return {
1389
+ output: "",
1390
+ provider: "anthropic-api",
1391
+ durationMs: Date.now() - startTime,
1392
+ error: `Anthropic API error ${response.status}: ${errorText}`
1393
+ };
1394
+ }
1395
+ const data = await response.json();
1396
+ const text = data.content.filter((block) => block.type === "text").map((block) => block.text).join("\n");
1397
+ return {
1398
+ output: text,
1399
+ provider: "anthropic-api",
1400
+ durationMs: Date.now() - startTime
1401
+ };
1402
+ } catch (err) {
1403
+ return {
1404
+ output: "",
1405
+ provider: "anthropic-api",
1406
+ durationMs: Date.now() - startTime,
1407
+ error: `Anthropic API call failed: ${err.message}`
1408
+ };
1409
+ }
1410
+ }
1411
+ async function invokeAI(options) {
1412
+ const savedConfig = loadProviderConfig();
1413
+ const detection = detectProvider(savedConfig || void 0);
1414
+ switch (detection.provider) {
1415
+ case "claude-cli":
1416
+ return invokeClaudeCLI(options, savedConfig?.claudePath);
1417
+ case "anthropic-api":
1418
+ return invokeAnthropicAPI(options);
1419
+ case "openai-api":
1420
+ case "google-api":
1421
+ return {
1422
+ output: "",
1423
+ provider: detection.provider,
1424
+ durationMs: 0,
1425
+ error: `${detection.provider} provider not yet implemented. Use Claude CLI or set ANTHROPIC_API_KEY.`
1426
+ };
1427
+ default:
1428
+ return {
1429
+ output: "",
1430
+ provider: "claude-cli",
1431
+ durationMs: 0,
1432
+ error: detection.message
1433
+ };
1434
+ }
1435
+ }
1246
1436
  function requireClaudeCLI(feature) {
1247
1437
  const cli = detectClaudeCLI();
1248
1438
  if (cli.found) {
@@ -1265,6 +1455,291 @@ Or set an API key: export ANTHROPIC_API_KEY=sk-ant-...`
1265
1455
  );
1266
1456
  }
1267
1457
 
1458
+ // scripts/lib/vision/define.ts
1459
+ var fs4 = __toESM(require("fs"));
1460
+
1461
+ // scripts/lib/paths.ts
1462
+ var path2 = __toESM(require("path"));
1463
+ var fs3 = __toESM(require("fs"));
1464
+ function findProjectRoot() {
1465
+ const cwd = process.cwd();
1466
+ if (fs3.existsSync(path2.join(cwd, "data", "config.json"))) {
1467
+ return cwd;
1468
+ }
1469
+ try {
1470
+ const entries = fs3.readdirSync(cwd, { withFileTypes: true });
1471
+ for (const entry of entries) {
1472
+ if (entry.isDirectory()) {
1473
+ const candidate = path2.join(cwd, entry.name, "data", "config.json");
1474
+ if (fs3.existsSync(candidate)) {
1475
+ return path2.join(cwd, entry.name);
1476
+ }
1477
+ }
1478
+ }
1479
+ } catch {
1480
+ }
1481
+ let dir = cwd;
1482
+ for (let i = 0; i < 5; i++) {
1483
+ const parent = path2.dirname(dir);
1484
+ if (parent === dir) break;
1485
+ if (fs3.existsSync(path2.join(parent, "data", "config.json"))) {
1486
+ return parent;
1487
+ }
1488
+ dir = parent;
1489
+ }
1490
+ return cwd;
1491
+ }
1492
+ var PROJECT_DIR = findProjectRoot();
1493
+ var DATA_DIR = path2.join(PROJECT_DIR, "data");
1494
+ var STATUS_FILE = path2.join(PROJECT_DIR, "STATUS.md");
1495
+ var TODO_FILE = path2.join(PROJECT_DIR, "TODO.md");
1496
+ var MEMORY_FILE = path2.join(PROJECT_DIR, "MEMORY.md");
1497
+ var IDEAS_FILE = path2.join(DATA_DIR, "ideas.json");
1498
+ var GOALS_FILE = path2.join(DATA_DIR, "goals.json");
1499
+ var SESSIONS_FILE = path2.join(DATA_DIR, "sessions.json");
1500
+ var CONFIG_FILE = path2.join(DATA_DIR, "config.json");
1501
+ var BUSINESS_CONTEXT_FILE = path2.join(DATA_DIR, "business-context.json");
1502
+ var HYPOTHESES_FILE = path2.join(DATA_DIR, "hypotheses.json");
1503
+ var IMPLEMENTATIONS_FILE = path2.join(DATA_DIR, "implementations.json");
1504
+ var ROADMAP_FILE = path2.join(DATA_DIR, "roadmap.json");
1505
+ var PRODUCT_VISION_FILE = path2.join(DATA_DIR, "product-vision.json");
1506
+ var COMPETITORS_FILE = path2.join(DATA_DIR, "competitors.json");
1507
+ var POSITIONING_FILE = path2.join(DATA_DIR, "positioning.json");
1508
+ var PAGES_FILE = path2.join(DATA_DIR, "pages.json");
1509
+ var PAYMENTS_FILE = path2.join(DATA_DIR, "payments.json");
1510
+ var POSTHOG_FILE = path2.join(DATA_DIR, "posthog.json");
1511
+ var SOCIAL_FILE = path2.join(DATA_DIR, "social.json");
1512
+ var MARKETING_STRATEGIES_FILE = path2.join(DATA_DIR, "marketing-strategies.json");
1513
+ var CAMPAIGNS_DIR = path2.join(DATA_DIR, "campaigns");
1514
+ var TEMPLATES_DIR = path2.join(__dirname, "..", "..", "templates");
1515
+ var COMMAND_TEMPLATES_DIR = path2.join(TEMPLATES_DIR, "commands");
1516
+
1517
+ // scripts/lib/vision/define.ts
1518
+ var PROJECT_DIR2 = PRODUCT_VISION_FILE.replace(/\/data\/product-vision\.json$/, "");
1519
+ function loadJson(filePath, defaultValue) {
1520
+ try {
1521
+ if (!fs4.existsSync(filePath)) return defaultValue;
1522
+ return JSON.parse(fs4.readFileSync(filePath, "utf-8"));
1523
+ } catch {
1524
+ return defaultValue;
1525
+ }
1526
+ }
1527
+ function saveJson(filePath, data) {
1528
+ fs4.writeFileSync(filePath, JSON.stringify(data, null, 2) + "\n");
1529
+ }
1530
+ function loadProductVision() {
1531
+ if (!fs4.existsSync(PRODUCT_VISION_FILE)) return null;
1532
+ try {
1533
+ return JSON.parse(fs4.readFileSync(PRODUCT_VISION_FILE, "utf-8"));
1534
+ } catch {
1535
+ return null;
1536
+ }
1537
+ }
1538
+ async function generateProductVision() {
1539
+ const positioning = loadJson(POSITIONING_FILE, null);
1540
+ const businessContext = loadJson(BUSINESS_CONTEXT_FILE, null);
1541
+ const competitors = loadJson(COMPETITORS_FILE, null);
1542
+ const existingVision = loadProductVision();
1543
+ const prompt = buildVisionPrompt(positioning, businessContext, competitors, existingVision);
1544
+ const aiResult = await invokeAI({
1545
+ prompt,
1546
+ cwd: PROJECT_DIR2,
1547
+ timeoutMs: 18e4,
1548
+ useStdin: true,
1549
+ expectJson: true
1550
+ });
1551
+ if (aiResult.error || !aiResult.output.trim()) {
1552
+ console.error(`Vision generation failed: ${aiResult.error || "empty output"}`);
1553
+ return null;
1554
+ }
1555
+ let vision = null;
1556
+ try {
1557
+ const raw = aiResult.output.trim();
1558
+ const jsonMatch = raw.match(/```(?:json)?\s*([\s\S]*?)```/);
1559
+ const jsonStr = jsonMatch ? jsonMatch[1].trim() : raw;
1560
+ vision = JSON.parse(jsonStr);
1561
+ } catch {
1562
+ console.error("Failed to parse vision JSON from AI output");
1563
+ return null;
1564
+ }
1565
+ vision.last_updated = (/* @__PURE__ */ new Date()).toISOString();
1566
+ vision.version = existingVision ? (existingVision.version || 0) + 1 : 1;
1567
+ saveJson(PRODUCT_VISION_FILE, vision);
1568
+ return vision;
1569
+ }
1570
+ async function deriveHypothesesFromVision(vision) {
1571
+ const prompt = `You are a product strategist. Given this product vision, derive 5-8 testable business hypotheses.
1572
+
1573
+ PRODUCT VISION:
1574
+ - One-liner: ${vision.one_liner}
1575
+ - Focus metric: ${vision.focus_metric}
1576
+ - Best-fit customers: ${vision.obviously_awesome.best_fit_customers.primary}
1577
+ - Value delivered: ${vision.obviously_awesome.value_delivered.join(", ")}
1578
+ - Problem (external): ${vision.storybrand.problem.external}
1579
+ - Problem (internal): ${vision.storybrand.problem.internal}
1580
+ - Success transformation: ${vision.storybrand.success.transformation}
1581
+ - Anti-goals: ${vision.anti_goals.join(", ")}
1582
+
1583
+ Each hypothesis should be:
1584
+ - Specific and falsifiable ("If we build X, then Y will happen")
1585
+ - Tied to a funnel stage (acquisition, engagement, conversion, monetization)
1586
+ - Have clear validation criteria
1587
+
1588
+ Respond with JSON only (no markdown):
1589
+ [
1590
+ {
1591
+ "title": "Short title",
1592
+ "statement": "If we [action], then [outcome] because [reason]",
1593
+ "description": "Detailed explanation",
1594
+ "funnel_stage": "acquisition|engagement|conversion|monetization",
1595
+ "priority": "critical|high|medium|low",
1596
+ "effort_to_test": "xs|s|m|l|xl",
1597
+ "validation_criteria": ["criteria 1", "criteria 2"]
1598
+ }
1599
+ ]`;
1600
+ const aiResult = await invokeAI({
1601
+ prompt,
1602
+ cwd: PROJECT_DIR2,
1603
+ timeoutMs: 12e4,
1604
+ useStdin: true,
1605
+ expectJson: true
1606
+ });
1607
+ if (aiResult.error || !aiResult.output.trim()) {
1608
+ console.error(`Hypothesis derivation failed: ${aiResult.error || "empty output"}`);
1609
+ return [];
1610
+ }
1611
+ try {
1612
+ const raw = aiResult.output.trim();
1613
+ const jsonMatch = raw.match(/```(?:json)?\s*([\s\S]*?)```/);
1614
+ const jsonStr = jsonMatch ? jsonMatch[1].trim() : raw;
1615
+ return JSON.parse(jsonStr);
1616
+ } catch {
1617
+ console.error("Failed to parse hypotheses JSON");
1618
+ return [];
1619
+ }
1620
+ }
1621
+ function buildVisionPrompt(positioning, businessContext, competitors, existingVision) {
1622
+ const sections = [];
1623
+ sections.push(`You are a product strategist. Generate a structured product vision using two proven frameworks:
1624
+
1625
+ 1. **Obviously Awesome** (April Dunford) \u2014 5-step positioning:
1626
+ - Competitive alternatives: What would customers do if you didn't exist?
1627
+ - Unique attributes: What capabilities do you have that alternatives lack?
1628
+ - Value: What value do those attributes enable?
1629
+ - Best-fit customers: Who cares most about that value?
1630
+ - Market category: What context makes your value obvious?
1631
+
1632
+ 2. **StoryBrand** (Donald Miller) \u2014 7-part narrative:
1633
+ - Character: The customer \u2014 who are they, what do they want?
1634
+ - Problem: External (tangible), Internal (emotional), Philosophical (why it matters)
1635
+ - Guide: You \u2014 empathy + authority
1636
+ - Plan: 3 simple steps to succeed
1637
+ - Call to Action: Direct CTA + transitional CTA
1638
+ - Failure: What happens if they don't act
1639
+ - Success: The transformation (before \u2192 after)`);
1640
+ if (businessContext) {
1641
+ sections.push(`
1642
+ BUSINESS CONTEXT:
1643
+ Product: ${businessContext.product?.name || "Unknown"} \u2014 ${businessContext.product?.summary || ""}
1644
+ Funnels: ${JSON.stringify(businessContext.funnels?.map((f) => ({ name: f.name, status: f.status })) || [])}
1645
+ Monetization: MRR ${businessContext.monetization?.current_mrr || 0}, ${businessContext.monetization?.paying_lawyers || 0} paying customers
1646
+ Key constraints: ${businessContext.key_constraints?.join(", ") || "none"}`);
1647
+ }
1648
+ if (positioning) {
1649
+ sections.push(`
1650
+ EXISTING POSITIONING:
1651
+ Tagline: ${positioning.current?.tagline || "none"}
1652
+ Value prop: ${positioning.current?.value_proposition || "none"}
1653
+ Target audience: ${JSON.stringify(positioning.current?.target_audience || {})}
1654
+ Differentiators: ${positioning.current?.differentiators?.join(", ") || "none"}`);
1655
+ }
1656
+ if (competitors?.competitors?.length) {
1657
+ const topCompetitors = competitors.competitors.slice(0, 5);
1658
+ sections.push(`
1659
+ COMPETITORS:
1660
+ ${topCompetitors.map((c) => `- ${c.name}: ${c.positioning?.value_proposition || "unknown"}`).join("\n")}`);
1661
+ }
1662
+ if (existingVision) {
1663
+ sections.push(`
1664
+ EXISTING VISION (v${existingVision.version}, refresh this):
1665
+ One-liner: ${existingVision.one_liner}
1666
+ Focus metric: ${existingVision.focus_metric}`);
1667
+ }
1668
+ sections.push(`
1669
+ Respond with JSON only (no markdown code blocks, just raw JSON):
1670
+ {
1671
+ "last_updated": "${(/* @__PURE__ */ new Date()).toISOString()}",
1672
+ "version": ${existingVision ? (existingVision.version || 0) + 1 : 1},
1673
+ "obviously_awesome": {
1674
+ "competitive_alternatives": ["alt1", "alt2", ...],
1675
+ "unique_attributes": ["attr1", "attr2", ...],
1676
+ "value_delivered": ["value1", "value2", ...],
1677
+ "best_fit_customers": { "primary": "...", "characteristics": ["...", "..."] },
1678
+ "market_category": "...",
1679
+ "positioning_statement": "..."
1680
+ },
1681
+ "storybrand": {
1682
+ "character": { "identity": "...", "desire": "..." },
1683
+ "problem": { "external": "...", "internal": "...", "philosophical": "..." },
1684
+ "guide": { "empathy": "...", "authority": "..." },
1685
+ "plan": ["step 1", "step 2", "step 3"],
1686
+ "call_to_action": { "direct": "...", "transitional": "..." },
1687
+ "failure": "...",
1688
+ "success": { "transformation": "...", "before": "...", "after": "..." }
1689
+ },
1690
+ "one_liner": "For [best_fit_customers] who [problem], [product] is the [category] that [value]. Unlike [alternatives], we [unique_attributes].",
1691
+ "focus_metric": "The ONE metric that proves this vision is working",
1692
+ "anti_goals": ["Things we explicitly will NOT build"]
1693
+ }`);
1694
+ return sections.join("\n");
1695
+ }
1696
+
1697
+ // scripts/lib/vision/hypotheses.ts
1698
+ var fs5 = __toESM(require("fs"));
1699
+ function loadJson2(filePath, defaultValue) {
1700
+ try {
1701
+ if (!fs5.existsSync(filePath)) return defaultValue;
1702
+ return JSON.parse(fs5.readFileSync(filePath, "utf-8"));
1703
+ } catch {
1704
+ return defaultValue;
1705
+ }
1706
+ }
1707
+ function saveJson2(filePath, data) {
1708
+ fs5.writeFileSync(filePath, JSON.stringify(data, null, 2) + "\n");
1709
+ }
1710
+ async function seedHypothesesFromVision(vision) {
1711
+ const v = vision || loadProductVision();
1712
+ if (!v) {
1713
+ console.error("No product vision found. Run /vision first.");
1714
+ return [];
1715
+ }
1716
+ const derived = await deriveHypothesesFromVision(v);
1717
+ if (derived.length === 0) return [];
1718
+ const store = loadJson2(HYPOTHESES_FILE, { hypotheses: [] });
1719
+ const now = (/* @__PURE__ */ new Date()).toISOString();
1720
+ const newHypotheses = derived.map((h, i) => ({
1721
+ id: `hyp-vision-${Date.now().toString(36)}-${i}`,
1722
+ created_at: now,
1723
+ updated_at: now,
1724
+ title: h.title,
1725
+ statement: h.statement,
1726
+ description: h.description,
1727
+ funnel_stage: h.funnel_stage,
1728
+ priority: h.priority || "medium",
1729
+ status: "stated",
1730
+ evidence_for: [],
1731
+ evidence_against: [],
1732
+ validation_criteria: h.validation_criteria || [],
1733
+ validation_ideas: [],
1734
+ reference_model: "product-vision",
1735
+ effort_to_test: h.effort_to_test || "m",
1736
+ tags: ["vision-derived"]
1737
+ }));
1738
+ store.hypotheses.push(...newHypotheses);
1739
+ saveJson2(HYPOTHESES_FILE, store);
1740
+ return newHypotheses;
1741
+ }
1742
+
1268
1743
  // scripts/lib/logger.ts
1269
1744
  function logError(context, error) {
1270
1745
  const entry = {
@@ -1585,59 +2060,6 @@ function formatValueSummary(ideas, analysisType, durationSeconds, repoName) {
1585
2060
  }
1586
2061
  }
1587
2062
 
1588
- // scripts/lib/paths.ts
1589
- var path2 = __toESM(require("path"));
1590
- var fs3 = __toESM(require("fs"));
1591
- function findProjectRoot() {
1592
- const cwd = process.cwd();
1593
- if (fs3.existsSync(path2.join(cwd, "data", "config.json"))) {
1594
- return cwd;
1595
- }
1596
- try {
1597
- const entries = fs3.readdirSync(cwd, { withFileTypes: true });
1598
- for (const entry of entries) {
1599
- if (entry.isDirectory()) {
1600
- const candidate = path2.join(cwd, entry.name, "data", "config.json");
1601
- if (fs3.existsSync(candidate)) {
1602
- return path2.join(cwd, entry.name);
1603
- }
1604
- }
1605
- }
1606
- } catch {
1607
- }
1608
- let dir = cwd;
1609
- for (let i = 0; i < 5; i++) {
1610
- const parent = path2.dirname(dir);
1611
- if (parent === dir) break;
1612
- if (fs3.existsSync(path2.join(parent, "data", "config.json"))) {
1613
- return parent;
1614
- }
1615
- dir = parent;
1616
- }
1617
- return cwd;
1618
- }
1619
- var PROJECT_DIR = findProjectRoot();
1620
- var DATA_DIR = path2.join(PROJECT_DIR, "data");
1621
- var STATUS_FILE = path2.join(PROJECT_DIR, "STATUS.md");
1622
- var TODO_FILE = path2.join(PROJECT_DIR, "TODO.md");
1623
- var MEMORY_FILE = path2.join(PROJECT_DIR, "MEMORY.md");
1624
- var IDEAS_FILE = path2.join(DATA_DIR, "ideas.json");
1625
- var GOALS_FILE = path2.join(DATA_DIR, "goals.json");
1626
- var SESSIONS_FILE = path2.join(DATA_DIR, "sessions.json");
1627
- var CONFIG_FILE = path2.join(DATA_DIR, "config.json");
1628
- var BUSINESS_CONTEXT_FILE = path2.join(DATA_DIR, "business-context.json");
1629
- var HYPOTHESES_FILE = path2.join(DATA_DIR, "hypotheses.json");
1630
- var IMPLEMENTATIONS_FILE = path2.join(DATA_DIR, "implementations.json");
1631
- var ROADMAP_FILE = path2.join(DATA_DIR, "roadmap.json");
1632
- var COMPETITORS_FILE = path2.join(DATA_DIR, "competitors.json");
1633
- var POSITIONING_FILE = path2.join(DATA_DIR, "positioning.json");
1634
- var PAGES_FILE = path2.join(DATA_DIR, "pages.json");
1635
- var PAYMENTS_FILE = path2.join(DATA_DIR, "payments.json");
1636
- var POSTHOG_FILE = path2.join(DATA_DIR, "posthog.json");
1637
- var SOCIAL_FILE = path2.join(DATA_DIR, "social.json");
1638
- var TEMPLATES_DIR = path2.join(__dirname, "..", "..", "templates");
1639
- var COMMAND_TEMPLATES_DIR = path2.join(TEMPLATES_DIR, "commands");
1640
-
1641
2063
  // scripts/analyze.ts
1642
2064
  function parseArgs() {
1643
2065
  const args = process.argv.slice(2);
@@ -1647,7 +2069,7 @@ function parseArgs() {
1647
2069
  for (const arg of args) {
1648
2070
  if (arg.startsWith("--type=")) {
1649
2071
  const value = arg.split("=")[1];
1650
- if (["quick", "deep", "metrics", "seo", "research", "growth"].includes(value)) {
2072
+ if (["quick", "deep", "metrics", "seo", "research", "growth", "vision"].includes(value)) {
1651
2073
  type = value;
1652
2074
  }
1653
2075
  } else if (arg.startsWith("--topic=")) {
@@ -1659,35 +2081,35 @@ function parseArgs() {
1659
2081
  return { type, topic, context };
1660
2082
  }
1661
2083
  function loadConfig() {
1662
- if (!fs4.existsSync(CONFIG_FILE)) {
2084
+ if (!fs6.existsSync(CONFIG_FILE)) {
1663
2085
  throw new Error("Config file not found. Please ensure data/config.json exists.");
1664
2086
  }
1665
- return JSON.parse(fs4.readFileSync(CONFIG_FILE, "utf-8"));
2087
+ return JSON.parse(fs6.readFileSync(CONFIG_FILE, "utf-8"));
1666
2088
  }
1667
2089
  function loadBusinessContext() {
1668
- if (!fs4.existsSync(BUSINESS_CONTEXT_FILE)) {
2090
+ if (!fs6.existsSync(BUSINESS_CONTEXT_FILE)) {
1669
2091
  return void 0;
1670
2092
  }
1671
2093
  try {
1672
- return JSON.parse(fs4.readFileSync(BUSINESS_CONTEXT_FILE, "utf-8"));
2094
+ return JSON.parse(fs6.readFileSync(BUSINESS_CONTEXT_FILE, "utf-8"));
1673
2095
  } catch {
1674
2096
  return void 0;
1675
2097
  }
1676
2098
  }
1677
2099
  function loadIdeas() {
1678
- if (!fs4.existsSync(IDEAS_FILE)) {
2100
+ if (!fs6.existsSync(IDEAS_FILE)) {
1679
2101
  return { ideas: [] };
1680
2102
  }
1681
- return JSON.parse(fs4.readFileSync(IDEAS_FILE, "utf-8"));
2103
+ return JSON.parse(fs6.readFileSync(IDEAS_FILE, "utf-8"));
1682
2104
  }
1683
2105
  function saveIdeas(data) {
1684
2106
  atomicWriteFileSync(IDEAS_FILE, JSON.stringify(data, null, 2));
1685
2107
  }
1686
2108
  function loadSessions() {
1687
- if (!fs4.existsSync(SESSIONS_FILE)) {
2109
+ if (!fs6.existsSync(SESSIONS_FILE)) {
1688
2110
  return { sessions: [] };
1689
2111
  }
1690
- return JSON.parse(fs4.readFileSync(SESSIONS_FILE, "utf-8"));
2112
+ return JSON.parse(fs6.readFileSync(SESSIONS_FILE, "utf-8"));
1691
2113
  }
1692
2114
  function saveSessions(data) {
1693
2115
  atomicWriteFileSync(SESSIONS_FILE, JSON.stringify(data, null, 2));
@@ -1773,8 +2195,8 @@ function flushSessionLogs(sessionId) {
1773
2195
  }
1774
2196
  function loadGoalsContext() {
1775
2197
  try {
1776
- if (!fs4.existsSync(GOALS_FILE)) return "";
1777
- const goalsData = JSON.parse(fs4.readFileSync(GOALS_FILE, "utf-8"));
2198
+ if (!fs6.existsSync(GOALS_FILE)) return "";
2199
+ const goalsData = JSON.parse(fs6.readFileSync(GOALS_FILE, "utf-8"));
1778
2200
  const goals = goalsData.goals || [];
1779
2201
  if (goals.length === 0) return "";
1780
2202
  return goals.map((g) => {
@@ -1792,8 +2214,8 @@ function linkIdeasToHypotheses(ideas) {
1792
2214
  const ideasWithHypothesis = ideas.filter((i) => i.hypothesis_id);
1793
2215
  if (ideasWithHypothesis.length === 0) return;
1794
2216
  try {
1795
- if (!fs4.existsSync(HYPOTHESES_FILE)) return;
1796
- const data = JSON.parse(fs4.readFileSync(HYPOTHESES_FILE, "utf-8"));
2217
+ if (!fs6.existsSync(HYPOTHESES_FILE)) return;
2218
+ const data = JSON.parse(fs6.readFileSync(HYPOTHESES_FILE, "utf-8"));
1797
2219
  const hypotheses = data.hypotheses || [];
1798
2220
  let changed = false;
1799
2221
  for (const idea of ideasWithHypothesis) {
@@ -1817,8 +2239,8 @@ function linkIdeasToHypotheses(ideas) {
1817
2239
  }
1818
2240
  function matchNewIdeasToEpics(newIdeas, ideasData) {
1819
2241
  try {
1820
- if (!fs4.existsSync(ROADMAP_FILE)) return;
1821
- const roadmapData = JSON.parse(fs4.readFileSync(ROADMAP_FILE, "utf-8"));
2242
+ if (!fs6.existsSync(ROADMAP_FILE)) return;
2243
+ const roadmapData = JSON.parse(fs6.readFileSync(ROADMAP_FILE, "utf-8"));
1822
2244
  const epics = roadmapData.epics || [];
1823
2245
  if (epics.length === 0) return;
1824
2246
  let matched = 0;
@@ -1852,8 +2274,8 @@ function matchNewIdeasToEpics(newIdeas, ideasData) {
1852
2274
  }
1853
2275
  function loadHypothesesContext() {
1854
2276
  try {
1855
- if (!fs4.existsSync(HYPOTHESES_FILE)) return "";
1856
- const data = JSON.parse(fs4.readFileSync(HYPOTHESES_FILE, "utf-8"));
2277
+ if (!fs6.existsSync(HYPOTHESES_FILE)) return "";
2278
+ const data = JSON.parse(fs6.readFileSync(HYPOTHESES_FILE, "utf-8"));
1857
2279
  const hypotheses = data.hypotheses || [];
1858
2280
  if (hypotheses.length === 0) return "";
1859
2281
  return hypotheses.filter((h) => h.status === "stated" || h.status === "testing").map(
@@ -2160,7 +2582,7 @@ Return ONLY this JSON structure (no markdown code blocks):
2160
2582
  const jsonMatch = output.match(/\{[\s\S]*\}/);
2161
2583
  if (jsonMatch) {
2162
2584
  const snapshot = JSON.parse(jsonMatch[0]);
2163
- fs4.writeFileSync(snapshotPath, JSON.stringify(snapshot, null, 2));
2585
+ fs6.writeFileSync(snapshotPath, JSON.stringify(snapshot, null, 2));
2164
2586
  console.log(`Codebase snapshot saved to ${snapshotPath}`);
2165
2587
  }
2166
2588
  } catch (error) {
@@ -2183,6 +2605,33 @@ async function main() {
2183
2605
  if (type === "research" && topic) {
2184
2606
  console.log(`Research topic: ${topic}`);
2185
2607
  }
2608
+ if (type === "vision") {
2609
+ console.log("Generating product vision (Obviously Awesome + StoryBrand)...\n");
2610
+ const vision = await generateProductVision();
2611
+ if (!vision) {
2612
+ console.error("Vision generation failed");
2613
+ process.exit(1);
2614
+ }
2615
+ console.log(`
2616
+ \u2713 Vision saved to data/product-vision.json (v${vision.version})`);
2617
+ console.log(` One-liner: ${vision.one_liner}`);
2618
+ console.log(` Focus metric: ${vision.focus_metric}`);
2619
+ console.log(` Anti-goals: ${vision.anti_goals.join(", ")}
2620
+ `);
2621
+ console.log("Deriving hypotheses from vision...");
2622
+ const hypotheses = await seedHypothesesFromVision(vision);
2623
+ if (hypotheses.length > 0) {
2624
+ console.log(`\u2713 ${hypotheses.length} hypotheses seeded to data/hypotheses.json
2625
+ `);
2626
+ for (const h of hypotheses) {
2627
+ console.log(` - [${h.funnel_stage}] ${h.title}`);
2628
+ }
2629
+ } else {
2630
+ console.log(" No hypotheses generated (you can add them manually)");
2631
+ }
2632
+ console.log("\n=== Vision Analysis Complete ===");
2633
+ return;
2634
+ }
2186
2635
  const config = loadConfig();
2187
2636
  console.log(`Analyzing ${config.repos.length} repositories...`);
2188
2637
  const session = createSession(type, config.repos.map((r) => r.name));