@bobsworkshop/cli 0.7.0 → 0.7.2

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/dist/bob.js CHANGED
@@ -1,27 +1,37 @@
1
- #!/usr/bin/env node
2
1
  import {
3
2
  buildLocalContext,
4
3
  callCloudFunction,
5
4
  callLocalModel,
5
+ completeTask,
6
+ createAnalysisRun,
7
+ ensureProjectStructure,
6
8
  extractAllProposedFiles,
7
9
  extractProposedFile,
10
+ getActiveConversationId,
8
11
  getConfig,
9
12
  getConfigPath,
13
+ getProjectName,
10
14
  isAuthenticated,
15
+ loadDependencies,
11
16
  loadLocalSuggestions,
17
+ loadSummaries,
12
18
  markSuggestionStatus,
13
19
  processAllProposedFiles,
14
20
  proposeAndWriteFile,
15
21
  readFileContent,
16
22
  registerLoginCommand,
23
+ saveDependencies,
24
+ saveSummaries,
25
+ setActiveConversationId,
17
26
  setConfigValue,
18
- stripCodeBlockFromResponse
19
- } from "./chunk-WXLT3UL7.js";
27
+ stripCodeBlockFromResponse,
28
+ updateManifestProgress
29
+ } from "./chunk-NUMFL5IZ.js";
20
30
 
21
31
  // bin/bob.ts
22
32
  import { Command } from "commander";
23
33
  import chalk25 from "chalk";
24
- import * as path14 from "path";
34
+ import * as path13 from "path";
25
35
 
26
36
  // src/commands/config.ts
27
37
  import chalk from "chalk";
@@ -109,8 +119,8 @@ function registerConfigCommand(program2) {
109
119
 
110
120
  // src/commands/chat.ts
111
121
  import chalk9 from "chalk";
112
- import * as fs6 from "fs";
113
- import * as path7 from "path";
122
+ import * as fs5 from "fs";
123
+ import * as path6 from "path";
114
124
  import * as readline2 from "readline";
115
125
 
116
126
  // src/core/profile-store.ts
@@ -356,143 +366,24 @@ Do NOT mention that you are adapting to their profile. Do NOT reference this sec
356
366
  }
357
367
 
358
368
  // src/core/conversation-store.ts
359
- import * as fs3 from "fs";
360
- import * as path3 from "path";
361
-
362
- // src/core/project-map.ts
363
369
  import * as fs2 from "fs";
364
370
  import * as path2 from "path";
