@bobsworkshop/cli 1.0.0 → 1.0.1

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,7 +1,7 @@
1
- #!/usr/bin/env node
2
1
  import {
3
2
  buildLocalContext,
4
3
  callCloudFunction,
4
+ callHTTPFunction,
5
5
  callLocalModel,
6
6
  completeTask,
7
7
  createAnalysisRun,
@@ -27,7 +27,7 @@ import {
27
27
  setConfigValue,
28
28
  stripCodeBlockFromResponse,
29
29
  updateManifestProgress
30
- } from "./chunk-NZW7H2BY.js";
30
+ } from "./chunk-WRMNJJA6.js";
31
31
  import {
32
32
  agentExists,
33
33
  createAgent,
@@ -485,8 +485,8 @@ ${stderr}`);
485
485
 
486
486
  // bin/bob.ts
487
487
  import { Command } from "commander";
488
- import chalk31 from "chalk";
489
- import * as path22 from "path";
488
+ import chalk32 from "chalk";
489
+ import * as path23 from "path";
490
490
 
491
491
  // src/commands/config.ts
492
492
  import chalk from "chalk";
@@ -757,6 +757,29 @@ async function getTodayMessages(projectName) {
757
757
  return msg.timestamp >= twentyFourHoursAgo;
758
758
  });
759
759
  }
760
+ function buildDNAString() {
761
+ const dna = loadCurrentDNA();
762
+ if (!dna) return null;
763
+ const weekly = loadWeeklyProfiles(1)[0] || null;
764
+ const lines = [
765
+ "### USER BEHAVIORAL DNA ###",
766
+ `Archetype: ${dna.archetype || "Unknown"}`,
767
+ `Communication Style: ${dna.communicationStyle || "Unknown"}`,
768
+ `Work Rhythm: ${dna.workRhythm || "Unknown"}`,
769
+ `Decision Making: ${dna.decisionMaking || "Unknown"}`,
770
+ `Emotional State: ${dna.emotionalState || "Unknown"}`
771
+ ];
772
+ if (dna.growth) lines.push(`Growth Focus: ${dna.growth}`);
773
+ if (dna.source) lines.push(`Profile Source: ${dna.source} (${dna.lastUpdated || "unknown date"})`);
774
+ if (weekly) {
775
+ lines.push("");
776
+ lines.push("--- WEEKLY TRAJECTORY ---");
777
+ if (weekly.trajectory) lines.push(`Weekly Arc: ${weekly.trajectory}`);
778
+ if (weekly.moodShift) lines.push(`Mood Shift: ${weekly.moodShift}`);
779
+ if (weekly.focusEvolution) lines.push(`Focus Evolution: ${weekly.focusEvolution}`);
780
+ }
781
+ return lines.join("\n");
782
+ }
760
783
 
761
784
  // src/ai/persona.ts
762
785
  var STANDARD_STYLE_PROMPT = `You are Bob: friendly, direct, senior-level engineering partner.
@@ -3462,7 +3485,7 @@ function registerAnalyseCommand(program2) {
3462
3485
  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) => {
3463
3486
  const config = getConfig();
3464
3487
  if (options.auto) {
3465
- const { runAutoFix } = await import("./analyse-auto-I7TIDS4E.js");
3488
+ const { runAutoFix } = await import("./analyse-auto-VFZGDTTQ.js");
3466
3489
  const category = options.bugs ? "bugs" : options.features ? "features" : options.improvements ? "improvements" : options.upgrades ? "upgrades" : void 0;
3467
3490
  await runAutoFix({
3468
3491
  category,
@@ -3472,7 +3495,7 @@ function registerAnalyseCommand(program2) {
3472
3495
  return;
3473
3496
  }
3474
3497
  if (options.bugs || options.features || options.improvements || options.upgrades) {
3475
- const { showInteractiveResults } = await import("./analyse-results-QSTTMRQE.js");
3498
+ const { showInteractiveResults } = await import("./analyse-results-XAVKSCF4.js");
3476
3499
  const category = options.bugs ? "bugs" : options.features ? "features" : options.improvements ? "improvements" : "upgrades";
3477
3500
  await showInteractiveResults(config, category, options.sort, options.search);
3478
3501
  return;
@@ -10728,10 +10751,10 @@ function renderExecutionEvent(event, agentNames) {
10728
10751
  }
10729
10752
  }
10730
10753
  async function renderPostMissionFeedback(mission, cwd) {
10731
- const readline11 = await import("readline");
10732
- const path23 = await import("path");
10733
- const fs18 = await import("fs");
10734
- const os8 = await import("os");
10754
+ const readline12 = await import("readline");
10755
+ const path24 = await import("path");
10756
+ const fs19 = await import("fs");
10757
+ const os9 = await import("os");
10735
10758
  console.log("");
10736
10759
  console.log(DIRECTOR_COLOR(" \u2554\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\u2557"));
10737
10760
  console.log(DIRECTOR_COLOR(" \u2551") + AMBER9(" \u{1F4DD} Mission Feedback \u2014 Help train the agents"));
@@ -10742,7 +10765,7 @@ async function renderPostMissionFeedback(mission, cwd) {
10742
10765
  console.log("");
10743
10766
  const completedTasks = mission.tasks.filter((t) => t.status === "completed");
10744
10767
  const feedback = [];
10745
- const rl = readline11.createInterface({ input: process.stdin, output: process.stdout });
10768
+ const rl = readline12.createInterface({ input: process.stdin, output: process.stdout });
10746
10769
  for (const task of completedTasks) {
10747
10770
  const chip = renderAgentChip(task.assignedTo, mission.tasks.map((t) => t.assignedTo), true);
10748
10771
  console.log(` ${chip} ${GRAY8(task.instruction.slice(0, 60))}`);
@@ -10774,21 +10797,21 @@ async function renderPostMissionFeedback(mission, cwd) {
10774
10797
  }
10775
10798
  rl.close();
10776
10799
  if (feedback.length === 0) return;
10777
- const projectName = path23.basename(cwd);
10778
- const feedbackDir = path23.join(os8.homedir(), ".bob", "projects", projectName, "agents", "feedback");
10779
- if (!fs18.existsSync(feedbackDir)) fs18.mkdirSync(feedbackDir, { recursive: true });
10800
+ const projectName = path24.basename(cwd);
10801
+ const feedbackDir = path24.join(os9.homedir(), ".bob", "projects", projectName, "agents", "feedback");
10802
+ if (!fs19.existsSync(feedbackDir)) fs19.mkdirSync(feedbackDir, { recursive: true });
10780
10803
  const sessionFeedback = {
10781
10804
  missionId: mission.id,
10782
10805
  missionDescription: mission.description,
10783
10806
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
10784
10807
  tasks: feedback
10785
10808
  };
10786
- const feedbackFile = path23.join(feedbackDir, `${mission.id}.json`);
10787
- fs18.writeFileSync(feedbackFile, JSON.stringify(sessionFeedback, null, 2));
10788
- const globalDir = path23.join(os8.homedir(), ".bob", "global", "agent-training");
10789
- if (!fs18.existsSync(globalDir)) fs18.mkdirSync(globalDir, { recursive: true });
10790
- const globalFile = path23.join(globalDir, `${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]}_${mission.id}.json`);
10791
- fs18.writeFileSync(globalFile, JSON.stringify(sessionFeedback, null, 2));
10809
+ const feedbackFile = path24.join(feedbackDir, `${mission.id}.json`);
10810
+ fs19.writeFileSync(feedbackFile, JSON.stringify(sessionFeedback, null, 2));
10811
+ const globalDir = path24.join(os9.homedir(), ".bob", "global", "agent-training");
10812
+ if (!fs19.existsSync(globalDir)) fs19.mkdirSync(globalDir, { recursive: true });
10813
+ const globalFile = path24.join(globalDir, `${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]}_${mission.id}.json`);
10814
+ fs19.writeFileSync(globalFile, JSON.stringify(sessionFeedback, null, 2));
10792
10815
  console.log(GREEN9(` \u2705 Feedback saved. Thank you for helping train the agents.`));
10793
10816
  console.log(GRAY8(` Saved to: ~/.bob/projects/${projectName}/agents/feedback/`));
10794
10817
  console.log(GRAY8(` Global: ~/.bob/global/agent-training/`));
@@ -10823,7 +10846,7 @@ function renderMissionComplete(mission) {
10823
10846
  console.log("");
10824
10847
  }
10825
10848
  async function renderPostMissionCommitPrompt(mission, cwd) {
10826
- const readline11 = await import("readline");
10849
+ const readline12 = await import("readline");
10827
10850
  const allCreated = [];
10828
10851
  const allModified = [];
10829
10852
  for (const task of mission.tasks) {
@@ -10899,7 +10922,7 @@ async function renderPostMissionCommitPrompt(mission, cwd) {
10899
10922
  console.log(BORDER13(" \u2551") + GRAY8(` ${allCreated.length} created \u2502 ${allModified.length} modified \u2502 ${totalFiles} total`));
10900
10923
  console.log(BORDER13(" \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"));
10901
10924
  console.log("");
10902
- const rl = readline11.createInterface({
10925
+ const rl = readline12.createInterface({
10903
10926
  input: process.stdin,
10904
10927
  output: process.stdout
10905
10928
  });
@@ -11248,26 +11271,574 @@ async function executeMission(mission, agents, cwd, localEndpoint, options) {
11248
11271
  }
11249
11272
  }
11250
11273
 
11274
+ // src/commands/userbob.ts
11275
+ import chalk31 from "chalk";
11276
+ import * as readline11 from "readline";
11277
+ import * as fs18 from "fs";
11278
+ import * as path22 from "path";
11279
+ import * as os8 from "os";
11280
+ var PURPLE5 = chalk31.hex("#AB47BC");
11281
+ var AMBER11 = chalk31.hex("#FFAB00");
11282
+ var GREEN11 = chalk31.hex("#66BB6A");
11283
+ var CYAN11 = chalk31.hex("#26C6DA");
11284
+ var RED10 = chalk31.hex("#EF5350");
11285
+ var GRAY10 = chalk31.gray;
11286
+ var BLUE5 = chalk31.hex("#42A5F5");
11287
+ var BOB_COLOR = chalk31.hex("#E66F24");
11288
+ var BORDER14 = chalk31.hex("#455A64");
11289
+ var WHITE7 = chalk31.white;
11290
+ var BOB_DIR8 = path22.join(os8.homedir(), ".bob");
11291
+ function getSessionFilePath() {
11292
+ const projectName = path22.basename(process.cwd());
11293
+ return path22.join(BOB_DIR8, "projects", projectName, "userbob-session.json");
11294
+ }
11295
+ function writeSessionFile(data) {
11296
+ const filePath = getSessionFilePath();
11297
+ const dir = path22.dirname(filePath);
11298
+ if (!fs18.existsSync(dir)) fs18.mkdirSync(dir, { recursive: true });
11299
+ fs18.writeFileSync(filePath, JSON.stringify(data, null, 2));
11300
+ }
11301
+ function readSessionFile() {
11302
+ const filePath = getSessionFilePath();
11303
+ if (!fs18.existsSync(filePath)) return null;
11304
+ try {
11305
+ return JSON.parse(fs18.readFileSync(filePath, "utf-8"));
11306
+ } catch {
11307
+ return null;
11308
+ }
11309
+ }
11310
+ function clearSessionFile() {
11311
+ const filePath = getSessionFilePath();
11312
+ if (fs18.existsSync(filePath)) fs18.unlinkSync(filePath);
11313
+ }
11314
+ function renderHUD(sat, target, stag, stagTarget, div, divTarget, grading) {
11315
+ const satBar = sat >= target ? GREEN11(`${sat}%`) : sat >= target * 0.7 ? AMBER11(`${sat}%`) : RED10(`${sat}%`);
11316
+ console.log("");
11317
+ console.log(BORDER14(" \u2500\u2500\u2500 MISSION CONTROL \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\u2500\u2500\u2500\u2500\u2500"));
11318
+ console.log(
11319
+ ` SAT: ${satBar} \u2192 ${target}% \u2502 STAG: ${stag}/${stagTarget > 0 ? stagTarget : "\u221E"} \u2502 DIV: ${div}/${divTarget > 0 ? divTarget : "\u221E"} \u2502 GRADE: ${grading}`
11320
+ );
11321
+ console.log(BORDER14(" \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\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"));
11322
+ console.log("");
11323
+ }
11324
+ function stripMarkdown2(text) {
11325
+ return text.replace(/\*\*(.+?)\*\*/g, "$1").replace(/\*(.+?)\*/g, "$1").replace(/^#{1,6}\s+/gm, "").replace(/^---+$/gm, "").replace(/^>\s?/gm, "").replace(/`([^`]+)`/g, "$1").replace(/^\s*[-*+]\s+/gm, " \u2022 ").replace(/^\s*\d+\.\s+/gm, " ").replace(/\n{3,}/g, "\n\n").trim();
11326
+ }
11327
+ function renderMessage(sender, message, audit) {
11328
+ const cleanMsg = stripMarkdown2(message);
11329
+ const maxWidth = 70;
11330
+ const lines = wrapText3(cleanMsg, maxWidth - 4);
11331
+ if (sender === "userBob") {
11332
+ const topBar = PURPLE5(` \u250C\u2500 UserBob ${"\u2500".repeat(maxWidth - 13)}\u2510`);
11333
+ const bottomBar = PURPLE5(` \u2514${"\u2500".repeat(maxWidth - 2)}\u2518`);
11334
+ console.log("");
11335
+ console.log(topBar);
11336
+ for (const line of lines) {
11337
+ const padded = line.padEnd(maxWidth - 4);
11338
+ console.log(PURPLE5(" \u2502") + ` ${padded}` + PURPLE5(" \u2502"));
11339
+ }
11340
+ console.log(bottomBar);
11341
+ if (audit) {
11342
+ const chips = [];
11343
+ if (audit.satisfactionScore !== void 0) chips.push(CYAN11(`[SAT: ${audit.satisfactionScore}%]`));
11344
+ if (audit.resemblanceScore !== void 0) chips.push(BLUE5(`[RES: ${audit.resemblanceScore}%]`));
11345
+ if (audit.reasoning) chips.push(GRAY10(`[${String(audit.reasoning).slice(0, 50)}...]`));
11346
+ if (chips.length > 0) console.log(" " + chips.join(" "));
11347
+ }
11348
+ } else if (sender === "bob") {
11349
+ const indent = " ";
11350
+ const topBar = BOB_COLOR(`${indent}\u250C${"\u2500".repeat(maxWidth - 12)}\u2500 Bob \u2500\u2510`);
11351
+ const bottomBar = BOB_COLOR(`${indent}\u2514${"\u2500".repeat(maxWidth - 2)}\u2518`);
11352
+ console.log("");
11353
+ console.log(topBar);
11354
+ for (const line of lines) {
11355
+ const padded = line.padEnd(maxWidth - 4);
11356
+ console.log(BOB_COLOR(`${indent}\u2502`) + ` ${padded}` + BOB_COLOR(" \u2502"));
11357
+ }
11358
+ console.log(bottomBar);
11359
+ } else if (sender === "system") {
11360
+ console.log("");
11361
+ console.log(CYAN11(" \u2500\u2500 SYSTEM \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\u2500"));
11362
+ console.log(GRAY10(` ${cleanMsg}`));
11363
+ console.log(CYAN11(" \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\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
11364
+ } else {
11365
+ console.log("");
11366
+ console.log(GRAY10(` [${sender.toUpperCase()}] ${cleanMsg}`));
11367
+ }
11368
+ }
11369
+ function wrapText3(text, maxWidth) {
11370
+ const lines = [];
11371
+ const paragraphs = text.split("\n");
11372
+ for (const paragraph of paragraphs) {
11373
+ if (paragraph.trim() === "") {
11374
+ lines.push("");
11375
+ continue;
11376
+ }
11377
+ const words = paragraph.split(" ");
11378
+ let currentLine = "";
11379
+ for (const word of words) {
11380
+ if ((currentLine + " " + word).trim().length > maxWidth) {
11381
+ if (currentLine) lines.push(currentLine.trim());
11382
+ currentLine = word;
11383
+ } else {
11384
+ currentLine = currentLine ? currentLine + " " + word : word;
11385
+ }
11386
+ }
11387
+ if (currentLine.trim()) lines.push(currentLine.trim());
11388
+ }
11389
+ return lines;
11390
+ }
11391
+ async function handleSlashCommand(input, config, conversationId) {
11392
+ const trimmed = input.trim();
11393
+ if (trimmed === "/status") {
11394
+ try {
11395
+ const response = await callCloudFunction("getCLIConversationMessages", { conversationId, since: null });
11396
+ const state = response?.state || {};
11397
+ console.log("");
11398
+ console.log(AMBER11(" \u2500\u2500\u2500 Current Parameters \u2500\u2500\u2500"));
11399
+ console.log(GRAY10(` Target Satisfaction : ${state.targetSatisfaction ?? "N/A"}`));
11400
+ console.log(GRAY10(` Grading Standard : ${state.gradingStandard ?? "N/A"}`));
11401
+ console.log(GRAY10(` Current Satisfaction: ${state.currentSatisfaction ?? "N/A"}`));
11402
+ console.log(GRAY10(` Stalemate : ${state.stalemateState?.current ?? 0}/${state.stalemateState?.target ?? "\u221E"}`));
11403
+ console.log(GRAY10(` Divergence : ${state.divergenceState?.current ?? 0}/${state.divergenceState?.target ?? "\u221E"}`));
11404
+ console.log(GRAY10(` Status : ${state.simulationStatus ?? "UNKNOWN"}`));
11405
+ console.log(GRAY10(` Active : ${state.userBobActive ?? "UNKNOWN"}`));
11406
+ console.log("");
11407
+ } catch {
11408
+ console.log(RED10(" \u274C Could not fetch conversation state."));
11409
+ }
11410
+ return;
11411
+ }
11412
+ const setMatch = trimmed.match(/^\/set\s+(grading|target|stag|div)\s+(\d+)$/i);
11413
+ if (setMatch) {
11414
+ const param = setMatch[1].toLowerCase();
11415
+ const value = parseInt(setMatch[2], 10);
11416
+ const paramMap = {
11417
+ grading: "gradingStandard",
11418
+ target: "targetSatisfaction",
11419
+ stag: "stalemateZone",
11420
+ div: "divergenceThreshold"
11421
+ };
11422
+ try {
11423
+ await callHTTPFunction("userSimManagerService", {
11424
+ action: "updateParameters",
11425
+ conversationId,
11426
+ uid: config.uid,
11427
+ email: config.email,
11428
+ params: { [paramMap[param]]: value }
11429
+ });
11430
+ console.log(GREEN11(` \u2705 ${param} updated to ${value}`));
11431
+ } catch (e) {
11432
+ console.log(RED10(` \u274C Failed to update ${param}: ${e.message}`));
11433
+ }
11434
+ return;
11435
+ }
11436
+ const injectMatch = trimmed.match(/^\/inject\s+"(.+)"$/);
11437
+ if (injectMatch) {
11438
+ const note = injectMatch[1];
11439
+ try {
11440
+ await callHTTPFunction("userSimManagerService", {
11441
+ action: "injectNote",
11442
+ conversationId,
11443
+ uid: config.uid,
11444
+ email: config.email,
11445
+ note
11446
+ });
11447
+ console.log(GREEN11(` \u2705 Director's note injected.`));
11448
+ } catch (e) {
11449
+ console.log(RED10(` \u274C Failed to inject note: ${e.message}`));
11450
+ }
11451
+ return;
11452
+ }
11453
+ console.log(GRAY10(' Commands: /set grading|target|stag|div <n> /inject "note" /status /abort'));
11454
+ }
11455
+ async function runPlatformSimulation(config, conversationId, mission, params) {
11456
+ await callHTTPFunction("userSimManagerService", {
11457
+ action: "updateParameters",
11458
+ conversationId,
11459
+ uid: config.uid,
11460
+ email: config.email,
11461
+ params: {
11462
+ targetSatisfaction: params.target,
11463
+ gradingStandard: params.grading,
11464
+ stalemateZone: params.stag,
11465
+ divergenceThreshold: params.div
11466
+ }
11467
+ });
11468
+ await callHTTPFunction("userSimManagerService", {
11469
+ action: "injectNote",
11470
+ conversationId,
11471
+ uid: config.uid,
11472
+ email: config.email,
11473
+ note: mission
11474
+ });
11475
+ console.log(GREEN11(" \u2705 Mission injected. Simulation is running."));
11476
+ console.log("");
11477
+ console.log(BORDER14(" \u2500\u2500\u2500 LIVE SIMULATION \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\u2500\u2500\u2500\u2500\u2500"));
11478
+ console.log(GRAY10(" Messages will stream below as Bob and UserBob interact."));
11479
+ console.log(GRAY10(" You can type commands at any time:"));
11480
+ console.log("");
11481
+ console.log(AMBER11(" /abort") + GRAY10(" \u2014 Stop the simulation immediately"));
11482
+ console.log(AMBER11(" /set target 90") + GRAY10(" \u2014 Update satisfaction target"));
11483
+ console.log(AMBER11(" /set grading 70") + GRAY10(" \u2014 Update Teacher's Curve"));
11484
+ console.log(AMBER11(" /set stag 5") + GRAY10(" \u2014 Update stalemate threshold"));
11485
+ console.log(AMBER11(" /set div 3") + GRAY10(" \u2014 Update divergence threshold"));
11486
+ console.log(AMBER11(' /inject "note"') + GRAY10(" \u2014 Inject a director's note mid-session"));
11487
+ console.log(AMBER11(" /status") + GRAY10(" \u2014 Show current simulation parameters"));
11488
+ console.log("");
11489
+ console.log(BORDER14(" \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\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"));
11490
+ console.log("");
11491
+ let running = true;
11492
+ let lastMessageTimestamp = 0;
11493
+ let hudState = { sat: 0, target: params.target, stag: 0, stagTarget: params.stag, div: 0, divTarget: params.div, grading: params.grading };
11494
+ const sigintHandler = async () => {
11495
+ if (!running) return;
11496
+ running = false;
11497
+ console.log("\n");
11498
+ console.log(AMBER11(" \u{1F6D1} Aborting simulation..."));
11499
+ try {
11500
+ await callHTTPFunction("userSimManagerService", {
11501
+ action: "abortMission",
11502
+ conversationId,
11503
+ uid: config.uid,
11504
+ email: config.email
11505
+ });
11506
+ console.log(GREEN11(" \u2705 Simulation aborted."));
11507
+ } catch {
11508
+ }
11509
+ process.exit(0);
11510
+ };
11511
+ process.on("SIGINT", sigintHandler);
11512
+ const rl = readline11.createInterface({ input: process.stdin, output: process.stdout, terminal: true });
11513
+ rl.setPrompt("");
11514
+ rl.on("line", async (line) => {
11515
+ const trimmed = line.trim();
11516
+ if (!trimmed) return;
11517
+ if (trimmed === "/abort" || trimmed === "abort") {
11518
+ running = false;
11519
+ console.log(AMBER11(" \u{1F6D1} Aborting simulation..."));
11520
+ try {
11521
+ await callHTTPFunction("userSimManagerService", {
11522
+ action: "abortMission",
11523
+ conversationId,
11524
+ uid: config.uid,
11525
+ email: config.email
11526
+ });
11527
+ console.log(GREEN11(" \u2705 Simulation aborted."));
11528
+ } catch {
11529
+ }
11530
+ rl.close();
11531
+ process.exit(0);
11532
+ }
11533
+ await handleSlashCommand(trimmed, config, conversationId);
11534
+ });
11535
+ while (running) {
11536
+ await new Promise((r) => setTimeout(r, 3e3));
11537
+ try {
11538
+ const response = await callCloudFunction("getCLIConversationMessages", {
11539
+ conversationId,
11540
+ since: lastMessageTimestamp || null
11541
+ });
11542
+ const messages = response?.messages || [];
11543
+ const state = response?.state || {};
11544
+ for (const msg of messages) {
11545
+ renderMessage(msg.sender, msg.message, msg.simulationAudit);
11546
+ if (msg.timestamp && msg.timestamp > lastMessageTimestamp) {
11547
+ lastMessageTimestamp = msg.timestamp;
11548
+ }
11549
+ }
11550
+ if (state.currentSatisfaction !== void 0) hudState.sat = state.currentSatisfaction;
11551
+ if (state.targetSatisfaction !== void 0) hudState.target = state.targetSatisfaction;
11552
+ if (state.gradingStandard !== void 0) hudState.grading = state.gradingStandard;
11553
+ if (state.stalemateState) {
11554
+ hudState.stag = state.stalemateState.current ?? hudState.stag;
11555
+ hudState.stagTarget = state.stalemateState.target ?? hudState.stagTarget;
11556
+ }
11557
+ if (state.divergenceState) {
11558
+ hudState.div = state.divergenceState.current ?? hudState.div;
11559
+ hudState.divTarget = state.divergenceState.target ?? hudState.divTarget;
11560
+ }
11561
+ if (state.userBobActive === false || state.simulationStatus && state.simulationStatus !== "RUNNING") {
11562
+ if (messages.length > 0) {
11563
+ renderHUD(hudState.sat, hudState.target, hudState.stag, hudState.stagTarget, hudState.div, hudState.divTarget, hudState.grading);
11564
+ }
11565
+ console.log("");
11566
+ console.log(AMBER11(` \u{1F3C1} Simulation ended: ${state.simulationStatus || "INACTIVE"}`));
11567
+ console.log("");
11568
+ running = false;
11569
+ break;
11570
+ }
11571
+ if (messages.length > 0) {
11572
+ renderHUD(hudState.sat, hudState.target, hudState.stag, hudState.stagTarget, hudState.div, hudState.divTarget, hudState.grading);
11573
+ }
11574
+ } catch (e) {
11575
+ console.log(RED10(` \u274C Poll error: ${e.message}`));
11576
+ }
11577
+ }
11578
+ rl.close();
11579
+ process.removeListener("SIGINT", sigintHandler);
11580
+ }
11581
+ async function runLocalSimulation(config, dnaString, mission, params) {
11582
+ writeSessionFile({ active: true, turns: 0, mission });
11583
+ let running = true;
11584
+ let turns = 0;
11585
+ let conversationHistory = [];
11586
+ let sat = 0;
11587
+ let stalemateCurrent = 0;
11588
+ let divergenceCurrent = 0;
11589
+ let lastStatus = "";
11590
+ const sigintHandler = () => {
11591
+ running = false;
11592
+ writeSessionFile({ active: false });
11593
+ clearSessionFile();
11594
+ console.log("\n" + AMBER11(" \u{1F6D1} Simulation stopped."));
11595
+ process.exit(0);
11596
+ };
11597
+ process.on("SIGINT", sigintHandler);
11598
+ const rl = readline11.createInterface({ input: process.stdin, output: process.stdout, terminal: true });
11599
+ rl.setPrompt("");
11600
+ rl.on("line", (line) => {
11601
+ const t = line.trim();
11602
+ if (t === "/abort" || t === "abort") {
11603
+ running = false;
11604
+ writeSessionFile({ active: false });
11605
+ clearSessionFile();
11606
+ console.log(AMBER11(" \u{1F6D1} Simulation stopped."));
11607
+ rl.close();
11608
+ process.exit(0);
11609
+ }
11610
+ if (t.startsWith("/set ")) {
11611
+ const m = t.match(/^\/set\s+(grading|target|stag|div)\s+(\d+)$/i);
11612
+ if (m) {
11613
+ const val = parseInt(m[2], 10);
11614
+ if (m[1] === "grading") params.grading = val;
11615
+ if (m[1] === "target") params.target = val;
11616
+ if (m[1] === "stag") params.stag = val;
11617
+ if (m[1] === "div") params.div = val;
11618
+ console.log(GREEN11(` \u2705 ${m[1]} updated to ${val} (local)`));
11619
+ }
11620
+ }
11621
+ if (t === "/status") {
11622
+ console.log("");
11623
+ console.log(AMBER11(" \u2500\u2500\u2500 Local Sim Parameters \u2500\u2500\u2500"));
11624
+ console.log(GRAY10(` Target: ${params.target} \u2502 Grading: ${params.grading} \u2502 Stag Limit: ${params.stag} \u2502 Div Limit: ${params.div}`));
11625
+ console.log(GRAY10(` Current SAT: ${sat} \u2502 Turns: ${turns} \u2502 Stag: ${stalemateCurrent} \u2502 Div: ${divergenceCurrent}`));
11626
+ console.log("");
11627
+ }
11628
+ });
11629
+ const bobSystem = `You are Bob \u2014 a senior AI engineering consultant. A developer's digital twin (UserBob) is evaluating your work. Respond helpfully and directly to advance the mission. Mission context: ${mission}`;
11630
+ const userBobSystem = dnaString ? `You are a digital twin of a software engineer. You ARE this developer. Your personality, communication style, and engineering philosophy are defined below.
11631
+
11632
+ Mission: ${mission}
11633
+
11634
+ ${dnaString}
11635
+
11636
+ After each Bob response, evaluate it 0-100 on how well it advances YOUR mission. Reply with your natural reaction, then append exactly one JSON footer on its own line:
11637
+ {"satisfactionScore": <0-100>, "status": "CONVERGING|STAGNATING|DIVERGING"}` : `You are a digital twin of a software engineer. You have no personal profile loaded \u2014 respond based on the mission context only.
11638
+
11639
+ Mission: ${mission}
11640
+
11641
+ After each Bob response, evaluate it 0-100 on mission alignment. Reply with your reaction, then append exactly one JSON footer on its own line:
11642
+ {"satisfactionScore": <0-100>, "status": "CONVERGING|STAGNATING|DIVERGING"}`;
11643
+ console.log(BORDER14(" \u2500\u2500\u2500 LIVE LOCAL SIMULATION \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"));
11644
+ console.log(GRAY10(" Bob and UserBob will converse autonomously below."));
11645
+ console.log(GRAY10(" Commands:"));
11646
+ console.log(AMBER11(" /abort") + GRAY10(" \u2014 Stop the simulation"));
11647
+ console.log(AMBER11(" /set target 90") + GRAY10(" \u2014 Update satisfaction target"));
11648
+ console.log(AMBER11(" /set grading 70") + GRAY10(" \u2014 Update Teacher's Curve"));
11649
+ console.log(AMBER11(" /set stag 5") + GRAY10(" \u2014 Update stalemate threshold"));
11650
+ console.log(AMBER11(" /set div 3") + GRAY10(" \u2014 Update divergence threshold"));
11651
+ console.log(AMBER11(" /status") + GRAY10(" \u2014 Show current parameters"));
11652
+ console.log(BORDER14(" \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\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"));
11653
+ console.log("");
11654
+ const kickstart = `Mission received: "${mission}". Bob, what's your first move?`;
11655
+ console.log(PURPLE5(" UserBob > ") + WHITE7(kickstart));
11656
+ conversationHistory.push({ role: "user", content: kickstart });
11657
+ while (running) {
11658
+ const session = readSessionFile();
11659
+ if (!session?.active) {
11660
+ running = false;
11661
+ break;
11662
+ }
11663
+ turns++;
11664
+ try {
11665
+ const bobMessages = [
11666
+ { role: "system", content: bobSystem },
11667
+ ...conversationHistory
11668
+ ];
11669
+ const bobResponse = await callLocalModel(config.localEndpoint, bobMessages);
11670
+ console.log(BOB_COLOR(" Bob > ") + WHITE7(bobResponse));
11671
+ conversationHistory.push({ role: "assistant", content: bobResponse });
11672
+ const ubMessages = [
11673
+ { role: "system", content: userBobSystem },
11674
+ ...conversationHistory
11675
+ ];
11676
+ const ubResponse = await callLocalModel(config.localEndpoint, ubMessages);
11677
+ const jsonMatch = ubResponse.match(/\{[^}]*"satisfactionScore"[^}]*\}/);
11678
+ const cleanResponse = ubResponse.replace(/\{[^}]*"satisfactionScore"[^}]*\}/, "").trim();
11679
+ console.log(PURPLE5(" UserBob > ") + WHITE7(cleanResponse));
11680
+ let auditChips = [];
11681
+ if (jsonMatch) {
11682
+ try {
11683
+ const audit = JSON.parse(jsonMatch[0]);
11684
+ const rawScore = audit.satisfactionScore || 0;
11685
+ sat = Math.round(rawScore * (params.grading / 100));
11686
+ lastStatus = audit.status || "";
11687
+ auditChips = [CYAN11(`[SAT: ${sat}%]`), BLUE5(`[RAW: ${rawScore}]`), GRAY10(`[${lastStatus}]`)];
11688
+ if (lastStatus === "STAGNATING") {
11689
+ stalemateCurrent++;
11690
+ if (params.stag > 0 && stalemateCurrent >= params.stag) {
11691
+ console.log(" " + auditChips.join(" "));
11692
+ renderHUD(sat, params.target, stalemateCurrent, params.stag, divergenceCurrent, params.div, params.grading);
11693
+ console.log(AMBER11(` \u{1F3C1} Stalemate threshold reached (${stalemateCurrent}/${params.stag}). Simulation ended.`));
11694
+ running = false;
11695
+ break;
11696
+ }
11697
+ } else if (lastStatus === "DIVERGING") {
11698
+ divergenceCurrent++;
11699
+ stalemateCurrent = 0;
11700
+ if (params.div > 0 && divergenceCurrent >= params.div) {
11701
+ console.log(" " + auditChips.join(" "));
11702
+ renderHUD(sat, params.target, stalemateCurrent, params.stag, divergenceCurrent, params.div, params.grading);
11703
+ console.log(AMBER11(` \u{1F3C1} Divergence threshold reached (${divergenceCurrent}/${params.div}). Simulation ended.`));
11704
+ running = false;
11705
+ break;
11706
+ }
11707
+ } else if (lastStatus === "CONVERGING") {
11708
+ stalemateCurrent = 0;
11709
+ divergenceCurrent = 0;
11710
+ }
11711
+ } catch {
11712
+ }
11713
+ }
11714
+ if (auditChips.length) console.log(" " + auditChips.join(" "));
11715
+ conversationHistory.push({ role: "user", content: ubResponse });
11716
+ writeSessionFile({ active: true, turns, mission, sat });
11717
+ renderHUD(sat, params.target, stalemateCurrent, params.stag, divergenceCurrent, params.div, params.grading);
11718
+ if (sat >= params.target) {
11719
+ console.log(GREEN11(` \u{1F3AF} Target satisfaction ${params.target}% reached! Mission complete.`));
11720
+ running = false;
11721
+ break;
11722
+ }
11723
+ await new Promise((r) => setTimeout(r, 1e3));
11724
+ } catch (e) {
11725
+ console.log(RED10(` \u274C Local model error: ${e.message}`));
11726
+ console.log(GRAY10(" Retrying in 3 seconds..."));
11727
+ await new Promise((r) => setTimeout(r, 3e3));
11728
+ }
11729
+ }
11730
+ clearSessionFile();
11731
+ rl.close();
11732
+ process.removeListener("SIGINT", sigintHandler);
11733
+ console.log("");
11734
+ console.log(GRAY10(` Session complete. ${turns} turns processed.`));
11735
+ console.log("");
11736
+ }
11737
+ function registerUserBobCommand(program2) {
11738
+ program2.command("userbob [mission...]").description("Launch your UserBob digital twin simulation").option("--local", "Force local Ollama mode (Tier 1)").option("--target <number>", "Satisfaction target (default: 85)", "85").option("--grading <number>", "Teacher's curve grading standard (default: 50)", "50").option("--stag <number>", "Stalemate threshold \u2014 0 = infinite (default: 0)", "0").option("--div <number>", "Divergence threshold \u2014 0 = infinite (default: 0)", "0").option("--resume", "Resume without injecting a new mission note").action(async (missionArgs, options) => {
11739
+ const config = getConfig();
11740
+ const params = {
11741
+ target: parseInt(options.target, 10),
11742
+ grading: parseInt(options.grading, 10),
11743
+ stag: parseInt(options.stag, 10),
11744
+ div: parseInt(options.div, 10)
11745
+ };
11746
+ const usePlatform = !options.local && isAuthenticated();
11747
+ console.log("");
11748
+ console.log(BORDER14(" \u2554\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\u2557"));
11749
+ console.log(BORDER14(" \u2551") + PURPLE5(" \u{1F916} UserBob \u2014 Digital Twin Simulation"));
11750
+ console.log(BORDER14(" \u2551") + GRAY10(` Mode: ${usePlatform ? "Platform (Tier 3)" : "Local Ollama (Tier 1)"}`));
11751
+ console.log(BORDER14(" \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"));
11752
+ console.log("");
11753
+ const dna = buildDNAString();
11754
+ if (dna) {
11755
+ console.log(GREEN11(" \u2705 Behavioral DNA loaded."));
11756
+ } else {
11757
+ console.log(AMBER11(" \u26A0\uFE0F No behavioral profile found."));
11758
+ console.log(GRAY10(" UserBob performs significantly better with your DNA loaded."));
11759
+ console.log("");
11760
+ const rl = readline11.createInterface({ input: process.stdin, output: process.stdout, terminal: true });
11761
+ const answer = await new Promise((resolve4) => rl.question(AMBER11(" Run `bob profile --today` now? (y/n): "), resolve4));
11762
+ rl.close();
11763
+ if (answer.trim().toLowerCase() === "y") {
11764
+ console.log("");
11765
+ console.log(GRAY10(" Run `bob profile --today` in a separate terminal, then re-run `bob userbob`."));
11766
+ process.exit(0);
11767
+ } else {
11768
+ console.log("");
11769
+ console.log(RED10(" \u26A0\uFE0F Running in Generic Mode \u2014 no behavioral profile loaded."));
11770
+ console.log(RED10(" UserBob will respond using project context only."));
11771
+ console.log(RED10(" Responses won't reflect your personal communication style,"));
11772
+ console.log(RED10(" decision patterns, or engineering philosophy."));
11773
+ console.log(GRAY10(" Run `bob profile --today` anytime to unlock full personalization."));
11774
+ console.log("");
11775
+ }
11776
+ }
11777
+ let mission = missionArgs.length > 0 ? missionArgs.join(" ") : "";
11778
+ if (!mission && !options.resume) {
11779
+ const mrl = readline11.createInterface({ input: process.stdin, output: process.stdout, terminal: true });
11780
+ mission = await new Promise((resolve4) => mrl.question(AMBER11(" What's the mission? > "), resolve4));
11781
+ mrl.close();
11782
+ if (!mission.trim()) {
11783
+ console.log(RED10(" \u274C Mission cannot be empty. Exiting."));
11784
+ process.exit(1);
11785
+ }
11786
+ mission = mission.trim();
11787
+ }
11788
+ console.log("");
11789
+ console.log(GRAY10(` Target: ${params.target}% \u2502 Grade: ${params.grading} \u2502 Stag: ${params.stag || "\u221E"} \u2502 Div: ${params.div || "\u221E"}`));
11790
+ console.log("");
11791
+ if (usePlatform) {
11792
+ const conversationId = getActiveConversationId(process.cwd()) || config.conversationId;
11793
+ if (!conversationId) {
11794
+ console.log(RED10(" \u274C No active conversation. Run `bob conversations join` first."));
11795
+ process.exit(1);
11796
+ }
11797
+ if (options.resume) {
11798
+ console.log(AMBER11(" \u{1F504} Resuming simulation (no new mission note)..."));
11799
+ await callHTTPFunction("userSimManagerService", {
11800
+ action: "resumeMission",
11801
+ conversationId,
11802
+ uid: config.uid,
11803
+ email: config.email
11804
+ });
11805
+ console.log(GREEN11(" \u2705 Simulation resumed. Entering watch mode..."));
11806
+ console.log("");
11807
+ await runPlatformSimulation(config, conversationId, mission || "Resumed session", params);
11808
+ } else {
11809
+ await runPlatformSimulation(config, conversationId, mission, params);
11810
+ }
11811
+ return;
11812
+ }
11813
+ if (!config.localEndpoint) {
11814
+ console.log(RED10(" \u274C No local model configured."));
11815
+ console.log(GRAY10(" Run: bob config set localEndpoint http://127.0.0.1:11434/api/chat"));
11816
+ process.exit(1);
11817
+ }
11818
+ await runLocalSimulation(config, dna, mission, params);
11819
+ });
11820
+ }
11821
+
11251
11822
  // bin/bob.ts
11252
11823
  var program = new Command();
11253
11824
  program.name("bob").description("Bob's CLI \u2014 AI coding assistant and Forge orchestrator").version("0.8.0");
11254
11825
  program.command("whoami").description("Show current authentication status and configuration").action(() => {
11255
11826
  const config = getConfig();
11256
- const projectName = path22.basename(process.cwd());
11827
+ const projectName = path23.basename(process.cwd());
11257
11828
  const projectConvoId = getActiveConversationId(process.cwd()) || config.conversationId;
11258
11829
  console.log("");
11259
- console.log(chalk31.bold(" \u{1F916} Bob's CLI"));
11260
- console.log(chalk31.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"));
11261
- console.log(` ${chalk31.cyan("Status:")} ${config.loggedIn ? chalk31.green("Logged in as " + config.email) : "Not logged in"}`);
11262
- console.log(` ${chalk31.cyan("Tier:")} ${config.tier === "platform" ? "Platform (Tier 3)" : "Local-first (Tier 1)"}`);
11263
- console.log(` ${chalk31.cyan("Provider:")} ${config.provider || "Not configured"}`);
11264
- console.log(` ${chalk31.cyan("Mode:")} ${config.personalizationMode ? "Personalized" : config.consultantMode ? "Consultant" : "Standard"}`);
11265
- console.log(` ${chalk31.cyan("IDRP:")} ${config.idrp ? "Enabled" : "Disabled"}`);
11266
- console.log(` ${chalk31.cyan("Project:")} ${projectName} (${process.cwd()})`);
11267
- console.log(` ${chalk31.cyan("Session:")} ${projectConvoId ? projectConvoId.slice(0, 20) + "..." : "None"}`);
11830
+ console.log(chalk32.bold(" \u{1F916} Bob's CLI"));
11831
+ console.log(chalk32.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"));
11832
+ console.log(` ${chalk32.cyan("Status:")} ${config.loggedIn ? chalk32.green("Logged in as " + config.email) : "Not logged in"}`);
11833
+ console.log(` ${chalk32.cyan("Tier:")} ${config.tier === "platform" ? "Platform (Tier 3)" : "Local-first (Tier 1)"}`);
11834
+ console.log(` ${chalk32.cyan("Provider:")} ${config.provider || "Not configured"}`);
11835
+ console.log(` ${chalk32.cyan("Mode:")} ${config.personalizationMode ? "Personalized" : config.consultantMode ? "Consultant" : "Standard"}`);
11836
+ console.log(` ${chalk32.cyan("IDRP:")} ${config.idrp ? "Enabled" : "Disabled"}`);
11837
+ console.log(` ${chalk32.cyan("Project:")} ${projectName} (${process.cwd()})`);
11838
+ console.log(` ${chalk32.cyan("Session:")} ${projectConvoId ? projectConvoId.slice(0, 20) + "..." : "None"}`);
11268
11839
  console.log("");
11269
11840
  if (!config.loggedIn) {
11270
- console.log(chalk31.gray(" Run `bob login` to authenticate."));
11841
+ console.log(chalk32.gray(" Run `bob login` to authenticate."));
11271
11842
  console.log("");
11272
11843
  }
11273
11844
  });
@@ -11289,4 +11860,5 @@ registerProfileCommand(program);
11289
11860
  registerBackupCommand(program);
11290
11861
  registerAgentCommand(program);
11291
11862
  registerAgentRunCommand(program);
11863
+ registerUserBobCommand(program);
11292
11864
  program.parse();