365
- import * as os2 from "os";
366
- var BOB_DIR2 = path2.join(os2.homedir(), ".bob");
367
- var PROJECTS_DIR = path2.join(BOB_DIR2, "projects");
368
- function getProjectName(workingDir) {
369
- return path2.basename(workingDir);
370
- }
371
- function getProjectDir(workingDir) {
372
- const name = getProjectName(workingDir);
373
- return path2.join(PROJECTS_DIR, name);
374
- }
375
- function ensureProjectStructure(workingDir) {
376
- const projectDir = getProjectDir(workingDir);
377
- const conversationsDir = path2.join(projectDir, "conversations");
378
- const analysisDir = path2.join(projectDir, "analysis");
379
- const runsDir = path2.join(analysisDir, "runs");
380
- for (const dir of [BOB_DIR2, PROJECTS_DIR, projectDir, conversationsDir, analysisDir, runsDir]) {
381
- if (!fs2.existsSync(dir)) fs2.mkdirSync(dir, { recursive: true });
382
- }
383
- const metaPath = path2.join(projectDir, "project.json");
384
- if (!fs2.existsSync(metaPath)) {
385
- const meta = {
386
- name: getProjectName(workingDir),
387
- path: workingDir,
388
- createdAt: (/* @__PURE__ */ new Date()).toISOString(),
389
- lastIndexed: null
390
- };
391
- fs2.writeFileSync(metaPath, JSON.stringify(meta, null, 2));
392
- }
393
- return { projectDir, conversationsDir, analysisDir, runsDir };
394
- }
395
- function createAnalysisRun(workingDir, files) {
396
- const { runsDir } = ensureProjectStructure(workingDir);
397
- const runId = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
398
- const runDir = path2.join(runsDir, runId);
399
- const tasksDir = path2.join(runDir, "tasks");
400
- fs2.mkdirSync(runDir, { recursive: true });
401
- fs2.mkdirSync(tasksDir, { recursive: true });
402
- const manifest = {
403
- runId,
404
- status: "in_progress",
405
- totalFiles: files.length,
406
- completedFiles: 0,
407
- createdAt: (/* @__PURE__ */ new Date()).toISOString(),
408
- projectPath: workingDir
409
- };
410
- fs2.writeFileSync(path2.join(runDir, "manifest.json"), JSON.stringify(manifest, null, 2));
411
- for (const filePath of files) {
412
- const taskId = filePath.replace(/[\/\\]/g, "_");
413
- const task = {
414
- filePath,
415
- status: false,
416
- summary: null,
417
- dependencies: [],
418
- error: null
419
- };
420
- fs2.writeFileSync(path2.join(tasksDir, `${taskId}.json`), JSON.stringify(task, null, 2));
421
- }
422
- return { runId, runDir, tasksDir };
423
- }
424
- function completeTask(tasksDir, filePath, summary) {
425
- const taskId = filePath.replace(/[\/\\]/g, "_");
426
- const taskPath = path2.join(tasksDir, `${taskId}.json`);
427
- if (fs2.existsSync(taskPath)) {
428
- const task = JSON.parse(fs2.readFileSync(taskPath, "utf-8"));
429
- task.status = true;
430
- task.summary = summary;
431
- fs2.writeFileSync(taskPath, JSON.stringify(task, null, 2));
432
- }
433
- }
434
- function updateManifestProgress(runDir, completedFiles, status) {
435
- const manifestPath = path2.join(runDir, "manifest.json");
436
- if (fs2.existsSync(manifestPath)) {
437
- const manifest = JSON.parse(fs2.readFileSync(manifestPath, "utf-8"));
438
- manifest.completedFiles = completedFiles;
439
- if (status) manifest.status = status;
440
- fs2.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2));
441
- }
442
- }
443
- function saveSummaries(workingDir, summaries) {
444
- const { analysisDir } = ensureProjectStructure(workingDir);
445
- fs2.writeFileSync(path2.join(analysisDir, "summaries.json"), JSON.stringify(summaries, null, 2));
446
- const projectDir = getProjectDir(workingDir);
447
- const metaPath = path2.join(projectDir, "project.json");
448
- if (fs2.existsSync(metaPath)) {
449
- const meta = JSON.parse(fs2.readFileSync(metaPath, "utf-8"));
450
- meta.lastIndexed = (/* @__PURE__ */ new Date()).toISOString();
451
- fs2.writeFileSync(metaPath, JSON.stringify(meta, null, 2));
452
- }
453
- }
454
- function saveDependencies(workingDir, dependencies) {
455
- const { analysisDir } = ensureProjectStructure(workingDir);
456
- fs2.writeFileSync(path2.join(analysisDir, "dependencies.json"), JSON.stringify(dependencies, null, 2));
457
- }
458
- function loadSummaries(workingDir) {
459
- const { analysisDir } = ensureProjectStructure(workingDir);
460
- const summariesPath = path2.join(analysisDir, "summaries.json");
461
- if (!fs2.existsSync(summariesPath)) return null;
462
- try {
463
- return JSON.parse(fs2.readFileSync(summariesPath, "utf-8"));
464
- } catch {
465
- return null;
466
- }
467
- }
468
- function loadDependencies(workingDir) {
469
- const { analysisDir } = ensureProjectStructure(workingDir);
470
- const depsPath = path2.join(analysisDir, "dependencies.json");
471
- if (!fs2.existsSync(depsPath)) return null;
472
- try {
473
- return JSON.parse(fs2.readFileSync(depsPath, "utf-8"));
474
- } catch {
475
- return null;
476
- }
477
- }
478
-
479
- // src/core/conversation-store.ts
480
371
  function saveMessage(conversationId, message, meta) {
481
372
  const { conversationsDir } = ensureProjectStructure(process.cwd());
482
- const convoDir = path3.join(conversationsDir, conversationId);
483
- const messagesDir = path3.join(convoDir, "messages");
484
- if (!fs3.existsSync(convoDir)) fs3.mkdirSync(convoDir, { recursive: true });
485
- if (!fs3.existsSync(messagesDir)) fs3.mkdirSync(messagesDir, { recursive: true });
373
+ const convoDir = path2.join(conversationsDir, conversationId);
374
+ const messagesDir = path2.join(convoDir, "messages");
375
+ if (!fs2.existsSync(convoDir)) fs2.mkdirSync(convoDir, { recursive: true });
376
+ if (!fs2.existsSync(messagesDir)) fs2.mkdirSync(messagesDir, { recursive: true });
486
377
  const messageFilename = `${Date.now()}_${message.sender}.json`;
487
- fs3.writeFileSync(
488
- path3.join(messagesDir, messageFilename),
378
+ fs2.writeFileSync(
379
+ path2.join(messagesDir, messageFilename),
489
380
  JSON.stringify(message, null, 2)
490
381
  );
491
- const metaPath = path3.join(convoDir, "conversation.json");
382
+ const metaPath = path2.join(convoDir, "conversation.json");
492
383
  let convoMeta;
493
- if (fs3.existsSync(metaPath)) {
384
+ if (fs2.existsSync(metaPath)) {
494
385
  try {
495
- convoMeta = JSON.parse(fs3.readFileSync(metaPath, "utf-8"));
386
+ convoMeta = JSON.parse(fs2.readFileSync(metaPath, "utf-8"));
496
387
  } catch {
497
388
  convoMeta = createMeta(conversationId, meta);
498
389
  }
@@ -505,7 +396,7 @@ function saveMessage(conversationId, message, meta) {
505
396
  if (!convoMeta.title && message.sender === "user") {
506
397
  convoMeta.title = message.message.slice(0, 80);
507
398
  }
508
- fs3.writeFileSync(metaPath, JSON.stringify(convoMeta, null, 2));
399
+ fs2.writeFileSync(metaPath, JSON.stringify(convoMeta, null, 2));
509
400
  }
510
401
  function createMeta(conversationId, meta) {
511
402
  return {
@@ -523,8 +414,8 @@ function createMeta(conversationId, meta) {
523
414
  }
524
415
 
525
416
  // src/core/file-retrieval.ts
526
- import * as fs4 from "fs";
527
- import * as path4 from "path";
417
+ import * as fs3 from "fs";
418
+ import * as path3 from "path";
528
419
  async function getRelevantFileContents(userMessage, localEndpoint) {
529
420
  const cwd = process.cwd();
530
421
  const summaries = loadSummaries(cwd);
@@ -572,10 +463,10 @@ Return ONLY the JSON array of relevant file paths:`
572
463
  let fileContents = "## RELEVANT FILES (selected by Bob from project index) ##\n\n";
573
464
  const validFiles = [];
574
465
  for (const filePath of selectedFiles.slice(0, 10)) {
575
- const absolutePath = path4.join(cwd, filePath);
466
+ const absolutePath = path3.join(cwd, filePath);
576
467
  try {
577
- if (fs4.existsSync(absolutePath)) {
578
- const content = fs4.readFileSync(absolutePath, "utf-8");
468
+ if (fs3.existsSync(absolutePath)) {
469
+ const content = fs3.readFileSync(absolutePath, "utf-8");
579
470
  fileContents += `--- FILE: ${filePath} ---
580
471
  ${content}
581
472
  --- END FILE ---
@@ -789,8 +680,8 @@ function startDeepDiveAnimation() {
789
680
 
790
681
  // src/ui/chat-renderer.ts
791
682
  import chalk4 from "chalk";
792
- import * as fs5 from "fs";
793
- import * as path5 from "path";
683
+ import * as fs4 from "fs";
684
+ import * as path4 from "path";
794
685
  import { diffLines } from "diff";
795
686
 
796
687
  // src/ui/renderer.ts
@@ -991,8 +882,8 @@ function renderFileDiff(filePath, newContent, isNew) {
991
882
  console.log("");
992
883
  return;
993
884
  }
994
- const absolutePath = path5.join(process.cwd(), filePath);
995
- if (!fs5.existsSync(absolutePath)) {
885
+ const absolutePath = path4.join(process.cwd(), filePath);
886
+ if (!fs4.existsSync(absolutePath)) {
996
887
  const lineCount = newContent.split("\n").length;
997
888
  console.log("");
998
889
  console.log(SUCCESS(` \u25C6 Created ${filePath}`));
@@ -1000,7 +891,7 @@ function renderFileDiff(filePath, newContent, isNew) {
1000
891
  console.log("");
1001
892
  return;
1002
893
  }
1003
- const existingContent = fs5.readFileSync(absolutePath, "utf-8");
894
+ const existingContent = fs4.readFileSync(absolutePath, "utf-8");
1004
895
  const changes = diffLines(existingContent, newContent);
1005
896
  let additions = 0;
1006
897
  let removals = 0;
@@ -1152,7 +1043,8 @@ function registerDeepDiveCommand(program2) {
1152
1043
  console.log("");
1153
1044
  return;
1154
1045
  }
1155
- if (!config.conversationId) {
1046
+ const conversationId = getActiveConversationId(process.cwd()) || config.conversationId;
1047
+ if (!conversationId) {
1156
1048
  console.log("");
1157
1049
  console.log(ERROR2(" \u274C No active conversation."));
1158
1050
  console.log("");
@@ -1160,7 +1052,7 @@ function registerDeepDiveCommand(program2) {
1160
1052
  }
1161
1053
  const spinner = ora({ text: MODE_DEEPDIVE2(" Loading deep dives..."), spinner: "dots" }).start();
1162
1054
  try {
1163
- const result = await callCloudFunction("listCLIDeepDives", { conversationId: config.conversationId });
1055
+ const result = await callCloudFunction("listCLIDeepDives", { conversationId });
1164
1056
  spinner.stop();
1165
1057
  const dives = result.deepDives || [];
1166
1058
  console.log("");
@@ -1198,7 +1090,8 @@ function registerDeepDiveCommand(program2) {
1198
1090
  console.log("");
1199
1091
  return;
1200
1092
  }
1201
- if (!config.conversationId) {
1093
+ const conversationId = getActiveConversationId(process.cwd()) || config.conversationId;
1094
+ if (!conversationId) {
1202
1095
  console.log("");
1203
1096
  console.log(ERROR2(" \u274C No active conversation."));
1204
1097
  console.log("");
@@ -1206,7 +1099,7 @@ function registerDeepDiveCommand(program2) {
1206
1099
  }
1207
1100
  const spinner = ora({ text: MODE_DEEPDIVE2(" Loading deep dives..."), spinner: "dots" }).start();
1208
1101
  try {
1209
- const result = await callCloudFunction("listCLIDeepDives", { conversationId: config.conversationId });
1102
+ const result = await callCloudFunction("listCLIDeepDives", { conversationId });
1210
1103
  spinner.stop();
1211
1104
  const dives = result.deepDives || [];
1212
1105
  if (dives.length === 0) {
@@ -1246,7 +1139,7 @@ function registerDeepDiveCommand(program2) {
1246
1139
  await new Promise((resolve3) => setTimeout(resolve3, 3e3));
1247
1140
  animation.stop();
1248
1141
  await new Promise((resolve3) => setTimeout(resolve3, 300));
1249
- await runDeepDiveSession(config, config.conversationId, parentMessageId, initiatingPrompt, rl);
1142
+ await runDeepDiveSession(config, conversationId, parentMessageId, initiatingPrompt, rl);
1250
1143
  rl.close();
1251
1144
  } catch (error) {
1252
1145
  spinner.stop();
@@ -1263,7 +1156,8 @@ function registerDeepDiveCommand(program2) {
1263
1156
  console.log("");
1264
1157
  return;
1265
1158
  }
1266
- if (!config.conversationId) {
1159
+ const conversationId = getActiveConversationId(process.cwd()) || config.conversationId;
1160
+ if (!conversationId) {
1267
1161
  console.log("");
1268
1162
  console.log(ERROR2(" \u274C No active conversation."));
1269
1163
  console.log(MUTED2(" Join one with `bob conversations join` first."));
@@ -1271,7 +1165,7 @@ function registerDeepDiveCommand(program2) {
1271
1165
  return;
1272
1166
  }
1273
1167
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
1274
- await enterDeepDive(config, config.conversationId, rl);
1168
+ await enterDeepDive(config, conversationId, rl);
1275
1169
  rl.close();
1276
1170
  });
1277
1171
  }
@@ -1496,7 +1390,7 @@ Current request: ${trimmed}` : trimmed;
1496
1390
 
1497
1391
  // src/ui/session-header.ts
1498
1392
  import chalk6 from "chalk";
1499
- import * as path6 from "path";
1393
+ import * as path5 from "path";
1500
1394
  var BRAND_PRIMARY2 = chalk6.hex("#E66F24");
1501
1395
  var BRAND_SECONDARY3 = chalk6.hex("#FFAB00");
1502
1396
  var SUCCESS3 = chalk6.hex("#66BB6A");
@@ -1518,7 +1412,7 @@ function pad(content, visibleLen) {
1518
1412
  }
1519
1413
  function renderSessionHeader(mode) {
1520
1414
  const config = getConfig();
1521
- const projectName = path6.basename(process.cwd());
1415
+ const projectName = path5.basename(process.cwd());
1522
1416
  const summaries = loadSummaries(process.cwd());
1523
1417
  const fileCount = summaries ? Object.keys(summaries).length : 0;
1524
1418
  const isIndexed = fileCount > 0;
@@ -1695,9 +1589,10 @@ var lastConstraints = [];
1695
1589
  function registerChatCommand(program2) {
1696
1590
  program2.command("chat [message]").description("Chat with Bob \u2014 code-friendly engineering partner").option("-f, --file <path>", "Include a specific file as context").option("--no-context", "Skip local directory context").option("--personalized", "Use personalization mode (Tier 3 only)").option("--new", "Start a fresh conversation").option("-i, --interactive", "Enter interactive conversation mode").action(async (message, options) => {
1697
1591
  const config = getConfig();
1698
- let conversationId = config.conversationId;
1592
+ let conversationId = getActiveConversationId(process.cwd()) || config.conversationId || null;
1699
1593
  if (options.new || !conversationId) {
1700
1594
  conversationId = `cli_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
1595
+ setActiveConversationId(conversationId, process.cwd());
1701
1596
  setConfigValue("conversationId", conversationId);
1702
1597
  }
1703
1598
  let localContext = "";
@@ -1876,6 +1771,7 @@ async function runInteractiveSession(config, conversationId, localContext, perso
1876
1771
  history.length = 0;
1877
1772
  lastConstraints = [];
1878
1773
  conversationId = `cli_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
1774
+ setActiveConversationId(conversationId, process.cwd());
1879
1775
  setConfigValue("conversationId", conversationId);
1880
1776
  console.log(INFO6(" \u{1F504} New session started."));
1881
1777
  console.log("");
@@ -1912,8 +1808,8 @@ ${content}
1912
1808
  }
1913
1809
  if (trimmed.startsWith("/delete ")) {
1914
1810
  const filePath = trimmed.slice(8).trim();
1915
- const absolutePath = path7.resolve(process.cwd(), filePath);
1916
- if (!fs6.existsSync(absolutePath)) {
1811
+ const absolutePath = path6.resolve(process.cwd(), filePath);
1812
+ if (!fs5.existsSync(absolutePath)) {
1917
1813
  console.log(ERROR4(` \u274C File not found: ${filePath}`));
1918
1814
  console.log("");
1919
1815
  prompt();
@@ -1942,10 +1838,10 @@ ${content}
1942
1838
  rl.resume();
1943
1839
  if (confirm.toLowerCase() === "y" || confirm.toLowerCase() === "yes") {
1944
1840
  try {
1945
- const backupDir = path7.join(process.cwd(), ".bob-backups");
1946
- if (!fs6.existsSync(backupDir)) fs6.mkdirSync(backupDir, { recursive: true });
1947
- fs6.copyFileSync(absolutePath, path7.join(backupDir, filePath.replace(/[\/\\]/g, "_") + `.${Date.now()}.deleted`));
1948
- fs6.unlinkSync(absolutePath);
1841
+ const backupDir = path6.join(process.cwd(), ".bob-backups");
1842
+ if (!fs5.existsSync(backupDir)) fs5.mkdirSync(backupDir, { recursive: true });
1843
+ fs5.copyFileSync(absolutePath, path6.join(backupDir, filePath.replace(/[\/\\]/g, "_") + `.${Date.now()}.deleted`));
1844
+ fs5.unlinkSync(absolutePath);
1949
1845
  console.log(SUCCESS6(` \u2705 Deleted: ${filePath}`));
1950
1846
  console.log(MUTED6(` \u{1F4E6} Backup saved to .bob-backups/`));
1951
1847
  } catch (e) {
@@ -1988,9 +1884,10 @@ var lastConstraints2 = [];
1988
1884
  function registerConsultCommand(program2) {
1989
1885
  program2.command("consult [message]").description("Consult with Bob \u2014 strategic advice only, no code").option("-f, --file <path>", "Include a specific file as context").option("--no-context", "Skip local directory context").option("--new", "Start a fresh conversation").option("-i, --interactive", "Enter interactive consultant session").action(async (message, options) => {
1990
1886
  const config = getConfig();
1991
- let conversationId = config.conversationId;
1887
+ let conversationId = getActiveConversationId(process.cwd()) || config.conversationId || null;
1992
1888
  if (options.new || !conversationId) {
1993
1889
  conversationId = `cli_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
1890
+ setActiveConversationId(conversationId, process.cwd());
1994
1891
  setConfigValue("conversationId", conversationId);
1995
1892
  }
1996
1893
  let localContext = "";
@@ -2122,6 +2019,7 @@ async function runInteractiveSession2(config, conversationId, localContext) {
2122
2019
  history.length = 0;
2123
2020
  lastConstraints2 = [];
2124
2021
  conversationId = `cli_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
2022
+ setActiveConversationId(conversationId, process.cwd());
2125
2023
  setConfigValue("conversationId", conversationId);
2126
2024
  console.log(MODE_CONSULTANT4(" \u{1F504} New consultant session started."));
2127
2025
  console.log("");
@@ -2174,8 +2072,8 @@ ${content}
2174
2072
 
2175
2073
  // src/commands/index.ts
2176
2074
  import chalk11 from "chalk";
2177
- import * as fs7 from "fs";
2178
- import * as path8 from "path";
2075
+ import * as fs6 from "fs";
2076
+ import * as path7 from "path";
2179
2077
  var BRAND_PRIMARY5 = chalk11.hex("#E66F24");
2180
2078
  var BRAND_SECONDARY8 = chalk11.hex("#FFAB00");
2181
2079
  var SUCCESS8 = chalk11.hex("#66BB6A");
@@ -2218,10 +2116,10 @@ function registerIndexCommand(program2) {
2218
2116
  const summaries = {};
2219
2117
  let completed = 0;
2220
2118
  for (const filePath of files) {
2221
- const absolutePath = path8.join(cwd, filePath);
2119
+ const absolutePath = path7.join(cwd, filePath);
2222
2120
  let content;
2223
2121
  try {
2224
- content = fs7.readFileSync(absolutePath, "utf-8");
2122
+ content = fs6.readFileSync(absolutePath, "utf-8");
2225
2123
  } catch {
2226
2124
  console.log(ERROR6(` \u274C Could not read: ${filePath}`));
2227
2125
  continue;
@@ -2298,11 +2196,11 @@ Respond with ONLY the JSON object:`
2298
2196
  saveDependencies(cwd, dependencies);
2299
2197
  for (const [filePath, deps] of Object.entries(dependencies)) {
2300
2198
  const taskId = filePath.replace(/[\/\\]/g, "_");
2301
- const taskPath = path8.join(tasksDir, `${taskId}.json`);
2302
- if (fs7.existsSync(taskPath)) {
2303
- const task = JSON.parse(fs7.readFileSync(taskPath, "utf-8"));
2199
+ const taskPath = path7.join(tasksDir, `${taskId}.json`);
2200
+ if (fs6.existsSync(taskPath)) {
2201
+ const task = JSON.parse(fs6.readFileSync(taskPath, "utf-8"));
2304
2202
  task.dependencies = deps;
2305
- fs7.writeFileSync(taskPath, JSON.stringify(task, null, 2));
2203
+ fs6.writeFileSync(taskPath, JSON.stringify(task, null, 2));
2306
2204
  }
2307
2205
  }
2308
2206
  updateManifestProgress(runDir, completed, "completed");
@@ -2325,16 +2223,16 @@ function scanProjectFiles(rootDir, currentDir, depth = 0) {
2325
2223
  const dir = currentDir || rootDir;
2326
2224
  const files = [];
2327
2225
  try {
2328
- const entries = fs7.readdirSync(dir, { withFileTypes: true });
2226
+ const entries = fs6.readdirSync(dir, { withFileTypes: true });
2329
2227
  for (const entry of entries) {
2330
2228
  if (IGNORE_DIRS.includes(entry.name)) continue;
2331
2229
  if (entry.name.startsWith(".")) continue;
2332
- const fullPath = path8.join(dir, entry.name);
2333
- const relativePath = path8.relative(rootDir, fullPath).replace(/\\/g, "/");
2230
+ const fullPath = path7.join(dir, entry.name);
2231
+ const relativePath = path7.relative(rootDir, fullPath).replace(/\\/g, "/");
2334
2232
  if (entry.isDirectory()) {
2335
2233
  files.push(...scanProjectFiles(rootDir, fullPath, depth + 1));
2336
2234
  } else {
2337
- const ext = path8.extname(entry.name).toLowerCase();
2235
+ const ext = path7.extname(entry.name).toLowerCase();
2338
2236
  if (CODE_EXTENSIONS.has(ext)) {
2339
2237
  files.push(relativePath);
2340
2238
  }
@@ -2738,6 +2636,7 @@ function registerConversationsCommand(program2) {
2738
2636
  return;
2739
2637
  }
2740
2638
  const selected = conversations[selection - 1];
2639
+ setActiveConversationId(selected.id, process.cwd());
2741
2640
  setConfigValue("conversationId", selected.id);
2742
2641
  console.log("");
2743
2642
  console.log(SUCCESS11(` \u2705 Joined: "${selected.title}"`));
@@ -2982,14 +2881,14 @@ function registerForkCommand(program2) {
2982
2881
  console.log("");
2983
2882
  return;
2984
2883
  }
2985
- if (!config.conversationId) {
2884
+ const parentConvoId = getActiveConversationId(process.cwd()) || config.conversationId;
2885
+ if (!parentConvoId) {
2986
2886
  console.log("");
2987
2887
  console.log(ERROR10(" \u274C No active conversation to fork from."));
2988
2888
  console.log(MUTED12(" Start a conversation first with `bob chat`, or join one with `bob conversations join`."));
2989
2889
  console.log("");
2990
2890
  return;
2991
2891
  }
2992
- const parentConvoId = config.conversationId;
2993
2892
  console.log("");
2994
2893
  console.log(chalk16.bold(MODE_CONSULTANT6(` \u26A1 Forking: "${title}"`)));
2995
2894
  console.log(MUTED12(` From: ${parentConvoId.slice(0, 24)}...`));
@@ -3006,6 +2905,7 @@ function registerForkCommand(program2) {
3006
2905
  animation.stop();
3007
2906
  await new Promise((resolve3) => setTimeout(resolve3, 200));
3008
2907
  if (result?.conversationId) {
2908
+ setActiveConversationId(result.conversationId, process.cwd());
3009
2909
  setConfigValue("conversationId", result.conversationId);
3010
2910
  console.log("");
3011
2911
  console.log(SUCCESS12(` \u2705 Fork created: "${title}"`));
@@ -3052,7 +2952,8 @@ function registerForkCommand(program2) {
3052
2952
  console.log("");
3053
2953
  return;
3054
2954
  }
3055
- if (!config.conversationId) {
2955
+ const conversationId = getActiveConversationId(process.cwd()) || config.conversationId;
2956
+ if (!conversationId) {
3056
2957
  console.log("");
3057
2958
  console.log(ERROR10(" \u274C No active conversation."));
3058
2959
  console.log("");
@@ -3061,9 +2962,7 @@ function registerForkCommand(program2) {
3061
2962
  console.log("");
3062
2963
  console.log(chalk16.bold(MODE_CONSULTANT6(" \u{1F500} Loading forks...")));
3063
2964
  try {
3064
- const result = await callCloudFunction("listConversationForks", {
3065
- conversationId: config.conversationId
3066
- });
2965
+ const result = await callCloudFunction("listConversationForks", { conversationId });
3067
2966
  const forks = result.forks || [];
3068
2967
  console.log("");
3069
2968
  console.log(chalk16.bold(MODE_CONSULTANT6(" \u{1F500} Forks")));
@@ -3093,8 +2992,8 @@ function registerForkCommand(program2) {
3093
2992
  // src/commands/analyse.ts
3094
2993
  import chalk17 from "chalk";
3095
2994
  import ora5 from "ora";
3096
- import * as fs8 from "fs";
3097
- import * as path9 from "path";
2995
+ import * as fs7 from "fs";
2996
+ import * as path8 from "path";
3098
2997
  var BRAND_PRIMARY8 = chalk17.hex("#E66F24");
3099
2998
  var BRAND_SECONDARY12 = chalk17.hex("#FFAB00");
3100
2999
  var SUCCESS13 = chalk17.hex("#66BB6A");
@@ -3108,7 +3007,7 @@ function registerAnalyseCommand(program2) {
3108
3007
  program2.command("analyse").description("Analyse the current project for bugs, features, improvements, and upgrades").option("--results", "Show analysis dashboard or filtered list").option("--bugs", "Show bugs list (interactive)").option("--features", "Show features list (interactive)").option("--improvements", "Show improvements list (interactive)").option("--upgrades", "Show upgrades list (interactive)").option("--sort <method>", "Sort by: priority (default) or file").option("--search <query>", "Filter results by keyword").option("--status", "Show current analysis job status").option("--auto", "Auto-fix mode: Bob triages and MiniBob implements").option("--confidence <number>", "Confidence gate for auto-fix (default: 90)", "90").option("--priority <level>", "Priority gate for auto-fix: critical, high, medium, low (default: critical)", "critical").action(async (options) => {
3109
3008
  const config = getConfig();
3110
3009
  if (options.auto) {
3111
- const { runAutoFix } = await import("./analyse-auto-GCWXNMNZ.js");
3010
+ const { runAutoFix } = await import("./analyse-auto-DCC6UDFV.js");
3112
3011
  const category = options.bugs ? "bugs" : options.features ? "features" : options.improvements ? "improvements" : options.upgrades ? "upgrades" : void 0;
3113
3012
  await runAutoFix({
3114
3013
  category,
@@ -3118,7 +3017,7 @@ function registerAnalyseCommand(program2) {
3118
3017
  return;
3119
3018
  }
3120
3019
  if (options.bugs || options.features || options.improvements || options.upgrades) {
3121
- const { showInteractiveResults } = await import("./analyse-results-TIVOJ5SC.js");
3020
+ const { showInteractiveResults } = await import("./analyse-results-4S577CG5.js");
3122
3021
  const category = options.bugs ? "bugs" : options.features ? "features" : options.improvements ? "improvements" : "upgrades";
3123
3022
  await showInteractiveResults(config, category, options.sort, options.search);
3124
3023
  return;
@@ -3240,7 +3139,8 @@ function renderAnalysisDashboard(counts) {
3240
3139
  console.log("");
3241
3140
  }
3242
3141
  async function showStatus(config) {
3243
- if (!config.loggedIn || !config.authToken || !config.conversationId) {
3142
+ const conversationId = getActiveConversationId(process.cwd()) || config.conversationId;
3143
+ if (!config.loggedIn || !config.authToken || !conversationId) {
3244
3144
  console.log("");
3245
3145
  console.log(WARNING12(" \u26A0\uFE0F Status check requires Tier 3 with an active conversation."));
3246
3146
  console.log("");
@@ -3249,7 +3149,7 @@ async function showStatus(config) {
3249
3149
  const spinner = ora5({ text: INFO13(" Checking analysis status..."), spinner: "dots" }).start();
3250
3150
  try {
3251
3151
  const result = await callCloudFunction("getCLIAnalysisResults", {
3252
- conversationId: config.conversationId,
3152
+ conversationId,
3253
3153
  action: "status"
3254
3154
  });
3255
3155
  spinner.stop();
@@ -3318,15 +3218,15 @@ async function runAnalysis(config) {
3318
3218
  console.log("");
3319
3219
  console.log("");
3320
3220
  const { analysisDir } = ensureProjectStructure(cwd);
3321
- const resultsDir = path9.join(analysisDir, "results");
3322
- if (!fs8.existsSync(resultsDir)) fs8.mkdirSync(resultsDir, { recursive: true });
3221
+ const resultsDir = path8.join(analysisDir, "results");
3222
+ if (!fs7.existsSync(resultsDir)) fs7.mkdirSync(resultsDir, { recursive: true });
3323
3223
  let completed = 0;
3324
3224
  const allResults = {};
3325
3225
  for (const filePath of files) {
3326
- const absolutePath = path9.join(cwd, filePath);
3226
+ const absolutePath = path8.join(cwd, filePath);
3327
3227
  let content;
3328
3228
  try {
3329
- content = fs8.readFileSync(absolutePath, "utf-8");
3229
+ content = fs7.readFileSync(absolutePath, "utf-8");
3330
3230
  } catch (error) {
3331
3231
  console.error(ERROR11(` \u274C Could not read file ${filePath}: ${error.message}`));
3332
3232
  completed++;
@@ -3396,7 +3296,7 @@ ${content}`;
3396
3296
  }
3397
3297
  completed++;
3398
3298
  }
3399
- fs8.writeFileSync(path9.join(resultsDir, "analysis.json"), JSON.stringify(allResults, null, 2));
3299
+ fs7.writeFileSync(path8.join(resultsDir, "analysis.json"), JSON.stringify(allResults, null, 2));
3400
3300
  let totalBugs = 0, totalFeatures = 0, totalImprovements = 0, totalUpgrades = 0;
3401
3301
  for (const fileResults of Object.values(allResults)) {
3402
3302
  const r = fileResults;
@@ -3405,7 +3305,7 @@ ${content}`;
3405
3305
  totalImprovements += r.improvements?.length || 0;
3406
3306
  totalUpgrades += r.upgrades?.length || 0;
3407
3307
  }
3408
- fs8.writeFileSync(path9.join(resultsDir, "counts.json"), JSON.stringify({
3308
+ fs7.writeFileSync(path8.join(resultsDir, "counts.json"), JSON.stringify({
3409
3309
  bugs: totalBugs,
3410
3310
  features: totalFeatures,
3411
3311
  improvements: totalImprovements,
@@ -3422,18 +3322,18 @@ ${content}`;
3422
3322
  function loadLocalCounts() {
3423
3323
  const cwd = process.cwd();
3424
3324
  const { analysisDir } = ensureProjectStructure(cwd);
3425
- const countsPath = path9.join(analysisDir, "results", "counts.json");
3426
- if (!fs8.existsSync(countsPath)) return null;
3427
- return JSON.parse(fs8.readFileSync(countsPath, "utf-8"));
3325
+ const countsPath = path8.join(analysisDir, "results", "counts.json");
3326
+ if (!fs7.existsSync(countsPath)) return null;
3327
+ return JSON.parse(fs7.readFileSync(countsPath, "utf-8"));
3428
3328
  }
3429
3329
  function loadAddressedCount() {
3430
3330
  const cwd = process.cwd();
3431
- const projectName = path9.basename(cwd);
3331
+ const projectName = path8.basename(cwd);
3432
3332
  const homeDir = process.env.HOME || process.env.USERPROFILE || "";
3433
- const analysisPath = path9.join(homeDir, ".bob", "projects", projectName, "analysis", "results", "analysis.json");
3434
- if (!fs8.existsSync(analysisPath)) return 0;
3333
+ const analysisPath = path8.join(homeDir, ".bob", "projects", projectName, "analysis", "results", "analysis.json");
3334
+ if (!fs7.existsSync(analysisPath)) return 0;
3435
3335
  try {
3436
- const allResults = JSON.parse(fs8.readFileSync(analysisPath, "utf-8"));
3336
+ const allResults = JSON.parse(fs7.readFileSync(analysisPath, "utf-8"));
3437
3337
  let addressed = 0;
3438
3338
  for (const fileResults of Object.values(allResults)) {
3439
3339
  for (const category of ["bugs", "features", "improvements", "upgrades"]) {
@@ -3474,8 +3374,8 @@ import chalk18 from "chalk";
3474
3374
  import ora6 from "ora";
3475
3375
  import * as readline6 from "readline";
3476
3376
  import simpleGit2 from "simple-git";
3477
- import * as fs9 from "fs";
3478
- import * as path10 from "path";
3377
+ import * as fs8 from "fs";
3378
+ import * as path9 from "path";
3479
3379
  var RED = chalk18.hex("#EF5350");
3480
3380
  var GREEN = chalk18.hex("#66BB6A");
3481
3381
  var AMBER2 = chalk18.hex("#FFAB00");
@@ -3486,33 +3386,34 @@ var CYAN = chalk18.cyan;
3486
3386
  function registerAutonomyCommand(program2) {
3487
3387
  program2.command("autonomy").description("Launch autonomous repair mode \u2014 MiniBob fixes all analysed issues").option("--status", "Check current autonomy run progress (Tier 3)").option("--stop", "Stop the current autonomy run (Tier 3)").option("--category <cat>", "Limit to: bugs, features, improvements, upgrades").option("--priority <level>", "Minimum priority: critical, high, medium, low (default: high)", "high").option("--no-push", "Skip git push after completion").action(async (options) => {
3488
3388
  const config = getConfig();
3389
+ const conversationId = getActiveConversationId(process.cwd()) || config.conversationId;
3489
3390
  if (options.status) {
3490
- await showAutonomyStatus(config);
3391
+ await showAutonomyStatus(config, conversationId);
3491
3392
  return;
3492
3393
  }
3493
3394
  if (options.stop) {
3494
3395
  console.log(chalk18.yellow(" \u26A0\uFE0F Stop command not yet implemented for Tier 3."));
3495
3396
  return;
3496
3397
  }
3497
- if (config.tier === "platform" && config.provider !== "local" && config.loggedIn && config.conversationId) {
3498
- await runTier3Autonomy(config);
3398
+ if (config.tier === "platform" && config.provider !== "local" && config.loggedIn && conversationId) {
3399
+ await runTier3Autonomy(config, conversationId);
3499
3400
  } else {
3500
3401
  await runTier1Autonomy(config, options);
3501
3402
  }
3502
3403
  });
3503
3404
  }
3504
- async function runTier3Autonomy(config) {
3405
+ async function runTier3Autonomy(config, conversationId) {
3505
3406
  console.log("");
3506
3407
  console.log(chalk18.bold.cyan(" \u26A1 MiniBob Autonomy Mode (Platform)"));
3507
3408
  console.log(GRAY(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
3508
- console.log(GRAY(` \u{1F4E1} Conversation: ${config.conversationId?.slice(0, 24)}...`));
3509
- console.log(GRAY(` \u{1F517} https://bobs-workshop.web.app/#/bobcodeassistant/${config.conversationId}`));
3409
+ console.log(GRAY(` \u{1F4E1} Conversation: ${conversationId?.slice(0, 24)}...`));
3410
+ console.log(GRAY(` \u{1F517} https://bobs-workshop.web.app/#/bobcodeassistant/${conversationId}`));
3510
3411
  console.log(GRAY(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
3511
3412
  console.log("");
3512
3413
  const spinner = ora6({ text: CYAN(" Igniting autonomy workers..."), spinner: "dots" }).start();
3513
3414
  try {
3514
3415
  const result = await callCloudFunction("startMiniBobAutonomy", {
3515
- conversationId: config.conversationId,
3416
+ conversationId,
3516
3417
  proxyEmail: null
3517
3418
  });
3518
3419
  spinner.stop();
@@ -3547,7 +3448,7 @@ async function runTier3Autonomy(config) {
3547
3448
  while (running) {
3548
3449
  try {
3549
3450
  const updates = await callCloudFunction("getCLITerminalUpdates", {
3550
- conversationId: config.conversationId,
3451
+ conversationId,
3551
3452
  since: lastTimestamp
3552
3453
  });
3553
3454
  if (updates?.lines && updates.lines.length > 0) {
@@ -3579,7 +3480,7 @@ async function runTier3Autonomy(config) {
3579
3480
  rl.close();
3580
3481
  if (answer.toLowerCase() === "y" || answer.toLowerCase() === "yes") {
3581
3482
  try {
3582
- await callCloudFunction("commitAndPushChanges", { conversationId: config.conversationId });
3483
+ await callCloudFunction("commitAndPushChanges", { conversationId });
3583
3484
  console.log(GREEN(" \u2705 Pushed to GitHub!"));
3584
3485
  } catch (pushErr) {
3585
3486
  console.log(RED(` \u274C Push failed: ${pushErr.message}`));
@@ -3729,17 +3630,16 @@ Autonomous repair by Bob's CLI.`;
3729
3630
  console.log(GRAY(" \u{1F4E6} All original files backed up to .bob-backups/"));
3730
3631
  console.log("");
3731
3632
  }
3732
- async function showAutonomyStatus(config) {
3733
- if (!config.loggedIn || !config.conversationId) {
3633
+ async function showAutonomyStatus(config, conversationId) {
3634
+ if (!config.loggedIn || !conversationId) {
3734
3635
  console.log(chalk18.yellow(" \u26A0\uFE0F Status requires Tier 3 with an active conversation."));
3735
3636
  return;
3736
3637
  }
3737
3638
  const spinner = ora6({ text: CYAN(" Checking autonomy status..."), spinner: "dots" }).start();
3738
3639
  try {
3739
3640
  const result = await callCloudFunction("getCLITerminalUpdates", {
3740
- conversationId: config.conversationId,
3641
+ conversationId,
3741
3642
  since: new Date(Date.now() - 6e4).toISOString(),
3742
- // Last 60 seconds
3743
3643
  limit: 5
3744
3644
  });
3745
3645
  spinner.stop();
@@ -3813,17 +3713,17 @@ Return the complete file content now:`;
3813
3713
  return false;
3814
3714
  }
3815
3715
  }
3816
- const absolutePath = path10.join(process.cwd(), suggestion.filePath);
3817
- const backupDir = path10.join(process.cwd(), ".bob-backups");
3818
- if (!fs9.existsSync(backupDir)) fs9.mkdirSync(backupDir, { recursive: true });
3819
- if (fs9.existsSync(absolutePath)) {
3716
+ const absolutePath = path9.join(process.cwd(), suggestion.filePath);
3717
+ const backupDir = path9.join(process.cwd(), ".bob-backups");
3718
+ if (!fs8.existsSync(backupDir)) fs8.mkdirSync(backupDir, { recursive: true });
3719
+ if (fs8.existsSync(absolutePath)) {
3820
3720
  const timestamp = Date.now();
3821
3721
  const backupName = suggestion.filePath.replace(/[\/\\]/g, "_") + `.${timestamp}.bak`;
3822
- fs9.copyFileSync(absolutePath, path10.join(backupDir, backupName));
3722
+ fs8.copyFileSync(absolutePath, path9.join(backupDir, backupName));
3823
3723
  }
3824
- const dir = path10.dirname(absolutePath);
3825
- if (!fs9.existsSync(dir)) fs9.mkdirSync(dir, { recursive: true });
3826
- fs9.writeFileSync(absolutePath, newContent, "utf-8");
3724
+ const dir = path9.dirname(absolutePath);
3725
+ if (!fs8.existsSync(dir)) fs8.mkdirSync(dir, { recursive: true });
3726
+ fs8.writeFileSync(absolutePath, newContent, "utf-8");
3827
3727
  return true;
3828
3728
  } catch {
3829
3729
  return false;
@@ -3831,11 +3731,11 @@ Return the complete file content now:`;
3831
3731
  }
3832
3732
  function detectLocalCategory(suggestion) {
3833
3733
  const cwd = process.cwd();
3834
- const projectName = path10.basename(cwd);
3734
+ const projectName = path9.basename(cwd);
3835
3735
  const homeDir = process.env.HOME || process.env.USERPROFILE || "";
3836
- const analysisPath = path10.join(homeDir, ".bob", "projects", projectName, "analysis", "results", "analysis.json");
3837
- if (!fs9.existsSync(analysisPath)) return "bugs";
3838
- const allResults = JSON.parse(fs9.readFileSync(analysisPath, "utf-8"));
3736
+ const analysisPath = path9.join(homeDir, ".bob", "projects", projectName, "analysis", "results", "analysis.json");
3737
+ if (!fs8.existsSync(analysisPath)) return "bugs";
3738
+ const allResults = JSON.parse(fs8.readFileSync(analysisPath, "utf-8"));
3839
3739
  const fileResults = allResults[suggestion.filePath];
3840
3740
  if (!fileResults) return "bugs";
3841
3741
  for (const cat of ["bugs", "features", "improvements", "upgrades"]) {
@@ -3922,9 +3822,9 @@ function renderLocalTodoList(queue) {
3922
3822
 
3923
3823
  // src/commands/serve.ts
3924
3824
  import chalk19 from "chalk";
3925
- import * as fs10 from "fs";
3926
- import * as os3 from "os";
3927
- import * as path11 from "path";
3825
+ import * as fs9 from "fs";
3826
+ import * as os2 from "os";
3827
+ import * as path10 from "path";
3928
3828
  import * as crypto2 from "crypto";
3929
3829
  import axios from "axios";
3930
3830
  var GREEN2 = chalk19.hex("#66BB6A");
@@ -3933,7 +3833,7 @@ var RED2 = chalk19.hex("#EF5350");
3933
3833
  var GRAY2 = chalk19.gray;
3934
3834
  var CYAN2 = chalk19.cyan;
3935
3835
  var BORDER5 = chalk19.hex("#455A64");
3936
- var BOB_DIR3 = path11.join(os3.homedir(), ".bob");
3836
+ var BOB_DIR2 = path10.join(os2.homedir(), ".bob");
3937
3837
  var ALGORITHM = "aes-256-cbc";
3938
3838
  var TIER_CONFIGS = {
3939
3839
  "Power": {
@@ -3964,13 +3864,13 @@ function encrypt(inputPath, outputPath, uid) {
3964
3864
  const key = deriveKey(uid, salt);
3965
3865
  const iv = crypto2.randomBytes(16);
3966
3866
  const cipher = crypto2.createCipheriv(ALGORITHM, key, iv);
3967
- const input = fs10.readFileSync(inputPath);
3867
+ const input = fs9.readFileSync(inputPath);
3968
3868
  const encrypted = Buffer.concat([cipher.update(input), cipher.final()]);
3969
3869
  const header = Buffer.from(salt + iv.toString("hex"), "utf-8");
3970
- fs10.writeFileSync(outputPath, Buffer.concat([header, encrypted]));
3870
+ fs9.writeFileSync(outputPath, Buffer.concat([header, encrypted]));
3971
3871
  }
3972
3872
  function decrypt(inputPath, outputPath, uid) {
3973
- const data = fs10.readFileSync(inputPath);
3873
+ const data = fs9.readFileSync(inputPath);
3974
3874
  const header = data.slice(0, 64).toString("utf-8");
3975
3875
  const salt = header.slice(0, 32);
3976
3876
  const iv = Buffer.from(header.slice(32, 64), "hex");
@@ -3978,16 +3878,16 @@ function decrypt(inputPath, outputPath, uid) {
3978
3878
  const key = deriveKey(uid, salt);
3979
3879
  const decipher = crypto2.createDecipheriv(ALGORITHM, key, iv);
3980
3880
  const decrypted = Buffer.concat([decipher.update(encrypted), decipher.final()]);
3981
- fs10.writeFileSync(outputPath, decrypted);
3881
+ fs9.writeFileSync(outputPath, decrypted);
3982
3882
  }
3983
3883
  function getTempDir() {
3984
- const tmpDir = path11.join(os3.tmpdir(), `bob-remote-${Date.now()}`);
3985
- fs10.mkdirSync(tmpDir, { recursive: true });
3884
+ const tmpDir = path10.join(os2.tmpdir(), `bob-remote-${Date.now()}`);
3885
+ fs9.mkdirSync(tmpDir, { recursive: true });
3986
3886
  return tmpDir;
3987
3887
  }
3988
3888
  function cleanupTemp(tmpDir) {
3989
3889
  try {
3990
- fs10.rmSync(tmpDir, { recursive: true, force: true });
3890
+ fs9.rmSync(tmpDir, { recursive: true, force: true });
3991
3891
  } catch {
3992
3892
  }
3993
3893
  }
@@ -3998,16 +3898,16 @@ function scanProjectFiles2(rootDir, currentDir, depth = 0) {
3998
3898
  const dir = currentDir || rootDir;
3999
3899
  const files = [];
4000
3900
  try {
4001
- const entries = fs10.readdirSync(dir, { withFileTypes: true });
3901
+ const entries = fs9.readdirSync(dir, { withFileTypes: true });
4002
3902
  for (const entry of entries) {
4003
3903
  if (IGNORE_DIRS2.includes(entry.name)) continue;
4004
3904
  if (entry.name.startsWith(".")) continue;
4005
- const fullPath = path11.join(dir, entry.name);
4006
- const relativePath = path11.relative(rootDir, fullPath).replace(/\\/g, "/");
3905
+ const fullPath = path10.join(dir, entry.name);
3906
+ const relativePath = path10.relative(rootDir, fullPath).replace(/\\/g, "/");
4007
3907
  if (entry.isDirectory()) {
4008
3908
  files.push(...scanProjectFiles2(rootDir, fullPath, depth + 1));
4009
3909
  } else {
4010
- const ext = path11.extname(entry.name).toLowerCase();
3910
+ const ext = path10.extname(entry.name).toLowerCase();
4011
3911
  if (CODE_EXTENSIONS2.has(ext)) files.push(relativePath);
4012
3912
  }
4013
3913
  }
@@ -4074,8 +3974,8 @@ function registerServeCommand(program2) {
4074
3974
  return;
4075
3975
  }
4076
3976
  const tierConfig = TIER_CONFIGS[userTier] || TIER_CONFIGS["Starter"];
4077
- const machineId = os3.hostname();
4078
- const projectName = path11.basename(process.cwd());
3977
+ const machineId = os2.hostname();
3978
+ const projectName = path10.basename(process.cwd());
4079
3979
  const sessionId = `${machineId}_${Date.now()}`;
4080
3980
  await startActiveBob(config, sessionId, machineId, projectName, tierConfig, userTier);
4081
3981
  });
@@ -4351,10 +4251,10 @@ async function executeIndex(payload, config) {
4351
4251
  const summaries = {};
4352
4252
  let completed = 0;
4353
4253
  for (const filePath of files) {
4354
- const absolutePath = path11.join(cwd, filePath);
4254
+ const absolutePath = path10.join(cwd, filePath);
4355
4255
  let content;
4356
4256
  try {
4357
- content = fs10.readFileSync(absolutePath, "utf-8");
4257
+ content = fs9.readFileSync(absolutePath, "utf-8");
4358
4258
  } catch {
4359
4259
  completed++;
4360
4260
  continue;
@@ -4446,18 +4346,18 @@ async function executeAnalyse(payload, config) {
4446
4346
  const dependencies = loadDependencies(cwd) || {};
4447
4347
  const files = Object.keys(summaries);
4448
4348
  const { analysisDir } = ensureProjectStructure(cwd);
4449
- const resultsDir = path11.join(analysisDir, "results");
4450
- if (!fs10.existsSync(resultsDir)) fs10.mkdirSync(resultsDir, { recursive: true });
4349
+ const resultsDir = path10.join(analysisDir, "results");
4350
+ if (!fs9.existsSync(resultsDir)) fs9.mkdirSync(resultsDir, { recursive: true });
4451
4351
  const allResults = {};
4452
4352
  let totalBugs = 0;
4453
4353
  let totalFeatures = 0;
4454
4354
  let totalImprovements = 0;
4455
4355
  let totalUpgrades = 0;
4456
4356
  for (const filePath of files) {
4457
- const absolutePath = path11.join(cwd, filePath);
4357
+ const absolutePath = path10.join(cwd, filePath);
4458
4358
  let content;
4459
4359
  try {
4460
- content = fs10.readFileSync(absolutePath, "utf-8");
4360
+ content = fs9.readFileSync(absolutePath, "utf-8");
4461
4361
  } catch {
4462
4362
  continue;
4463
4363
  }
@@ -4508,12 +4408,12 @@ ${content}`;
4508
4408
  continue;
4509
4409
  }
4510
4410
  }
4511
- fs10.writeFileSync(
4512
- path11.join(resultsDir, "analysis.json"),
4411
+ fs9.writeFileSync(
4412
+ path10.join(resultsDir, "analysis.json"),
4513
4413
  JSON.stringify(allResults, null, 2)
4514
4414
  );
4515
- fs10.writeFileSync(
4516
- path11.join(resultsDir, "counts.json"),
4415
+ fs9.writeFileSync(
4416
+ path10.join(resultsDir, "counts.json"),
4517
4417
  JSON.stringify({ bugs: totalBugs, features: totalFeatures, improvements: totalImprovements, upgrades: totalUpgrades }, null, 2)
4518
4418
  );
4519
4419
  return {
@@ -4532,33 +4432,33 @@ async function executeBackup(payload, config) {
4532
4432
  return { success: false, error: "User UID not available. Re-login required." };
4533
4433
  }
4534
4434
  const cwd = process.cwd();
4535
- const projectName = path11.basename(cwd);
4435
+ const projectName = path10.basename(cwd);
4536
4436
  let sourceDir;
4537
4437
  let displayLabel;
4538
4438
  if (isGlobal) {
4539
- sourceDir = BOB_DIR3;
4439
+ sourceDir = BOB_DIR2;
4540
4440
  displayLabel = "global (~/.bob/)";
4541
4441
  } else if (isSource) {
4542
4442
  sourceDir = cwd;
4543
4443
  displayLabel = `source: ${projectName}`;
4544
4444
  } else {
4545
- sourceDir = path11.join(BOB_DIR3, "projects", projectName);
4445
+ sourceDir = path10.join(BOB_DIR2, "projects", projectName);
4546
4446
  displayLabel = `context: ${projectName}`;
4547
4447
  }
4548
- if (!fs10.existsSync(sourceDir)) {
4448
+ if (!fs9.existsSync(sourceDir)) {
4549
4449
  return { success: false, error: `Source directory not found: ${sourceDir}` };
4550
4450
  }
4551
4451
  const tmpDir = getTempDir();
4552
- const archivePath = path11.join(tmpDir, "bob-backup.tar.gz");
4553
- const encryptedPath = path11.join(tmpDir, "bob-backup.bob.enc");
4452
+ const archivePath = path10.join(tmpDir, "bob-backup.tar.gz");
4453
+ const encryptedPath = path10.join(tmpDir, "bob-backup.bob.enc");
4554
4454
  try {
4555
4455
  const tar = await import("tar");
4556
- const relativeSource = path11.relative(os3.homedir(), sourceDir);
4456
+ const relativeSource = path10.relative(os2.homedir(), sourceDir);
4557
4457
  await tar.create(
4558
- { gzip: true, file: archivePath, cwd: os3.homedir() },
4458
+ { gzip: true, file: archivePath, cwd: os2.homedir() },
4559
4459
  [relativeSource]
4560
4460
  );
4561
- const archiveStats = fs10.statSync(archivePath);
4461
+ const archiveStats = fs9.statSync(archivePath);
4562
4462
  const estimatedSizeGB = archiveStats.size / (1024 * 1024 * 1024);
4563
4463
  const sizeLabel = archiveStats.size < 1024 * 1024 ? `${(archiveStats.size / 1024).toFixed(1)} KB` : `${(archiveStats.size / (1024 * 1024)).toFixed(1)} MB`;
4564
4464
  encrypt(archivePath, encryptedPath, config.uid);
@@ -4572,7 +4472,7 @@ async function executeBackup(payload, config) {
4572
4472
  archiveName: archiveName || null,
4573
4473
  estimatedSizeGB
4574
4474
  });
4575
- const encryptedData = fs10.readFileSync(encryptedPath);
4475
+ const encryptedData = fs9.readFileSync(encryptedPath);
4576
4476
  await axios.put(uploadResult.uploadUrl, encryptedData, {
4577
4477
  headers: {
4578
4478
  "Content-Type": "application/octet-stream",
@@ -4613,10 +4513,10 @@ async function executeRestore(payload, config) {
4613
4513
  return { success: false, error: "User UID not available. Re-login required." };
4614
4514
  }
4615
4515
  const cwd = process.cwd();
4616
- const projectName = path11.basename(cwd);
4516
+ const projectName = path10.basename(cwd);
4617
4517
  const tmpDir = getTempDir();
4618
- const downloadPath = path11.join(tmpDir, "bob-backup.bob.enc");
4619
- const decryptedPath = path11.join(tmpDir, "bob-backup.tar.gz");
4518
+ const downloadPath = path10.join(tmpDir, "bob-backup.bob.enc");
4519
+ const decryptedPath = path10.join(tmpDir, "bob-backup.tar.gz");
4620
4520
  try {
4621
4521
  const downloadResult = await callCloudFunction("cliBackupLicense", {
4622
4522
  action: isSource ? "requestSourceDownload" : "requestDownload",
@@ -4630,26 +4530,26 @@ async function executeRestore(payload, config) {
4630
4530
  responseType: "arraybuffer",
4631
4531
  maxContentLength: Infinity
4632
4532
  });
4633
- fs10.writeFileSync(downloadPath, Buffer.from(response.data));
4533
+ fs9.writeFileSync(downloadPath, Buffer.from(response.data));
4634
4534
  decrypt(downloadPath, decryptedPath, config.uid);
4635
4535
  let restoreTarget;
4636
4536
  if (isGlobal) {
4637
- restoreTarget = BOB_DIR3;
4537
+ restoreTarget = BOB_DIR2;
4638
4538
  } else if (isSource) {
4639
4539
  restoreTarget = cwd;
4640
4540
  } else {
4641
- restoreTarget = path11.join(BOB_DIR3, "projects", projectName);
4541
+ restoreTarget = path10.join(BOB_DIR2, "projects", projectName);
4642
4542
  }
4643
4543
  const preRestoreBackup = `${restoreTarget}-pre-restore-${Date.now()}`;
4644
- if (fs10.existsSync(restoreTarget)) {
4645
- fs10.cpSync(restoreTarget, preRestoreBackup, { recursive: true });
4544
+ if (fs9.existsSync(restoreTarget)) {
4545
+ fs9.cpSync(restoreTarget, preRestoreBackup, { recursive: true });
4646
4546
  }
4647
4547
  const tar = await import("tar");
4648
4548
  if (isSource) {
4649
- const parentDir = path11.dirname(cwd);
4549
+ const parentDir = path10.dirname(cwd);
4650
4550
  await tar.extract({ file: decryptedPath, cwd: parentDir });
4651
4551
  } else {
4652
- await tar.extract({ file: decryptedPath, cwd: os3.homedir() });
4552
+ await tar.extract({ file: decryptedPath, cwd: os2.homedir() });
4653
4553
  }
4654
4554
  const scopeLabel = isGlobal ? "global (~/.bob/)" : isSource ? `source: ${projectName}` : `context: ${projectName}`;
4655
4555
  return {
@@ -4658,7 +4558,7 @@ async function executeRestore(payload, config) {
4658
4558
  projectName,
4659
4559
  isSource,
4660
4560
  isGlobal,
4661
- preRestoreBackup: path11.basename(preRestoreBackup)
4561
+ preRestoreBackup: path10.basename(preRestoreBackup)
4662
4562
  };
4663
4563
  } catch (error) {
4664
4564
  return { success: false, error: `Restore failed: ${error.message}` };
@@ -4945,9 +4845,7 @@ async function showConnectionStatus(config) {
4945
4845
  }
4946
4846
  const spinner = ora7({ text: INFO14(" Checking Active Bob status..."), spinner: "dots" }).start();
4947
4847
  try {
4948
- const result = await callCloudFunction("listActiveBobs", {
4949
- conversationId: config.conversationId
4950
- });
4848
+ const result = await callCloudFunction("listActiveBobs", { conversationId: config.conversationId });
4951
4849
  spinner.stop();
4952
4850
  const sessions = result?.sessions || [];
4953
4851
  const activeSessions = sessions.filter((s) => s.active);
@@ -5026,6 +4924,7 @@ async function discoverAndConnect(config) {
5026
4924
  return;
5027
4925
  }
5028
4926
  const selected = bobs[selection - 1];
4927
+ setActiveConversationId(selected.conversationId, process.cwd());
5029
4928
  setConfigValue("conversationId", selected.conversationId);
5030
4929
  console.log("");
5031
4930
  console.log(SUCCESS14(` \u2705 Connected to: ${selected.machineId} (${selected.projectName})`));
@@ -5720,7 +5619,7 @@ async function renderProfileDashboard() {
5720
5619
  }
5721
5620
 
5722
5621
  // src/commands/profile.ts
5723
- import * as path12 from "path";
5622
+ import * as path11 from "path";
5724
5623
  var AMBER5 = chalk23.hex("#FFAB00");
5725
5624
  var GREEN4 = chalk23.hex("#66BB6A");
5726
5625
  var BLUE2 = chalk23.hex("#42A5F5");
@@ -5856,7 +5755,7 @@ async function generateDailyProfile(config) {
5856
5755
  return;
5857
5756
  }
5858
5757
  const userMessages = messages.filter((m) => m.role === "user");
5859
- const projectName = path12.basename(process.cwd());
5758
+ const projectName = path11.basename(process.cwd());
5860
5759
  console.log("");
5861
5760
  console.log(CYAN4(` \u{1F9EC} Generating daily profile from ${userMessages.length} messages...`));
5862
5761
  console.log("");
@@ -6177,9 +6076,9 @@ function getWeekNumber(date) {
6177
6076
  // src/commands/backup.ts
6178
6077
  import chalk24 from "chalk";
6179
6078
  import ora11 from "ora";
6180
- import * as fs11 from "fs";
6181
- import * as path13 from "path";
6182
- import * as os4 from "os";
6079
+ import * as fs10 from "fs";
6080
+ import * as path12 from "path";
6081
+ import * as os3 from "os";
6183
6082
  import * as crypto3 from "crypto";
6184
6083
  import axios2 from "axios";
6185
6084
  import inquirer from "inquirer";
@@ -6190,7 +6089,7 @@ var RED5 = chalk24.hex("#EF5350");
6190
6089
  var AMBER6 = chalk24.hex("#FFAB00");
6191
6090
  var GRAY5 = chalk24.gray;
6192
6091
  var BORDER10 = chalk24.hex("#455A64");
6193
- var BOB_DIR4 = path13.join(os4.homedir(), ".bob");
6092
+ var BOB_DIR3 = path12.join(os3.homedir(), ".bob");
6194
6093
  var ALGORITHM2 = "aes-256-cbc";
6195
6094
  function deriveKey2(uid, salt) {
6196
6095
  return crypto3.pbkdf2Sync(uid, salt, 1e5, 32, "sha256");
@@ -6200,13 +6099,13 @@ function encrypt2(inputPath, outputPath, uid) {
6200
6099
  const key = deriveKey2(uid, salt);
6201
6100
  const iv = crypto3.randomBytes(16);
6202
6101
  const cipher = crypto3.createCipheriv(ALGORITHM2, key, iv);
6203
- const input = fs11.readFileSync(inputPath);
6102
+ const input = fs10.readFileSync(inputPath);
6204
6103
  const encrypted = Buffer.concat([cipher.update(input), cipher.final()]);
6205
6104
  const header = Buffer.from(salt + iv.toString("hex"), "utf-8");
6206
- fs11.writeFileSync(outputPath, Buffer.concat([header, encrypted]));
6105
+ fs10.writeFileSync(outputPath, Buffer.concat([header, encrypted]));
6207
6106
  }
6208
6107
  function decrypt2(inputPath, outputPath, uid) {
6209
- const data = fs11.readFileSync(inputPath);
6108
+ const data = fs10.readFileSync(inputPath);
6210
6109
  const header = data.slice(0, 64).toString("utf-8");
6211
6110
  const salt = header.slice(0, 32);
6212
6111
  const iv = Buffer.from(header.slice(32, 64), "hex");
@@ -6214,7 +6113,7 @@ function decrypt2(inputPath, outputPath, uid) {
6214
6113
  const key = deriveKey2(uid, salt);
6215
6114
  const decipher = crypto3.createDecipheriv(ALGORITHM2, key, iv);
6216
6115
  const decrypted = Buffer.concat([decipher.update(encrypted), decipher.final()]);
6217
- fs11.writeFileSync(outputPath, decrypted);
6116
+ fs10.writeFileSync(outputPath, decrypted);
6218
6117
  }
6219
6118
  function formatBytes(bytes) {
6220
6119
  if (bytes < 1024) return `${bytes} B`;
@@ -6223,13 +6122,13 @@ function formatBytes(bytes) {
6223
6122
  return `${(bytes / (1024 * 1024 * 1024)).toFixed(2)} GB`;
6224
6123
  }
6225
6124
  function getTempDir2() {
6226
- const tmpDir = path13.join(os4.tmpdir(), `bob-backup-${Date.now()}`);
6227
- fs11.mkdirSync(tmpDir, { recursive: true });
6125
+ const tmpDir = path12.join(os3.tmpdir(), `bob-backup-${Date.now()}`);
6126
+ fs10.mkdirSync(tmpDir, { recursive: true });
6228
6127
  return tmpDir;
6229
6128
  }
6230
6129
  function cleanupTemp2(tmpDir) {
6231
6130
  try {
6232
- fs11.rmSync(tmpDir, { recursive: true, force: true });
6131
+ fs10.rmSync(tmpDir, { recursive: true, force: true });
6233
6132
  } catch {
6234
6133
  }
6235
6134
  }
@@ -6244,10 +6143,10 @@ function requireAuth(config) {
6244
6143
  return true;
6245
6144
  }
6246
6145
  function getCurrentProjectName() {
6247
- return path13.basename(process.cwd());
6146
+ return path12.basename(process.cwd());
6248
6147
  }
6249
6148
  function getProjectBackupDir(projectName) {
6250
- return path13.join(BOB_DIR4, "projects", projectName);
6149
+ return path12.join(BOB_DIR3, "projects", projectName);
6251
6150
  }
6252
6151
  function normalizeFilePath(filePath) {
6253
6152
  return filePath.replace(/\\/g, "/");
@@ -6276,7 +6175,7 @@ function handleBackupError(error) {
6276
6175
  console.log("");
6277
6176
  }
6278
6177
  function loadGitignorePatterns(projectDir) {
6279
- const gitignorePath = path13.join(projectDir, ".gitignore");
6178
+ const gitignorePath = path12.join(projectDir, ".gitignore");
6280
6179
  const defaultIgnore = [
6281
6180
  "node_modules",
6282
6181
  ".git",
@@ -6293,9 +6192,9 @@ function loadGitignorePatterns(projectDir) {
6293
6192
  "coverage",
6294
6193
  ".nyc_output"
6295
6194
  ];
6296
- if (!fs11.existsSync(gitignorePath)) return defaultIgnore;
6195
+ if (!fs10.existsSync(gitignorePath)) return defaultIgnore;
6297
6196
  try {
6298
- const lines = fs11.readFileSync(gitignorePath, "utf-8").split("\n").map((l) => l.trim()).filter((l) => l && !l.startsWith("#"));
6197
+ const lines = fs10.readFileSync(gitignorePath, "utf-8").split("\n").map((l) => l.trim()).filter((l) => l && !l.startsWith("#"));
6299
6198
  return [...defaultIgnore, ...lines];
6300
6199
  } catch {
6301
6200
  return defaultIgnore;
@@ -6323,7 +6222,7 @@ async function runBackup(options) {
6323
6222
  console.log(BORDER10(" \u2551") + GRAY5(` Scope: ${isGlobal ? "\u{1F310} Global (~/.bob/)" : `\u{1F4C1} Project: ${projectName}`}`));
6324
6223
  if (archiveName) console.log(BORDER10(" \u2551") + GRAY5(` Archive: "${archiveName}"`));
6325
6224
  console.log(BORDER10(" \u2551"));
6326
- if (!fs11.existsSync(sourceDir)) {
6225
+ if (!fs10.existsSync(sourceDir)) {
6327
6226
  console.log(BORDER10(" \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D"));
6328
6227
  console.log("");
6329
6228
  console.log(RED5(` \u274C Source directory not found: ${sourceDir}`));
@@ -6332,22 +6231,22 @@ async function runBackup(options) {
6332
6231
  return;
6333
6232
  }
6334
6233
  const tmpDir = getTempDir2();
6335
- const archivePath = path13.join(tmpDir, "bob-backup.tar.gz");
6336
- const encryptedPath = path13.join(tmpDir, "bob-backup.bob.enc");
6234
+ const archivePath = path12.join(tmpDir, "bob-backup.tar.gz");
6235
+ const encryptedPath = path12.join(tmpDir, "bob-backup.bob.enc");
6337
6236
  try {
6338
6237
  const compressSpinner = ora11({ text: GRAY5(" Compressing ..."), spinner: "dots" }).start();
6339
6238
  const tar = await import("tar");
6340
- const relativeSource = path13.relative(os4.homedir(), sourceDir);
6239
+ const relativeSource = path12.relative(os3.homedir(), sourceDir);
6341
6240
  await tar.create(
6342
- { gzip: true, file: archivePath, cwd: os4.homedir() },
6241
+ { gzip: true, file: archivePath, cwd: os3.homedir() },
6343
6242
  [relativeSource]
6344
6243
  );
6345
- const archiveStats = fs11.statSync(archivePath);
6244
+ const archiveStats = fs10.statSync(archivePath);
6346
6245
  const estimatedSizeGB = archiveStats.size / (1024 * 1024 * 1024);
6347
6246
  compressSpinner.succeed(GREEN5(` Compressing ${displayName} ...`) + GRAY5(` ${formatBytes(archiveStats.size)}`));
6348
6247
  const encryptSpinner = ora11({ text: GRAY5(" Encrypting archive ..."), spinner: "dots" }).start();
6349
6248
  encrypt2(archivePath, encryptedPath, config.uid);
6350
- const encryptedStats = fs11.statSync(encryptedPath);
6249
+ const encryptedStats = fs10.statSync(encryptedPath);
6351
6250
  encryptSpinner.succeed(GREEN5(" Encrypting archive ...") + GRAY5(` ${formatBytes(encryptedStats.size)}`));
6352
6251
  const urlSpinner = ora11({ text: GRAY5(" Requesting upload authorization ..."), spinner: "dots" }).start();
6353
6252
  let uploadResult;
@@ -6378,7 +6277,7 @@ async function runBackup(options) {
6378
6277
  return;
6379
6278
  }
6380
6279
  const uploadSpinner = ora11({ text: GRAY5(" Uploading to S3 ..."), spinner: "dots" }).start();
6381
- const encryptedData = fs11.readFileSync(encryptedPath);
6280
+ const encryptedData = fs10.readFileSync(encryptedPath);
6382
6281
  await axios2.put(uploadResult.uploadUrl, encryptedData, {
6383
6282
  headers: { "Content-Type": "application/octet-stream", "Content-Length": encryptedData.length },
6384
6283
  maxBodyLength: Infinity,
@@ -6437,8 +6336,8 @@ async function runSourceBackup(options) {
6437
6336
  if (archiveName) console.log(BORDER10(" \u2551") + GRAY5(` Archive: "${archiveName}"`));
6438
6337
  console.log(BORDER10(" \u2551"));
6439
6338
  if (isFileMode) {
6440
- const absoluteFilePath = path13.resolve(projectDir, filePath);
6441
- if (!fs11.existsSync(absoluteFilePath)) {
6339
+ const absoluteFilePath = path12.resolve(projectDir, filePath);
6340
+ if (!fs10.existsSync(absoluteFilePath)) {
6442
6341
  console.log(BORDER10(" \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D"));
6443
6342
  console.log("");
6444
6343
  console.log(RED5(` \u274C File not found: ${filePath}`));
@@ -6446,7 +6345,7 @@ async function runSourceBackup(options) {
6446
6345
  return;
6447
6346
  }
6448
6347
  } else {
6449
- if (!fs11.existsSync(projectDir)) {
6348
+ if (!fs10.existsSync(projectDir)) {
6450
6349
  console.log(BORDER10(" \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D"));
6451
6350
  console.log("");
6452
6351
  console.log(RED5(` \u274C Project directory not found: ${projectDir}`));
@@ -6455,21 +6354,21 @@ async function runSourceBackup(options) {
6455
6354
  }
6456
6355
  }
6457
6356
  const tmpDir = getTempDir2();
6458
- const archivePath = path13.join(tmpDir, "bob-source.tar.gz");
6459
- const encryptedPath = path13.join(tmpDir, "bob-source.bob.enc");
6357
+ const archivePath = path12.join(tmpDir, "bob-source.tar.gz");
6358
+ const encryptedPath = path12.join(tmpDir, "bob-source.bob.enc");
6460
6359
  try {
6461
6360
  const compressSpinner = ora11({ text: GRAY5(" Compressing source ..."), spinner: "dots" }).start();
6462
6361
  const tar = await import("tar");
6463
6362
  if (isFileMode) {
6464
- const relativeFilePath = path13.normalize(filePath).replace(/\\/g, "/");
6363
+ const relativeFilePath = path12.normalize(filePath).replace(/\\/g, "/");
6465
6364
  await tar.create(
6466
6365
  { gzip: true, file: archivePath, cwd: projectDir },
6467
6366
  [relativeFilePath]
6468
6367
  );
6469
6368
  } else {
6470
6369
  const ignorePatterns = loadGitignorePatterns(projectDir);
6471
- const parentDir = path13.dirname(projectDir);
6472
- const projectDirName = path13.basename(projectDir);
6370
+ const parentDir = path12.dirname(projectDir);
6371
+ const projectDirName = path12.basename(projectDir);
6473
6372
  await tar.create(
6474
6373
  {
6475
6374
  gzip: true,
@@ -6480,14 +6379,14 @@ async function runSourceBackup(options) {
6480
6379
  [projectDirName]
6481
6380
  );
6482
6381
  }
6483
- const archiveStats = fs11.statSync(archivePath);
6382
+ const archiveStats = fs10.statSync(archivePath);
6484
6383
  const estimatedSizeGB = archiveStats.size / (1024 * 1024 * 1024);
6485
6384
  compressSpinner.succeed(
6486
6385
  GREEN5(` Compressing ${isFileMode ? filePath : projectName} ...`) + GRAY5(` ${formatBytes(archiveStats.size)}`)
6487
6386
  );
6488
6387
  const encryptSpinner = ora11({ text: GRAY5(" Encrypting ..."), spinner: "dots" }).start();
6489
6388
  encrypt2(archivePath, encryptedPath, config.uid);
6490
- const encryptedStats = fs11.statSync(encryptedPath);
6389
+ const encryptedStats = fs10.statSync(encryptedPath);
6491
6390
  encryptSpinner.succeed(GREEN5(" Encrypting ...") + GRAY5(` ${formatBytes(encryptedStats.size)}`));
6492
6391
  const urlSpinner = ora11({ text: GRAY5(" Requesting upload authorization ..."), spinner: "dots" }).start();
6493
6392
  let uploadResult;
@@ -6510,7 +6409,7 @@ async function runSourceBackup(options) {
6510
6409
  return;
6511
6410
  }
6512
6411
  const uploadSpinner = ora11({ text: GRAY5(" Uploading to S3 ..."), spinner: "dots" }).start();
6513
- const encryptedData = fs11.readFileSync(encryptedPath);
6412
+ const encryptedData = fs10.readFileSync(encryptedPath);
6514
6413
  await axios2.put(uploadResult.uploadUrl, encryptedData, {
6515
6414
  headers: { "Content-Type": "application/octet-stream", "Content-Length": encryptedData.length },
6516
6415
  maxBodyLength: Infinity,
@@ -6571,7 +6470,7 @@ function registerBackupCommand(program2) {
6571
6470
  let sourceDir;
6572
6471
  let displayName;
6573
6472
  if (isGlobal) {
6574
- sourceDir = BOB_DIR4;
6473
+ sourceDir = BOB_DIR3;
6575
6474
  displayName = "~/.bob/ (global)";
6576
6475
  } else {
6577
6476
  sourceDir = getProjectBackupDir(projectName);
@@ -6748,13 +6647,10 @@ function registerBackupCommand(program2) {
6748
6647
  return;
6749
6648
  }
6750
6649
  const tmpDir = getTempDir2();
6751
- const downloadPath = path13.join(tmpDir, "bob-backup.bob.enc");
6752
- const decryptedPath = path13.join(tmpDir, "bob-backup.tar.gz");
6650
+ const downloadPath = path12.join(tmpDir, "bob-backup.bob.enc");
6651
+ const decryptedPath = path12.join(tmpDir, "bob-backup.tar.gz");
6753
6652
  try {
6754
- const dlSpinner = ora11({
6755
- text: GRAY5(` Downloading ${label} ...`),
6756
- spinner: "dots"
6757
- }).start();
6653
+ const dlSpinner = ora11({ text: GRAY5(` Downloading ${label} ...`), spinner: "dots" }).start();
6758
6654
  let downloadAction;
6759
6655
  if (isSource) {
6760
6656
  downloadAction = selected.type === "archive" ? "requestSourceArchiveDownload" : "requestSourceDownload";
@@ -6774,49 +6670,44 @@ function registerBackupCommand(program2) {
6774
6670
  responseType: "arraybuffer",
6775
6671
  maxContentLength: Infinity
6776
6672
  });
6777
- fs11.writeFileSync(downloadPath, Buffer.from(response.data));
6673
+ fs10.writeFileSync(downloadPath, Buffer.from(response.data));
6778
6674
  dlSpinner.succeed(GREEN5(` Downloading ${label} ...`));
6779
6675
  const decryptSpinner = ora11({ text: GRAY5(" Decrypting ..."), spinner: "dots" }).start();
6780
6676
  decrypt2(downloadPath, decryptedPath, config.uid);
6781
6677
  decryptSpinner.succeed(GREEN5(" Decrypting ..."));
6782
- const backupSpinner = ora11({
6783
- text: GRAY5(" Backing up current state ..."),
6784
- spinner: "dots"
6785
- }).start();
6678
+ const backupSpinner = ora11({ text: GRAY5(" Backing up current state ..."), spinner: "dots" }).start();
6786
6679
  let preRestoreBackup;
6787
6680
  if (isSource && filePath) {
6788
- const absoluteFilePath = path13.resolve(projectDir, filePath);
6789
- const backupDir = path13.join(projectDir, ".bob-backups");
6790
- if (!fs11.existsSync(backupDir)) fs11.mkdirSync(backupDir, { recursive: true });
6681
+ const absoluteFilePath = path12.resolve(projectDir, filePath);
6682
+ const backupDir = path12.join(projectDir, ".bob-backups");
6683
+ if (!fs10.existsSync(backupDir)) fs10.mkdirSync(backupDir, { recursive: true });
6791
6684
  const backupFileName = filePath.replace(/[\/\\]/g, "_") + `.${Date.now()}.bak`;
6792
- preRestoreBackup = path13.join(backupDir, backupFileName);
6793
- if (fs11.existsSync(absoluteFilePath)) {
6794
- fs11.copyFileSync(absoluteFilePath, preRestoreBackup);
6685
+ preRestoreBackup = path12.join(backupDir, backupFileName);
6686
+ if (fs10.existsSync(absoluteFilePath)) {
6687
+ fs10.copyFileSync(absoluteFilePath, preRestoreBackup);
6795
6688
  }
6796
6689
  } else if (isSource) {
6797
6690
  preRestoreBackup = `${projectDir}-pre-restore-${Date.now()}`;
6798
- if (fs11.existsSync(projectDir)) {
6799
- fs11.cpSync(projectDir, preRestoreBackup, { recursive: true });
6691
+ if (fs10.existsSync(projectDir)) {
6692
+ fs10.cpSync(projectDir, preRestoreBackup, { recursive: true });
6800
6693
  }
6801
6694
  } else {
6802
- const restoreTarget = isGlobal ? BOB_DIR4 : getProjectBackupDir(projectName);
6695
+ const restoreTarget = isGlobal ? BOB_DIR3 : getProjectBackupDir(projectName);
6803
6696
  preRestoreBackup = `${restoreTarget}-pre-restore-${Date.now()}`;
6804
- if (fs11.existsSync(restoreTarget)) {
6805
- fs11.cpSync(restoreTarget, preRestoreBackup, { recursive: true });
6697
+ if (fs10.existsSync(restoreTarget)) {
6698
+ fs10.cpSync(restoreTarget, preRestoreBackup, { recursive: true });
6806
6699
  }
6807
6700
  }
6808
- backupSpinner.succeed(
6809
- GREEN5(" Backing up current state ...") + GRAY5(` \u2192 ${path13.basename(preRestoreBackup)}`)
6810
- );
6701
+ backupSpinner.succeed(GREEN5(" Backing up current state ...") + GRAY5(` \u2192 ${path12.basename(preRestoreBackup)}`));
6811
6702
  const extractSpinner = ora11({ text: GRAY5(" Extracting ..."), spinner: "dots" }).start();
6812
6703
  const tar = await import("tar");
6813
6704
  if (isSource && filePath) {
6814
6705
  await tar.extract({ file: decryptedPath, cwd: projectDir });
6815
6706
  } else if (isSource) {
6816
- const parentDir = path13.dirname(projectDir);
6707
+ const parentDir = path12.dirname(projectDir);
6817
6708
  await tar.extract({ file: decryptedPath, cwd: parentDir });
6818
6709
  } else {
6819
- await tar.extract({ file: decryptedPath, cwd: os4.homedir() });
6710
+ await tar.extract({ file: decryptedPath, cwd: os3.homedir() });
6820
6711
  }
6821
6712
  extractSpinner.succeed(GREEN5(" Extracting ..."));
6822
6713
  console.log("");
@@ -6824,13 +6715,13 @@ function registerBackupCommand(program2) {
6824
6715
  console.log(BORDER10(" \u2551") + GREEN5(" \u2705 Restore complete. ") + BORDER10("\u2551"));
6825
6716
  if (isSource && filePath) {
6826
6717
  console.log(BORDER10(" \u2551") + GRAY5(` Restored: ${filePath}`));
6827
- console.log(BORDER10(" \u2551") + GRAY5(` Backup: .bob-backups/${path13.basename(preRestoreBackup)}`));
6718
+ console.log(BORDER10(" \u2551") + GRAY5(` Backup: .bob-backups/${path12.basename(preRestoreBackup)}`));
6828
6719
  } else if (isSource) {
6829
6720
  console.log(BORDER10(" \u2551") + GRAY5(` Restored: ${projectName}/ source`));
6830
- console.log(BORDER10(" \u2551") + GRAY5(` Backup: ${path13.basename(preRestoreBackup)}/`));
6721
+ console.log(BORDER10(" \u2551") + GRAY5(` Backup: ${path12.basename(preRestoreBackup)}/`));
6831
6722
  } else {
6832
6723
  console.log(BORDER10(" \u2551") + GRAY5(` Restored: ${isGlobal ? "~/.bob/" : `~/.bob/projects/${projectName}/`}`));
6833
- console.log(BORDER10(" \u2551") + GRAY5(` Backup: ${path13.basename(preRestoreBackup)}`));
6724
+ console.log(BORDER10(" \u2551") + GRAY5(` Backup: ${path12.basename(preRestoreBackup)}`));
6834
6725
  }
6835
6726
  console.log(BORDER10(" \u2551") + GRAY5(` From: ${label}`));
6836
6727
  console.log(BORDER10(" \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D"));
@@ -6871,10 +6762,11 @@ function registerBackupCommand(program2) {
6871
6762
 
6872
6763
  // bin/bob.ts
6873
6764
  var program = new Command();
6874
- program.name("bob").description("Bob's CLI \u2014 AI coding assistant and Forge orchestrator").version("0.1.3");
6765
+ program.name("bob").description("Bob's CLI \u2014 AI coding assistant and Forge orchestrator").version("0.7.0");
6875
6766
  program.command("whoami").description("Show current authentication status and configuration").action(() => {
6876
6767
  const config = getConfig();
6877
- const projectName = path14.basename(process.cwd());
6768
+ const projectName = path13.basename(process.cwd());
6769
+ const projectConvoId = getActiveConversationId(process.cwd()) || config.conversationId;
6878
6770
  console.log("");
6879
6771
  console.log(chalk25.bold(" \u{1F916} Bob's CLI"));
6880
6772
  console.log(chalk25.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
@@ -6884,7 +6776,7 @@ program.command("whoami").description("Show current authentication status and co
6884
6776
  console.log(` ${chalk25.cyan("Mode:")} ${config.personalizationMode ? "Personalized" : config.consultantMode ? "Consultant" : "Standard"}`);
6885
6777
  console.log(` ${chalk25.cyan("IDRP:")} ${config.idrp ? "Enabled" : "Disabled"}`);
6886
6778
  console.log(` ${chalk25.cyan("Project:")} ${projectName} (${process.cwd()})`);
6887
- console.log(` ${chalk25.cyan("Session:")} ${config.conversationId ? config.conversationId.slice(0, 20) + "..." : "None"}`);
6779
+ console.log(` ${chalk25.cyan("Session:")} ${projectConvoId ? projectConvoId.slice(0, 20) + "..." : "None"}`);
6888
6780
  console.log("");
6889
6781
  if (!config.loggedIn) {
6890
6782
  console.log(chalk25.gray(" Run `bob login` to authenticate."));