@bobsworkshop/cli 0.5.3 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/bob.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import {
2
2
  buildLocalContext,
3
3
  callCloudFunction,
4
+ callHTTPFunction,
4
5
  callLocalModel,
5
6
  extractAllProposedFiles,
6
7
  extractProposedFile,
@@ -15,12 +16,12 @@ import {
15
16
  registerLoginCommand,
16
17
  setConfigValue,
17
18
  stripCodeBlockFromResponse
18
- } from "./chunk-CI36GGK2.js";
19
+ } from "./chunk-SADPOL7M.js";
19
20
 
20
21
  // bin/bob.ts
21
22
  import { Command } from "commander";
22
- import chalk24 from "chalk";
23
- import * as path13 from "path";
23
+ import chalk26 from "chalk";
24
+ import * as path14 from "path";
24
25
 
25
26
  // src/commands/config.ts
26
27
  import chalk from "chalk";
@@ -291,6 +292,29 @@ async function getTodayMessages(projectName) {
291
292
  return msg.timestamp >= twentyFourHoursAgo;
292
293
  });
293
294
  }
295
+ function buildDNAString() {
296
+ const dna = loadCurrentDNA();
297
+ if (!dna) return null;
298
+ const weekly = loadWeeklyProfiles(1)[0] || null;
299
+ const lines = [
300
+ "### USER BEHAVIORAL DNA ###",
301
+ `Archetype: ${dna.archetype || "Unknown"}`,
302
+ `Communication Style: ${dna.communicationStyle || "Unknown"}`,
303
+ `Work Rhythm: ${dna.workRhythm || "Unknown"}`,
304
+ `Decision Making: ${dna.decisionMaking || "Unknown"}`,
305
+ `Emotional State: ${dna.emotionalState || "Unknown"}`
306
+ ];
307
+ if (dna.growth) lines.push(`Growth Focus: ${dna.growth}`);
308
+ if (dna.source) lines.push(`Profile Source: ${dna.source} (${dna.lastUpdated || "unknown date"})`);
309
+ if (weekly) {
310
+ lines.push("");
311
+ lines.push("--- WEEKLY TRAJECTORY ---");
312
+ if (weekly.trajectory) lines.push(`Weekly Arc: ${weekly.trajectory}`);
313
+ if (weekly.moodShift) lines.push(`Mood Shift: ${weekly.moodShift}`);
314
+ if (weekly.focusEvolution) lines.push(`Focus Evolution: ${weekly.focusEvolution}`);
315
+ }
316
+ return lines.join("\n");
317
+ }
294
318
 
295
319
  // src/ai/persona.ts
296
320
  var STANDARD_STYLE_PROMPT = `You are Bob: friendly, direct, senior-level engineering partner.
@@ -3102,7 +3126,7 @@ function registerAnalyseCommand(program2) {
3102
3126
  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) => {
3103
3127
  const config = getConfig();
3104
3128
  if (options.auto) {
3105
- const { runAutoFix } = await import("./analyse-auto-HYYDD4OQ.js");
3129
+ const { runAutoFix } = await import("./analyse-auto-3JL5TO3G.js");
3106
3130
  const category = options.bugs ? "bugs" : options.features ? "features" : options.improvements ? "improvements" : options.upgrades ? "upgrades" : void 0;
3107
3131
  await runAutoFix({
3108
3132
  category,
@@ -3112,7 +3136,7 @@ function registerAnalyseCommand(program2) {
3112
3136
  return;
3113
3137
  }
3114
3138
  if (options.bugs || options.features || options.improvements || options.upgrades) {
3115
- const { showInteractiveResults } = await import("./analyse-results-7TS24WG7.js");
3139
+ const { showInteractiveResults } = await import("./analyse-results-NXVQJCO6.js");
3116
3140
  const category = options.bugs ? "bugs" : options.features ? "features" : options.improvements ? "improvements" : "upgrades";
3117
3141
  await showInteractiveResults(config, category, options.sort, options.search);
3118
3142
  return;
@@ -5720,13 +5744,1079 @@ function getWeekNumber(date) {
5720
5744
  return Math.ceil(((d.getTime() - yearStart.getTime()) / 864e5 + 1) / 7);
5721
5745
  }
5722
5746
 
5747
+ // src/commands/userbob.ts
5748
+ import chalk24 from "chalk";
5749
+ import * as readline8 from "readline";
5750
+ import * as fs10 from "fs";
5751
+ import * as path13 from "path";
5752
+ import * as os4 from "os";
5753
+ var PURPLE = chalk24.hex("#AB47BC");
5754
+ var AMBER6 = chalk24.hex("#FFAB00");
5755
+ var GREEN5 = chalk24.hex("#66BB6A");
5756
+ var CYAN5 = chalk24.hex("#26C6DA");
5757
+ var RED5 = chalk24.hex("#EF5350");
5758
+ var GRAY5 = chalk24.gray;
5759
+ var BLUE4 = chalk24.hex("#42A5F5");
5760
+ var BOB_COLOR = chalk24.hex("#E66F24");
5761
+ var BORDER10 = chalk24.hex("#455A64");
5762
+ var WHITE3 = chalk24.white;
5763
+ var BOB_DIR3 = path13.join(os4.homedir(), ".bob");
5764
+ function getSessionFilePath() {
5765
+ const projectName = path13.basename(process.cwd());
5766
+ return path13.join(BOB_DIR3, "projects", projectName, "userbob-session.json");
5767
+ }
5768
+ function writeSessionFile(data) {
5769
+ const filePath = getSessionFilePath();
5770
+ const dir = path13.dirname(filePath);
5771
+ if (!fs10.existsSync(dir)) fs10.mkdirSync(dir, { recursive: true });
5772
+ fs10.writeFileSync(filePath, JSON.stringify(data, null, 2));
5773
+ }
5774
+ function readSessionFile() {
5775
+ const filePath = getSessionFilePath();
5776
+ if (!fs10.existsSync(filePath)) return null;
5777
+ try {
5778
+ return JSON.parse(fs10.readFileSync(filePath, "utf-8"));
5779
+ } catch {
5780
+ return null;
5781
+ }
5782
+ }
5783
+ function clearSessionFile() {
5784
+ const filePath = getSessionFilePath();
5785
+ if (fs10.existsSync(filePath)) fs10.unlinkSync(filePath);
5786
+ }
5787
+ function renderHUD(sat, target, stag, stagTarget, div, divTarget, grading) {
5788
+ const satBar = sat >= target ? GREEN5(`${sat}%`) : sat >= target * 0.7 ? AMBER6(`${sat}%`) : RED5(`${sat}%`);
5789
+ console.log("");
5790
+ console.log(BORDER10(" \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"));
5791
+ console.log(
5792
+ ` SAT: ${satBar} \u2192 ${target}% \u2502 STAG: ${stag}/${stagTarget > 0 ? stagTarget : "\u221E"} \u2502 DIV: ${div}/${divTarget > 0 ? divTarget : "\u221E"} \u2502 GRADE: ${grading}`
5793
+ );
5794
+ console.log(BORDER10(" \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"));
5795
+ console.log("");
5796
+ }
5797
+ function stripMarkdown(text) {
5798
+ 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();
5799
+ }
5800
+ function renderMessage(sender, message, audit) {
5801
+ const cleanMsg = stripMarkdown(message);
5802
+ const maxWidth = 70;
5803
+ const lines = wrapText2(cleanMsg, maxWidth - 4);
5804
+ if (sender === "userBob") {
5805
+ const topBar = PURPLE(` \u250C\u2500 UserBob ${"\u2500".repeat(maxWidth - 13)}\u2510`);
5806
+ const bottomBar = PURPLE(` \u2514${"\u2500".repeat(maxWidth - 2)}\u2518`);
5807
+ console.log("");
5808
+ console.log(topBar);
5809
+ for (const line of lines) {
5810
+ const padded = line.padEnd(maxWidth - 4);
5811
+ console.log(PURPLE(" \u2502") + ` ${padded}` + PURPLE(" \u2502"));
5812
+ }
5813
+ console.log(bottomBar);
5814
+ if (audit) {
5815
+ const chips = [];
5816
+ if (audit.satisfactionScore !== void 0) chips.push(CYAN5(`[SAT: ${audit.satisfactionScore}%]`));
5817
+ if (audit.resemblanceScore !== void 0) chips.push(BLUE4(`[RES: ${audit.resemblanceScore}%]`));
5818
+ if (audit.reasoning) chips.push(GRAY5(`[${String(audit.reasoning).slice(0, 50)}...]`));
5819
+ if (chips.length > 0) console.log(" " + chips.join(" "));
5820
+ }
5821
+ } else if (sender === "bob") {
5822
+ const indent = " ";
5823
+ const topBar = BOB_COLOR(`${indent}\u250C${"\u2500".repeat(maxWidth - 12)}\u2500 Bob \u2500\u2510`);
5824
+ const bottomBar = BOB_COLOR(`${indent}\u2514${"\u2500".repeat(maxWidth - 2)}\u2518`);
5825
+ console.log("");
5826
+ console.log(topBar);
5827
+ for (const line of lines) {
5828
+ const padded = line.padEnd(maxWidth - 4);
5829
+ console.log(BOB_COLOR(`${indent}\u2502`) + ` ${padded}` + BOB_COLOR(" \u2502"));
5830
+ }
5831
+ console.log(bottomBar);
5832
+ } else if (sender === "system") {
5833
+ console.log("");
5834
+ console.log(CYAN5(" \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"));
5835
+ console.log(GRAY5(` ${cleanMsg}`));
5836
+ console.log(CYAN5(" \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"));
5837
+ } else {
5838
+ console.log("");
5839
+ console.log(GRAY5(` [${sender.toUpperCase()}] ${cleanMsg}`));
5840
+ }
5841
+ }
5842
+ function wrapText2(text, maxWidth) {
5843
+ const lines = [];
5844
+ const paragraphs = text.split("\n");
5845
+ for (const paragraph of paragraphs) {
5846
+ if (paragraph.trim() === "") {
5847
+ lines.push("");
5848
+ continue;
5849
+ }
5850
+ const words = paragraph.split(" ");
5851
+ let currentLine = "";
5852
+ for (const word of words) {
5853
+ if ((currentLine + " " + word).trim().length > maxWidth) {
5854
+ if (currentLine) lines.push(currentLine.trim());
5855
+ currentLine = word;
5856
+ } else {
5857
+ currentLine = currentLine ? currentLine + " " + word : word;
5858
+ }
5859
+ }
5860
+ if (currentLine.trim()) lines.push(currentLine.trim());
5861
+ }
5862
+ return lines;
5863
+ }
5864
+ async function handleSlashCommand(input, config, conversationId) {
5865
+ const trimmed = input.trim();
5866
+ if (trimmed === "/status") {
5867
+ try {
5868
+ const response = await callCloudFunction("getCLIConversationMessages", { conversationId, since: null });
5869
+ const state = response?.state || {};
5870
+ console.log("");
5871
+ console.log(AMBER6(" \u2500\u2500\u2500 Current Parameters \u2500\u2500\u2500"));
5872
+ console.log(GRAY5(` Target Satisfaction : ${state.targetSatisfaction ?? "N/A"}`));
5873
+ console.log(GRAY5(` Grading Standard : ${state.gradingStandard ?? "N/A"}`));
5874
+ console.log(GRAY5(` Current Satisfaction: ${state.currentSatisfaction ?? "N/A"}`));
5875
+ console.log(GRAY5(` Stalemate : ${state.stalemateState?.current ?? 0}/${state.stalemateState?.target ?? "\u221E"}`));
5876
+ console.log(GRAY5(` Divergence : ${state.divergenceState?.current ?? 0}/${state.divergenceState?.target ?? "\u221E"}`));
5877
+ console.log(GRAY5(` Status : ${state.simulationStatus ?? "UNKNOWN"}`));
5878
+ console.log(GRAY5(` Active : ${state.userBobActive ?? "UNKNOWN"}`));
5879
+ console.log("");
5880
+ } catch {
5881
+ console.log(RED5(" \u274C Could not fetch conversation state."));
5882
+ }
5883
+ return;
5884
+ }
5885
+ const setMatch = trimmed.match(/^\/set\s+(grading|target|stag|div)\s+(\d+)$/i);
5886
+ if (setMatch) {
5887
+ const param = setMatch[1].toLowerCase();
5888
+ const value = parseInt(setMatch[2], 10);
5889
+ const paramMap = {
5890
+ grading: "gradingStandard",
5891
+ target: "targetSatisfaction",
5892
+ stag: "stalemateZone",
5893
+ div: "divergenceThreshold"
5894
+ };
5895
+ try {
5896
+ await callHTTPFunction("userSimManagerService", {
5897
+ action: "updateParameters",
5898
+ conversationId,
5899
+ uid: config.uid,
5900
+ email: config.email,
5901
+ params: { [paramMap[param]]: value }
5902
+ });
5903
+ console.log(GREEN5(` \u2705 ${param} updated to ${value}`));
5904
+ } catch (e) {
5905
+ console.log(RED5(` \u274C Failed to update ${param}: ${e.message}`));
5906
+ }
5907
+ return;
5908
+ }
5909
+ const injectMatch = trimmed.match(/^\/inject\s+"(.+)"$/);
5910
+ if (injectMatch) {
5911
+ const note = injectMatch[1];
5912
+ try {
5913
+ await callHTTPFunction("userSimManagerService", {
5914
+ action: "injectNote",
5915
+ conversationId,
5916
+ uid: config.uid,
5917
+ email: config.email,
5918
+ note
5919
+ });
5920
+ console.log(GREEN5(` \u2705 Director's note injected.`));
5921
+ } catch (e) {
5922
+ console.log(RED5(` \u274C Failed to inject note: ${e.message}`));
5923
+ }
5924
+ return;
5925
+ }
5926
+ console.log(GRAY5(' Commands: /set grading|target|stag|div <n> /inject "note" /status /abort'));
5927
+ }
5928
+ async function runPlatformSimulation(config, conversationId, mission, params) {
5929
+ await callHTTPFunction("userSimManagerService", {
5930
+ action: "updateParameters",
5931
+ conversationId,
5932
+ uid: config.uid,
5933
+ email: config.email,
5934
+ params: {
5935
+ targetSatisfaction: params.target,
5936
+ gradingStandard: params.grading,
5937
+ stalemateZone: params.stag,
5938
+ divergenceThreshold: params.div
5939
+ }
5940
+ });
5941
+ await callHTTPFunction("userSimManagerService", {
5942
+ action: "injectNote",
5943
+ conversationId,
5944
+ uid: config.uid,
5945
+ email: config.email,
5946
+ note: mission
5947
+ });
5948
+ console.log(GREEN5(" \u2705 Mission injected. Simulation is running."));
5949
+ console.log("");
5950
+ console.log(BORDER10(" \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"));
5951
+ console.log(GRAY5(" Messages will stream below as Bob and UserBob interact."));
5952
+ console.log(GRAY5(" You can type commands at any time:"));
5953
+ console.log("");
5954
+ console.log(AMBER6(" /abort") + GRAY5(" \u2014 Stop the simulation immediately"));
5955
+ console.log(AMBER6(" /set target 90") + GRAY5(" \u2014 Update satisfaction target"));
5956
+ console.log(AMBER6(" /set grading 70") + GRAY5(" \u2014 Update Teacher's Curve"));
5957
+ console.log(AMBER6(" /set stag 5") + GRAY5(" \u2014 Update stalemate threshold"));
5958
+ console.log(AMBER6(" /set div 3") + GRAY5(" \u2014 Update divergence threshold"));
5959
+ console.log(AMBER6(' /inject "note"') + GRAY5(" \u2014 Inject a director's note mid-session"));
5960
+ console.log(AMBER6(" /status") + GRAY5(" \u2014 Show current simulation parameters"));
5961
+ console.log("");
5962
+ console.log(BORDER10(" \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"));
5963
+ console.log("");
5964
+ let running = true;
5965
+ let lastMessageTimestamp = 0;
5966
+ let hudState = { sat: 0, target: params.target, stag: 0, stagTarget: params.stag, div: 0, divTarget: params.div, grading: params.grading };
5967
+ const sigintHandler = async () => {
5968
+ if (!running) return;
5969
+ running = false;
5970
+ console.log("\n");
5971
+ console.log(AMBER6(" \u{1F6D1} Aborting simulation..."));
5972
+ try {
5973
+ await callHTTPFunction("userSimManagerService", {
5974
+ action: "abortMission",
5975
+ conversationId,
5976
+ uid: config.uid,
5977
+ email: config.email
5978
+ });
5979
+ console.log(GREEN5(" \u2705 Simulation aborted."));
5980
+ } catch {
5981
+ }
5982
+ process.exit(0);
5983
+ };
5984
+ process.on("SIGINT", sigintHandler);
5985
+ const rl = readline8.createInterface({ input: process.stdin, output: process.stdout, terminal: true });
5986
+ rl.setPrompt("");
5987
+ rl.on("line", async (line) => {
5988
+ const trimmed = line.trim();
5989
+ if (!trimmed) return;
5990
+ if (trimmed === "/abort" || trimmed === "abort") {
5991
+ running = false;
5992
+ console.log(AMBER6(" \u{1F6D1} Aborting simulation..."));
5993
+ try {
5994
+ await callHTTPFunction("userSimManagerService", {
5995
+ action: "abortMission",
5996
+ conversationId,
5997
+ uid: config.uid,
5998
+ email: config.email
5999
+ });
6000
+ console.log(GREEN5(" \u2705 Simulation aborted."));
6001
+ } catch {
6002
+ }
6003
+ rl.close();
6004
+ process.exit(0);
6005
+ }
6006
+ await handleSlashCommand(trimmed, config, conversationId);
6007
+ });
6008
+ while (running) {
6009
+ await new Promise((r) => setTimeout(r, 3e3));
6010
+ try {
6011
+ const response = await callCloudFunction("getCLIConversationMessages", {
6012
+ conversationId,
6013
+ since: lastMessageTimestamp || null
6014
+ });
6015
+ const messages = response?.messages || [];
6016
+ const state = response?.state || {};
6017
+ for (const msg of messages) {
6018
+ renderMessage(msg.sender, msg.message, msg.simulationAudit);
6019
+ if (msg.timestamp && msg.timestamp > lastMessageTimestamp) {
6020
+ lastMessageTimestamp = msg.timestamp;
6021
+ }
6022
+ }
6023
+ if (state.currentSatisfaction !== void 0) hudState.sat = state.currentSatisfaction;
6024
+ if (state.targetSatisfaction !== void 0) hudState.target = state.targetSatisfaction;
6025
+ if (state.gradingStandard !== void 0) hudState.grading = state.gradingStandard;
6026
+ if (state.stalemateState) {
6027
+ hudState.stag = state.stalemateState.current ?? hudState.stag;
6028
+ hudState.stagTarget = state.stalemateState.target ?? hudState.stagTarget;
6029
+ }
6030
+ if (state.divergenceState) {
6031
+ hudState.div = state.divergenceState.current ?? hudState.div;
6032
+ hudState.divTarget = state.divergenceState.target ?? hudState.divTarget;
6033
+ }
6034
+ if (state.userBobActive === false || state.simulationStatus && state.simulationStatus !== "RUNNING") {
6035
+ if (messages.length > 0) {
6036
+ renderHUD(hudState.sat, hudState.target, hudState.stag, hudState.stagTarget, hudState.div, hudState.divTarget, hudState.grading);
6037
+ }
6038
+ console.log("");
6039
+ console.log(AMBER6(` \u{1F3C1} Simulation ended: ${state.simulationStatus || "INACTIVE"}`));
6040
+ console.log("");
6041
+ running = false;
6042
+ break;
6043
+ }
6044
+ if (messages.length > 0) {
6045
+ renderHUD(hudState.sat, hudState.target, hudState.stag, hudState.stagTarget, hudState.div, hudState.divTarget, hudState.grading);
6046
+ }
6047
+ } catch (e) {
6048
+ console.log(RED5(` \u274C Poll error: ${e.message}`));
6049
+ }
6050
+ }
6051
+ rl.close();
6052
+ process.removeListener("SIGINT", sigintHandler);
6053
+ }
6054
+ async function runLocalSimulation(config, dnaString, mission, params) {
6055
+ writeSessionFile({ active: true, turns: 0, mission });
6056
+ let running = true;
6057
+ let turns = 0;
6058
+ let conversationHistory = [];
6059
+ let sat = 0;
6060
+ let stalemateCurrent = 0;
6061
+ let divergenceCurrent = 0;
6062
+ let lastStatus = "";
6063
+ const sigintHandler = () => {
6064
+ running = false;
6065
+ writeSessionFile({ active: false });
6066
+ clearSessionFile();
6067
+ console.log("\n" + AMBER6(" \u{1F6D1} Simulation stopped."));
6068
+ process.exit(0);
6069
+ };
6070
+ process.on("SIGINT", sigintHandler);
6071
+ const rl = readline8.createInterface({ input: process.stdin, output: process.stdout, terminal: true });
6072
+ rl.setPrompt("");
6073
+ rl.on("line", (line) => {
6074
+ const t = line.trim();
6075
+ if (t === "/abort" || t === "abort") {
6076
+ running = false;
6077
+ writeSessionFile({ active: false });
6078
+ clearSessionFile();
6079
+ console.log(AMBER6(" \u{1F6D1} Simulation stopped."));
6080
+ rl.close();
6081
+ process.exit(0);
6082
+ }
6083
+ if (t.startsWith("/set ")) {
6084
+ const m = t.match(/^\/set\s+(grading|target|stag|div)\s+(\d+)$/i);
6085
+ if (m) {
6086
+ const val = parseInt(m[2], 10);
6087
+ if (m[1] === "grading") params.grading = val;
6088
+ if (m[1] === "target") params.target = val;
6089
+ if (m[1] === "stag") params.stag = val;
6090
+ if (m[1] === "div") params.div = val;
6091
+ console.log(GREEN5(` \u2705 ${m[1]} updated to ${val} (local)`));
6092
+ }
6093
+ }
6094
+ if (t === "/status") {
6095
+ console.log("");
6096
+ console.log(AMBER6(" \u2500\u2500\u2500 Local Sim Parameters \u2500\u2500\u2500"));
6097
+ console.log(GRAY5(` Target: ${params.target} \u2502 Grading: ${params.grading} \u2502 Stag Limit: ${params.stag} \u2502 Div Limit: ${params.div}`));
6098
+ console.log(GRAY5(` Current SAT: ${sat} \u2502 Turns: ${turns} \u2502 Stag: ${stalemateCurrent} \u2502 Div: ${divergenceCurrent}`));
6099
+ console.log("");
6100
+ }
6101
+ });
6102
+ 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}`;
6103
+ 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.
6104
+
6105
+ Mission: ${mission}
6106
+
6107
+ ${dnaString}
6108
+
6109
+ 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:
6110
+ {"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.
6111
+
6112
+ Mission: ${mission}
6113
+
6114
+ 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:
6115
+ {"satisfactionScore": <0-100>, "status": "CONVERGING|STAGNATING|DIVERGING"}`;
6116
+ console.log(BORDER10(" \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"));
6117
+ console.log(GRAY5(" Bob and UserBob will converse autonomously below."));
6118
+ console.log(GRAY5(" Commands:"));
6119
+ console.log(AMBER6(" /abort") + GRAY5(" \u2014 Stop the simulation"));
6120
+ console.log(AMBER6(" /set target 90") + GRAY5(" \u2014 Update satisfaction target"));
6121
+ console.log(AMBER6(" /set grading 70") + GRAY5(" \u2014 Update Teacher's Curve"));
6122
+ console.log(AMBER6(" /set stag 5") + GRAY5(" \u2014 Update stalemate threshold"));
6123
+ console.log(AMBER6(" /set div 3") + GRAY5(" \u2014 Update divergence threshold"));
6124
+ console.log(AMBER6(" /status") + GRAY5(" \u2014 Show current parameters"));
6125
+ console.log(BORDER10(" \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"));
6126
+ console.log("");
6127
+ const kickstart = `Mission received: "${mission}". Bob, what's your first move?`;
6128
+ console.log(PURPLE(" UserBob > ") + WHITE3(kickstart));
6129
+ conversationHistory.push({ role: "user", content: kickstart });
6130
+ while (running) {
6131
+ const session = readSessionFile();
6132
+ if (!session?.active) {
6133
+ running = false;
6134
+ break;
6135
+ }
6136
+ turns++;
6137
+ try {
6138
+ const bobMessages = [
6139
+ { role: "system", content: bobSystem },
6140
+ ...conversationHistory
6141
+ ];
6142
+ const bobResponse = await callLocalModel(config.localEndpoint, bobMessages);
6143
+ console.log(BOB_COLOR(" Bob > ") + WHITE3(bobResponse));
6144
+ conversationHistory.push({ role: "assistant", content: bobResponse });
6145
+ const ubMessages = [
6146
+ { role: "system", content: userBobSystem },
6147
+ ...conversationHistory
6148
+ ];
6149
+ const ubResponse = await callLocalModel(config.localEndpoint, ubMessages);
6150
+ const jsonMatch = ubResponse.match(/\{[^}]*"satisfactionScore"[^}]*\}/);
6151
+ const cleanResponse = ubResponse.replace(/\{[^}]*"satisfactionScore"[^}]*\}/, "").trim();
6152
+ console.log(PURPLE(" UserBob > ") + WHITE3(cleanResponse));
6153
+ let auditChips = [];
6154
+ if (jsonMatch) {
6155
+ try {
6156
+ const audit = JSON.parse(jsonMatch[0]);
6157
+ const rawScore = audit.satisfactionScore || 0;
6158
+ sat = Math.round(rawScore * (params.grading / 100));
6159
+ lastStatus = audit.status || "";
6160
+ auditChips = [CYAN5(`[SAT: ${sat}%]`), BLUE4(`[RAW: ${rawScore}]`), GRAY5(`[${lastStatus}]`)];
6161
+ if (lastStatus === "STAGNATING") {
6162
+ stalemateCurrent++;
6163
+ if (params.stag > 0 && stalemateCurrent >= params.stag) {
6164
+ console.log(" " + auditChips.join(" "));
6165
+ renderHUD(sat, params.target, stalemateCurrent, params.stag, divergenceCurrent, params.div, params.grading);
6166
+ console.log(AMBER6(` \u{1F3C1} Stalemate threshold reached (${stalemateCurrent}/${params.stag}). Simulation ended.`));
6167
+ running = false;
6168
+ break;
6169
+ }
6170
+ } else if (lastStatus === "DIVERGING") {
6171
+ divergenceCurrent++;
6172
+ stalemateCurrent = 0;
6173
+ if (params.div > 0 && divergenceCurrent >= params.div) {
6174
+ console.log(" " + auditChips.join(" "));
6175
+ renderHUD(sat, params.target, stalemateCurrent, params.stag, divergenceCurrent, params.div, params.grading);
6176
+ console.log(AMBER6(` \u{1F3C1} Divergence threshold reached (${divergenceCurrent}/${params.div}). Simulation ended.`));
6177
+ running = false;
6178
+ break;
6179
+ }
6180
+ } else if (lastStatus === "CONVERGING") {
6181
+ stalemateCurrent = 0;
6182
+ divergenceCurrent = 0;
6183
+ }
6184
+ } catch {
6185
+ }
6186
+ }
6187
+ if (auditChips.length) console.log(" " + auditChips.join(" "));
6188
+ conversationHistory.push({ role: "user", content: ubResponse });
6189
+ writeSessionFile({ active: true, turns, mission, sat });
6190
+ renderHUD(sat, params.target, stalemateCurrent, params.stag, divergenceCurrent, params.div, params.grading);
6191
+ if (sat >= params.target) {
6192
+ console.log(GREEN5(` \u{1F3AF} Target satisfaction ${params.target}% reached! Mission complete.`));
6193
+ running = false;
6194
+ break;
6195
+ }
6196
+ await new Promise((r) => setTimeout(r, 1e3));
6197
+ } catch (e) {
6198
+ console.log(RED5(` \u274C Local model error: ${e.message}`));
6199
+ console.log(GRAY5(" Retrying in 3 seconds..."));
6200
+ await new Promise((r) => setTimeout(r, 3e3));
6201
+ }
6202
+ }
6203
+ clearSessionFile();
6204
+ rl.close();
6205
+ process.removeListener("SIGINT", sigintHandler);
6206
+ console.log("");
6207
+ console.log(GRAY5(` Session complete. ${turns} turns processed.`));
6208
+ console.log("");
6209
+ }
6210
+ function registerUserBobCommand(program2) {
6211
+ 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) => {
6212
+ const config = getConfig();
6213
+ const params = {
6214
+ target: parseInt(options.target, 10),
6215
+ grading: parseInt(options.grading, 10),
6216
+ stag: parseInt(options.stag, 10),
6217
+ div: parseInt(options.div, 10)
6218
+ };
6219
+ const usePlatform = !options.local && isAuthenticated();
6220
+ console.log("");
6221
+ console.log(BORDER10(" \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"));
6222
+ console.log(BORDER10(" \u2551") + PURPLE(" \u{1F916} UserBob \u2014 Digital Twin Simulation"));
6223
+ console.log(BORDER10(" \u2551") + GRAY5(` Mode: ${usePlatform ? "Platform (Tier 3)" : "Local Ollama (Tier 1)"}`));
6224
+ 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"));
6225
+ console.log("");
6226
+ const dna = buildDNAString();
6227
+ if (dna) {
6228
+ console.log(GREEN5(" \u2705 Behavioral DNA loaded."));
6229
+ } else {
6230
+ console.log(AMBER6(" \u26A0\uFE0F No behavioral profile found."));
6231
+ console.log(GRAY5(" UserBob performs significantly better with your DNA loaded."));
6232
+ console.log("");
6233
+ const rl = readline8.createInterface({ input: process.stdin, output: process.stdout, terminal: true });
6234
+ const answer = await new Promise((resolve2) => rl.question(AMBER6(" Run `bob profile --today` now? (y/n): "), resolve2));
6235
+ rl.close();
6236
+ if (answer.trim().toLowerCase() === "y") {
6237
+ console.log("");
6238
+ console.log(GRAY5(" Run `bob profile --today` in a separate terminal, then re-run `bob userbob`."));
6239
+ process.exit(0);
6240
+ } else {
6241
+ console.log("");
6242
+ console.log(RED5(" \u26A0\uFE0F Running in Generic Mode \u2014 no behavioral profile loaded."));
6243
+ console.log(RED5(" UserBob will respond using project context only."));
6244
+ console.log(RED5(" Responses won't reflect your personal communication style,"));
6245
+ console.log(RED5(" decision patterns, or engineering philosophy."));
6246
+ console.log(GRAY5(" Run `bob profile --today` anytime to unlock full personalization."));
6247
+ console.log("");
6248
+ }
6249
+ }
6250
+ let mission = missionArgs.length > 0 ? missionArgs.join(" ") : "";
6251
+ if (!mission && !options.resume) {
6252
+ const mrl = readline8.createInterface({ input: process.stdin, output: process.stdout, terminal: true });
6253
+ mission = await new Promise((resolve2) => mrl.question(AMBER6(" What's the mission? > "), resolve2));
6254
+ mrl.close();
6255
+ if (!mission.trim()) {
6256
+ console.log(RED5(" \u274C Mission cannot be empty. Exiting."));
6257
+ process.exit(1);
6258
+ }
6259
+ mission = mission.trim();
6260
+ }
6261
+ console.log("");
6262
+ console.log(GRAY5(` Target: ${params.target}% \u2502 Grade: ${params.grading} \u2502 Stag: ${params.stag || "\u221E"} \u2502 Div: ${params.div || "\u221E"}`));
6263
+ console.log("");
6264
+ if (usePlatform) {
6265
+ const conversationId = config.conversationId;
6266
+ if (!conversationId) {
6267
+ console.log(RED5(" \u274C No active conversation. Run `bob conversations join` first."));
6268
+ process.exit(1);
6269
+ }
6270
+ if (options.resume) {
6271
+ console.log(AMBER6(" \u{1F504} Resuming simulation (no new mission note)..."));
6272
+ await callHTTPFunction("userSimManagerService", {
6273
+ action: "resumeMission",
6274
+ conversationId,
6275
+ uid: config.uid,
6276
+ email: config.email
6277
+ });
6278
+ console.log(GREEN5(" \u2705 Simulation resumed. Entering watch mode..."));
6279
+ console.log("");
6280
+ await runPlatformSimulation(config, conversationId, mission || "Resumed session", params);
6281
+ } else {
6282
+ await runPlatformSimulation(config, conversationId, mission, params);
6283
+ }
6284
+ return;
6285
+ }
6286
+ if (!config.localEndpoint) {
6287
+ console.log(RED5(" \u274C No local model configured."));
6288
+ console.log(GRAY5(" Run: bob config set localEndpoint http://127.0.0.1:11434/api/chat"));
6289
+ process.exit(1);
6290
+ }
6291
+ await runLocalSimulation(config, dna, mission, params);
6292
+ });
6293
+ }
6294
+
6295
+ // src/commands/command-center.ts
6296
+ import chalk25 from "chalk";
6297
+ import inquirer from "inquirer";
6298
+ var ORANGE2 = chalk25.hex("#E66F24");
6299
+ var AMBER7 = chalk25.hex("#FFAB00");
6300
+ var GREEN6 = chalk25.hex("#66BB6A");
6301
+ var RED6 = chalk25.hex("#EF5350");
6302
+ var BLUE5 = chalk25.hex("#42A5F5");
6303
+ var PURPLE2 = chalk25.hex("#AB47BC");
6304
+ var CYAN6 = chalk25.hex("#26C6DA");
6305
+ var TEAL = chalk25.hex("#26A69A");
6306
+ var GRAY6 = chalk25.gray;
6307
+ var WHITE4 = chalk25.white;
6308
+ var BORDER11 = chalk25.hex("#455A64");
6309
+ function statusColor(status) {
6310
+ switch (status) {
6311
+ case "queued":
6312
+ return GRAY6;
6313
+ case "awaiting_approval":
6314
+ return AMBER7;
6315
+ case "in_progress":
6316
+ return BLUE5;
6317
+ case "completed":
6318
+ return GREEN6;
6319
+ case "failed":
6320
+ return RED6;
6321
+ case "denied":
6322
+ return RED6;
6323
+ default:
6324
+ return GRAY6;
6325
+ }
6326
+ }
6327
+ function statusLabel(status) {
6328
+ switch (status) {
6329
+ case "queued":
6330
+ return "QUEUED";
6331
+ case "awaiting_approval":
6332
+ return "NEEDS APPROVAL";
6333
+ case "in_progress":
6334
+ return "IN PROGRESS";
6335
+ case "completed":
6336
+ return "COMPLETE";
6337
+ case "failed":
6338
+ return "FAILED";
6339
+ case "denied":
6340
+ return "DENIED";
6341
+ default:
6342
+ return status.toUpperCase();
6343
+ }
6344
+ }
6345
+ function categoryColor(category) {
6346
+ const map = {
6347
+ security: RED6,
6348
+ frontend: BLUE5,
6349
+ backend: GREEN6,
6350
+ cloud_functions: PURPLE2,
6351
+ documentation: TEAL,
6352
+ testing: AMBER7,
6353
+ review: CYAN6,
6354
+ fullstack: ORANGE2
6355
+ };
6356
+ return map[category] || GRAY6;
6357
+ }
6358
+ function confidenceColor(confidence) {
6359
+ if (confidence >= 80) return GREEN6;
6360
+ if (confidence >= 50) return AMBER7;
6361
+ return RED6;
6362
+ }
6363
+ function formatTimestamp(ms) {
6364
+ if (!ms) return "\u2014";
6365
+ return new Date(ms).toLocaleString("en-US", {
6366
+ month: "short",
6367
+ day: "numeric",
6368
+ hour: "numeric",
6369
+ minute: "2-digit",
6370
+ hour12: true
6371
+ });
6372
+ }
6373
+ function stripMarkdown2(text) {
6374
+ return text.replace(/\*\*(.+?)\*\*/g, "$1").replace(/\*(.+?)\*/g, "$1").replace(/^#{1,6}\s+/gm, "").replace(/^---+$/gm, "").replace(/`([^`]+)`/g, "$1").replace(/^\s*[-*+]\s+/gm, " \u2022 ").replace(/\n{3,}/g, "\n\n").trim();
6375
+ }
6376
+ function renderStats(stats) {
6377
+ console.log("");
6378
+ console.log(BORDER11(" \u2500\u2500\u2500 COMMAND CENTER \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"));
6379
+ const parts = [];
6380
+ if (stats.awaiting_approval > 0) parts.push(AMBER7(`${stats.awaiting_approval} PENDING`));
6381
+ if (stats.in_progress > 0) parts.push(BLUE5(`${stats.in_progress} RUNNING`));
6382
+ if (stats.completed > 0) parts.push(GREEN6(`${stats.completed} DONE`));
6383
+ if (stats.failed > 0) parts.push(RED6(`${stats.failed} FAILED`));
6384
+ if (stats.denied > 0) parts.push(GRAY6(`${stats.denied} DENIED`));
6385
+ parts.push(GRAY6(`${stats.total} TOTAL`));
6386
+ console.log(" " + parts.join(GRAY6(" \u2502 ")));
6387
+ console.log(BORDER11(" \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"));
6388
+ console.log("");
6389
+ }
6390
+ function renderTaskDetail(task) {
6391
+ const catColor = categoryColor(task.request.category);
6392
+ const confColor = confidenceColor(task.request.confidence);
6393
+ const sColor = statusColor(task.outcome.status);
6394
+ console.log("");
6395
+ console.log(BORDER11(" \u250C\u2500 TASK DETAIL \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\u2510"));
6396
+ console.log(BORDER11(" \u2502"));
6397
+ console.log(BORDER11(" \u2502 ") + WHITE4(task.request.description));
6398
+ console.log(BORDER11(" \u2502"));
6399
+ console.log(BORDER11(" \u2502 ") + catColor(`[${task.request.category.toUpperCase()}]`) + " " + WHITE4(`${task.request.taskType.toUpperCase()}`) + " " + confColor(`${task.request.confidence}% confidence`) + " " + sColor(`\u25CF ${statusLabel(task.outcome.status)}`));
6400
+ if (task.request.targetFile) {
6401
+ console.log(BORDER11(" \u2502 ") + GRAY6("File: ") + CYAN6(task.request.targetFile));
6402
+ }
6403
+ console.log(BORDER11(" \u2502"));
6404
+ console.log(BORDER11(" \u2502 ") + GRAY6("Priority: ") + WHITE4(`P${task.priority}`) + GRAY6(" \u2502 Difficulty: ") + WHITE4(task.difficulty.toUpperCase()) + GRAY6(" \u2502 Created: ") + WHITE4(formatTimestamp(task.createdAt)));
6405
+ console.log(BORDER11(" \u2502"));
6406
+ console.log(BORDER11(" \u2502 ") + AMBER7("TRIGGER"));
6407
+ console.log(BORDER11(" \u2502 ") + GRAY6(stripMarkdown2(task.trigger.reasoning).slice(0, 120) + "..."));
6408
+ if (task.trigger.turnSatisfaction !== null) {
6409
+ console.log(BORDER11(" \u2502 ") + GRAY6("SAT at dispatch: ") + CYAN6(`${task.trigger.turnSatisfaction}%`));
6410
+ }
6411
+ if (task.outcome.resultSummary) {
6412
+ console.log(BORDER11(" \u2502"));
6413
+ console.log(BORDER11(" \u2502 ") + GREEN6("RESULT"));
6414
+ console.log(BORDER11(" \u2502 ") + GRAY6(stripMarkdown2(task.outcome.resultSummary).slice(0, 200) + "..."));
6415
+ }
6416
+ if (task.outcome.filesModified && task.outcome.filesModified.length > 0) {
6417
+ console.log(BORDER11(" \u2502"));
6418
+ console.log(BORDER11(" \u2502 ") + AMBER7("FILES MODIFIED"));
6419
+ for (const file of task.outcome.filesModified) {
6420
+ const icon = file.action === "created" ? GREEN6("+") : AMBER7("~");
6421
+ console.log(BORDER11(" \u2502 ") + icon + " " + CYAN6(file.path || file));
6422
+ }
6423
+ }
6424
+ if (task.outcome.error) {
6425
+ console.log(BORDER11(" \u2502"));
6426
+ console.log(BORDER11(" \u2502 ") + RED6("ERROR"));
6427
+ console.log(BORDER11(" \u2502 ") + RED6(task.outcome.error.slice(0, 150)));
6428
+ }
6429
+ if (task.isDenied && task.denyReason) {
6430
+ console.log(BORDER11(" \u2502"));
6431
+ console.log(BORDER11(" \u2502 ") + RED6("DENIED BY: ") + GRAY6(task.deniedBy || "Unknown"));
6432
+ console.log(BORDER11(" \u2502 ") + RED6("REASON: ") + GRAY6(task.denyReason));
6433
+ }
6434
+ if (task.outcome.turnsUsed || task.outcome.tokensConsumed) {
6435
+ console.log(BORDER11(" \u2502"));
6436
+ if (task.outcome.turnsUsed) {
6437
+ console.log(BORDER11(" \u2502 ") + GRAY6(`Turns: ${task.outcome.turnsUsed} \u2502 Tokens: ${task.outcome.tokensConsumed || 0} \u2502 Provider: ${task.outcome.provider || "unknown"}`));
6438
+ }
6439
+ }
6440
+ console.log(BORDER11(" \u2502"));
6441
+ console.log(BORDER11(" \u2514\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\u2518"));
6442
+ console.log("");
6443
+ }
6444
+ async function runDecisionStream(conversationId) {
6445
+ console.log("");
6446
+ console.log(ORANGE2(" \u2500\u2500\u2500 DECISION STREAM \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"));
6447
+ console.log(GRAY6(" Live feed of all autonomous decisions. Ctrl+C to exit.\n"));
6448
+ let lastCount = 0;
6449
+ let running = true;
6450
+ process.on("SIGINT", () => {
6451
+ running = false;
6452
+ console.log("\n" + AMBER7(" Stream ended."));
6453
+ process.exit(0);
6454
+ });
6455
+ while (running) {
6456
+ try {
6457
+ const response = await callCloudFunction("getCLIAutonomousTasks", { conversationId });
6458
+ const tasks = response?.tasks || [];
6459
+ if (tasks.length > lastCount) {
6460
+ const newTasks = tasks.slice(0, tasks.length - lastCount);
6461
+ for (const task of newTasks.reverse()) {
6462
+ const sColor = statusColor(task.outcome.status);
6463
+ const catColor = categoryColor(task.request.category);
6464
+ console.log(
6465
+ GRAY6(` ${formatTimestamp(task.createdAt)} `) + catColor(`[${task.request.category.toUpperCase()}]`) + " " + WHITE4(task.request.description.slice(0, 60) + (task.request.description.length > 60 ? "..." : "")) + " " + sColor(`\u25CF ${statusLabel(task.outcome.status)}`)
6466
+ );
6467
+ }
6468
+ lastCount = tasks.length;
6469
+ }
6470
+ } catch (e) {
6471
+ console.log(RED6(` \u274C Poll error: ${e.message}`));
6472
+ }
6473
+ await new Promise((r) => setTimeout(r, 3e3));
6474
+ }
6475
+ }
6476
+ async function runSettings(conversationId) {
6477
+ let response;
6478
+ try {
6479
+ response = await callCloudFunction("getCLIAutonomousTasks", { conversationId });
6480
+ } catch (e) {
6481
+ console.log(RED6(` \u274C Failed to fetch settings: ${e.message}`));
6482
+ return;
6483
+ }
6484
+ const settings = response?.settings || {};
6485
+ console.log("");
6486
+ console.log(ORANGE2(" \u2500\u2500\u2500 AUTONOMY SETTINGS \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"));
6487
+ console.log(GRAY6(` Current threshold: ${settings.autonomousConfidenceThreshold ?? 75}%`));
6488
+ console.log(GRAY6(" Tasks below this confidence level require your approval."));
6489
+ console.log("");
6490
+ const { threshold } = await inquirer.prompt([
6491
+ {
6492
+ type: "number",
6493
+ name: "threshold",
6494
+ message: AMBER7(" Confidence threshold (0-100):"),
6495
+ default: settings.autonomousConfidenceThreshold ?? 75,
6496
+ validate: (val) => val >= 0 && val <= 100 ? true : "Must be 0-100"
6497
+ }
6498
+ ]);
6499
+ const categories = ["security", "frontend", "backend", "cloud_functions", "documentation", "testing", "review", "fullstack"];
6500
+ const overrides = { ...settings.autonomousCategoryOverrides || {} };
6501
+ console.log("");
6502
+ console.log(GRAY6(" Category overrides:"));
6503
+ console.log("");
6504
+ for (const cat of categories) {
6505
+ const current = overrides[cat] || "threshold";
6506
+ const { override } = await inquirer.prompt([
6507
+ {
6508
+ type: "select",
6509
+ name: "override",
6510
+ message: categoryColor(cat)(` ${cat.padEnd(20)}`),
6511
+ default: current,
6512
+ choices: [
6513
+ { name: GRAY6("Use Threshold"), value: "threshold" },
6514
+ { name: GREEN6("Always Auto-Execute"), value: "autonomous" },
6515
+ { name: RED6("Always Require Approval"), value: "approval_required" }
6516
+ ]
6517
+ }
6518
+ ]);
6519
+ if (override === "threshold") {
6520
+ delete overrides[cat];
6521
+ } else {
6522
+ overrides[cat] = override;
6523
+ }
6524
+ }
6525
+ try {
6526
+ await callCloudFunction("updateCLIAutonomySettings", {
6527
+ conversationId,
6528
+ autonomousConfidenceThreshold: threshold,
6529
+ autonomousCategoryOverrides: overrides
6530
+ });
6531
+ console.log("");
6532
+ console.log(GREEN6(" \u2705 Settings saved."));
6533
+ } catch {
6534
+ console.log("");
6535
+ console.log(AMBER7(" \u26A0\uFE0F `updateCLIAutonomySettings` not deployed yet."));
6536
+ console.log(GRAY6(" Update via web app for now, or deploy the CF first."));
6537
+ }
6538
+ console.log("");
6539
+ }
6540
+ async function runTaskBoard(conversationId) {
6541
+ let continueLoop = true;
6542
+ while (continueLoop) {
6543
+ let response;
6544
+ try {
6545
+ response = await callCloudFunction("getCLIAutonomousTasks", { conversationId });
6546
+ } catch (e) {
6547
+ console.log(RED6(` \u274C Failed to fetch tasks: ${e.message}`));
6548
+ return;
6549
+ }
6550
+ const tasks = response?.tasks || [];
6551
+ const stats = response?.stats || {};
6552
+ renderStats(stats);
6553
+ if (tasks.length === 0) {
6554
+ console.log(GRAY6(" No autonomous tasks found for this conversation."));
6555
+ console.log(GRAY6(" Tasks appear here when UserBob dispatches work to Mini Bob."));
6556
+ console.log("");
6557
+ return;
6558
+ }
6559
+ const seen = /* @__PURE__ */ new Map();
6560
+ for (const task of tasks) {
6561
+ const key = task.request.description.slice(0, 80);
6562
+ if (!seen.has(key) || (task.createdAt || 0) > (seen.get(key).createdAt || 0)) {
6563
+ seen.set(key, task);
6564
+ }
6565
+ }
6566
+ const dedupedTasks = Array.from(seen.values());
6567
+ const taskChoices = dedupedTasks.map((task) => {
6568
+ const sColor = statusColor(task.outcome.status);
6569
+ const catColor = categoryColor(task.request.category);
6570
+ const desc = task.request.description.slice(0, 55) + (task.request.description.length > 55 ? "..." : "");
6571
+ return {
6572
+ name: sColor(` \u25CF ${statusLabel(task.outcome.status).padEnd(16)}`) + " " + catColor(`[${task.request.category.padEnd(15)}]`) + " " + WHITE4(desc),
6573
+ value: task.id,
6574
+ short: task.request.description.slice(0, 40)
6575
+ };
6576
+ });
6577
+ taskChoices.push({
6578
+ name: BORDER11(" \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"),
6579
+ value: "__separator__",
6580
+ short: "",
6581
+ disabled: true
6582
+ });
6583
+ taskChoices.push({
6584
+ name: GRAY6(" \u21A9 Exit Command Center"),
6585
+ value: "__exit__",
6586
+ short: "Exit"
6587
+ });
6588
+ const { selectedTaskId } = await inquirer.prompt([
6589
+ {
6590
+ type: "select",
6591
+ name: "selectedTaskId",
6592
+ message: ORANGE2(" Select a task to inspect:"),
6593
+ choices: taskChoices,
6594
+ pageSize: 14
6595
+ }
6596
+ ]);
6597
+ if (selectedTaskId === "__exit__" || selectedTaskId === "__separator__") {
6598
+ continueLoop = false;
6599
+ break;
6600
+ }
6601
+ const selectedTask = dedupedTasks.find((t) => t.id === selectedTaskId);
6602
+ if (!selectedTask) continue;
6603
+ renderTaskDetail(selectedTask);
6604
+ const actions = [];
6605
+ if (selectedTask.outcome.status === "awaiting_approval") {
6606
+ actions.push({ name: GREEN6(" \u2705 Approve \u2014 execute this task now"), value: "approve", short: "Approve" });
6607
+ actions.push({ name: RED6(" \u274C Deny \u2014 reject this task"), value: "deny", short: "Deny" });
6608
+ }
6609
+ actions.push({ name: AMBER7(" \u21A9 Back to task list"), value: "back", short: "Back" });
6610
+ actions.push({ name: GRAY6(" \u2715 Exit Command Center"), value: "exit", short: "Exit" });
6611
+ const { action } = await inquirer.prompt([
6612
+ {
6613
+ type: "select",
6614
+ name: "action",
6615
+ message: ORANGE2(" What would you like to do?"),
6616
+ choices: actions
6617
+ }
6618
+ ]);
6619
+ if (action === "approve") {
6620
+ const { confirmed } = await inquirer.prompt([
6621
+ {
6622
+ type: "confirm",
6623
+ name: "confirmed",
6624
+ message: AMBER7(" Approve task and execute autonomously?"),
6625
+ default: true
6626
+ }
6627
+ ]);
6628
+ if (confirmed) {
6629
+ console.log("");
6630
+ console.log(ORANGE2(" \u2500\u2500\u2500 EXECUTION STREAM \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"));
6631
+ console.log(GRAY6(" Mini Bob is executing. Streaming live logs...\n"));
6632
+ callCloudFunction("approveAutonomousTask", {
6633
+ conversationId,
6634
+ taskId: selectedTask.id,
6635
+ action: "approve"
6636
+ }).then(() => {
6637
+ }).catch((e) => {
6638
+ console.log(RED6(`
6639
+ \u274C Execution error: ${e.message}`));
6640
+ });
6641
+ let running = true;
6642
+ let seenLogIds = /* @__PURE__ */ new Set();
6643
+ let pollErrors = 0;
6644
+ const maxPollErrors = 5;
6645
+ const sigintHandler = () => {
6646
+ running = false;
6647
+ console.log("\n" + AMBER7(" Stream ended. Task continues in background."));
6648
+ process.exit(0);
6649
+ };
6650
+ process.on("SIGINT", sigintHandler);
6651
+ while (running) {
6652
+ await new Promise((r) => setTimeout(r, 2e3));
6653
+ try {
6654
+ const taskResponse = await callCloudFunction("getCLIAutonomousTasks", {
6655
+ conversationId,
6656
+ statusFilter: null
6657
+ });
6658
+ const updatedTask = taskResponse?.tasks?.find((t) => t.id === selectedTask.id);
6659
+ const logResponse = await callCloudFunction("getCLITaskExecutionLog", {
6660
+ conversationId,
6661
+ taskId: selectedTask.id
6662
+ });
6663
+ const logEntries = logResponse?.entries || [];
6664
+ for (const entry of logEntries) {
6665
+ if (seenLogIds.has(entry.id)) continue;
6666
+ seenLogIds.add(entry.id);
6667
+ const stage = entry.stage || "EXECUTION";
6668
+ let prefix;
6669
+ switch (stage) {
6670
+ case "INIT":
6671
+ prefix = CYAN6(" [INIT] ");
6672
+ break;
6673
+ case "TOOL_CALL":
6674
+ prefix = AMBER7(" [TOOL] ");
6675
+ break;
6676
+ case "FALLBACK":
6677
+ prefix = AMBER7(" [FALLBACK] ");
6678
+ break;
6679
+ case "COMPLETE":
6680
+ prefix = GREEN6(" [DONE] ");
6681
+ break;
6682
+ case "ERROR":
6683
+ prefix = RED6(" [ERROR] ");
6684
+ break;
6685
+ case "APPROVED":
6686
+ prefix = GREEN6(" [APPROVED] ");
6687
+ break;
6688
+ case "DENIED":
6689
+ prefix = RED6(" [DENIED] ");
6690
+ break;
6691
+ case "AWAITING_APPROVAL":
6692
+ prefix = AMBER7(" [PENDING] ");
6693
+ break;
6694
+ default:
6695
+ prefix = GRAY6(" [LOG] ");
6696
+ break;
6697
+ }
6698
+ console.log(prefix + WHITE4(entry.text));
6699
+ }
6700
+ if (updatedTask) {
6701
+ const status = updatedTask.outcome.status;
6702
+ if (status === "completed") {
6703
+ console.log("");
6704
+ console.log(GREEN6(" \u2705 Task complete!"));
6705
+ if (updatedTask.outcome.filesModified?.length > 0) {
6706
+ console.log("");
6707
+ console.log(AMBER7(" Files modified:"));
6708
+ for (const file of updatedTask.outcome.filesModified) {
6709
+ const icon = file.action === "created" ? GREEN6("+") : AMBER7("~");
6710
+ console.log(` ${icon} ${CYAN6(file.path || file)}`);
6711
+ }
6712
+ }
6713
+ if (updatedTask.outcome.resultSummary) {
6714
+ console.log("");
6715
+ console.log(AMBER7(" Summary:"));
6716
+ const summary = stripMarkdown2(updatedTask.outcome.resultSummary);
6717
+ const lines = summary.split("\n").slice(0, 8);
6718
+ for (const line of lines) {
6719
+ console.log(GRAY6(` ${line}`));
6720
+ }
6721
+ }
6722
+ if (updatedTask.outcome.turnsUsed) {
6723
+ console.log("");
6724
+ console.log(GRAY6(` Turns: ${updatedTask.outcome.turnsUsed} \u2502 Tokens: ${updatedTask.outcome.tokensConsumed || 0} \u2502 Provider: ${updatedTask.outcome.provider || "unknown"}`));
6725
+ }
6726
+ running = false;
6727
+ } else if (status === "failed") {
6728
+ console.log("");
6729
+ console.log(RED6(` \u274C Task failed: ${updatedTask.outcome.error || "Unknown error"}`));
6730
+ running = false;
6731
+ } else if (status === "denied") {
6732
+ console.log("");
6733
+ console.log(RED6(" \u274C Task was denied."));
6734
+ running = false;
6735
+ }
6736
+ }
6737
+ pollErrors = 0;
6738
+ } catch (e) {
6739
+ pollErrors++;
6740
+ if (pollErrors >= maxPollErrors) {
6741
+ console.log(RED6(` \u274C Lost connection after ${maxPollErrors} errors. Task continues in background.`));
6742
+ running = false;
6743
+ }
6744
+ }
6745
+ }
6746
+ process.removeListener("SIGINT", sigintHandler);
6747
+ console.log("");
6748
+ }
6749
+ } else if (action === "deny") {
6750
+ const { reason } = await inquirer.prompt([
6751
+ {
6752
+ type: "input",
6753
+ name: "reason",
6754
+ message: AMBER7(" Denial reason (optional):"),
6755
+ default: ""
6756
+ }
6757
+ ]);
6758
+ try {
6759
+ console.log(GRAY6(" Denying task..."));
6760
+ await callCloudFunction("approveAutonomousTask", {
6761
+ conversationId,
6762
+ taskId: selectedTask.id,
6763
+ action: "deny",
6764
+ reason: reason.trim() || null
6765
+ });
6766
+ console.log("");
6767
+ console.log(RED6(" \u274C Task denied."));
6768
+ console.log("");
6769
+ } catch (e) {
6770
+ console.log(RED6(` \u274C Failed to deny: ${e.message}`));
6771
+ }
6772
+ } else if (action === "exit") {
6773
+ continueLoop = false;
6774
+ break;
6775
+ }
6776
+ }
6777
+ }
6778
+ function registerCommandCenterCommand(program2) {
6779
+ program2.command("command-center").alias("cc").description("Autonomous Command Center \u2014 inspect, approve, and manage UserBob dispatch tasks").option("--stream", "Live decision stream feed").option("--settings", "Configure autonomy threshold and category overrides").action(async (options) => {
6780
+ if (!isAuthenticated()) {
6781
+ console.log("");
6782
+ console.log(RED6(" \u274C Authentication required."));
6783
+ console.log(GRAY6(" Run `bob login` first."));
6784
+ console.log("");
6785
+ process.exit(1);
6786
+ }
6787
+ const config = getConfig();
6788
+ const conversationId = config.conversationId;
6789
+ if (!conversationId) {
6790
+ console.log("");
6791
+ console.log(RED6(" \u274C No active conversation."));
6792
+ console.log(GRAY6(" Run `bob conversations join` first."));
6793
+ console.log("");
6794
+ process.exit(1);
6795
+ }
6796
+ console.log("");
6797
+ console.log(BORDER11(" \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"));
6798
+ console.log(BORDER11(" \u2551") + ORANGE2(" \u25C9 AUTONOMOUS COMMAND CENTER"));
6799
+ console.log(BORDER11(" \u2551") + GRAY6(` Conversation: ${conversationId.slice(0, 24)}...`));
6800
+ console.log(BORDER11(" \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"));
6801
+ if (options.stream) {
6802
+ await runDecisionStream(conversationId);
6803
+ return;
6804
+ }
6805
+ if (options.settings) {
6806
+ await runSettings(conversationId);
6807
+ return;
6808
+ }
6809
+ await runTaskBoard(conversationId);
6810
+ });
6811
+ }
6812
+
5723
6813
  // bin/bob.ts
5724
- var BRAND_PRIMARY11 = chalk24.hex("#E66F24");
5725
- var BRAND_SECONDARY15 = chalk24.hex("#FFAB00");
5726
- var SUCCESS16 = chalk24.hex("#66BB6A");
5727
- var INFO16 = chalk24.hex("#26C6DA");
5728
- var MUTED16 = chalk24.hex("#78909C");
5729
- var MODE_CONSULTANT9 = chalk24.hex("#AB47BC");
6814
+ var BRAND_PRIMARY11 = chalk26.hex("#E66F24");
6815
+ var BRAND_SECONDARY15 = chalk26.hex("#FFAB00");
6816
+ var SUCCESS16 = chalk26.hex("#66BB6A");
6817
+ var INFO16 = chalk26.hex("#26C6DA");
6818
+ var MUTED16 = chalk26.hex("#78909C");
6819
+ var MODE_CONSULTANT9 = chalk26.hex("#AB47BC");
5730
6820
  var program = new Command();
5731
6821
  program.name("bob").description("Bob's CLI \u2014 AI coding assistant and Forge orchestrator").version("0.2.0").helpOption(false).addHelpCommand(false);
5732
6822
  program.option("-h, --help", "Print this usage information").on("option:help", () => {
@@ -5740,7 +6830,7 @@ function printCustomHelp() {
5740
6830
  console.log("");
5741
6831
  console.log(BRAND_PRIMARY11(" \u25C9 Bob's CLI") + MUTED16(" \u2014 Your AI Engineering Partner, In Your Terminal."));
5742
6832
  console.log("");
5743
- console.log(chalk24.white(" Common commands:"));
6833
+ console.log(chalk26.white(" Common commands:"));
5744
6834
  console.log("");
5745
6835
  console.log(BRAND_SECONDARY15(' bob chat "message"'));
5746
6836
  console.log(MUTED16(" Chat with Bob \u2014 code-friendly engineering partner with file awareness."));
@@ -5751,13 +6841,13 @@ function printCustomHelp() {
5751
6841
  console.log(BRAND_SECONDARY15(" bob index"));
5752
6842
  console.log(MUTED16(" Index your project \u2014 generates summaries and dependency map for context."));
5753
6843
  console.log("");
5754
- console.log(chalk24.white(" Usage: ") + INFO16("bob <command> [arguments]"));
6844
+ console.log(chalk26.white(" Usage: ") + INFO16("bob <command> [arguments]"));
5755
6845
  console.log("");
5756
- console.log(chalk24.white(" Global options:"));
6846
+ console.log(chalk26.white(" Global options:"));
5757
6847
  console.log(MUTED16(" -h, --help Print this usage information."));
5758
6848
  console.log(MUTED16(" -V, --version Output the version number."));
5759
6849
  console.log("");
5760
- console.log(chalk24.white(" Available commands:"));
6850
+ console.log(chalk26.white(" Available commands:"));
5761
6851
  console.log("");
5762
6852
  console.log(INFO16(" Conversation"));
5763
6853
  printCmd("chat [message]", "Chat with Bob \u2014 code-friendly engineering partner");
@@ -5783,7 +6873,10 @@ function printCustomHelp() {
5783
6873
  console.log(MODE_CONSULTANT9(" Profile & Identity"));
5784
6874
  printCmd("profile", "View your behavioral DNA dashboard");
5785
6875
  printCmd("profile --cloud", "Generate cloud-powered daily profile");
6876
+ printCmd("userbob", "Launch your UserBob digital twin");
5786
6877
  printCmd("byok", "Manage Bring Your Own Key configuration");
6878
+ printCmd("command-center", "Autonomous Command Center \u2014 inspect and approve tasks");
6879
+ printCmd("cc", "Alias for command-center");
5787
6880
  console.log("");
5788
6881
  console.log(MUTED16(" Configuration"));
5789
6882
  printCmd("config show", "Display current configuration");
@@ -5792,7 +6885,7 @@ function printCustomHelp() {
5792
6885
  printCmd("logout", "Sign out and clear stored credentials");
5793
6886
  printCmd("whoami", "Show current auth status and project info");
5794
6887
  console.log("");
5795
- console.log(chalk24.white(" Interactive slash commands ") + MUTED16("(inside a chat/consult session):"));
6888
+ console.log(chalk26.white(" Interactive slash commands ") + MUTED16("(inside a chat/consult session):"));
5796
6889
  console.log("");
5797
6890
  printCmd("/exit", "End the session");
5798
6891
  printCmd("/new", "Start a fresh conversation");
@@ -5818,20 +6911,20 @@ function printCmd(cmd, desc) {
5818
6911
  }
5819
6912
  program.command("whoami").description("Show current authentication status and configuration").action(() => {
5820
6913
  const config = getConfig();
5821
- const projectName = path13.basename(process.cwd());
6914
+ const projectName = path14.basename(process.cwd());
5822
6915
  console.log("");
5823
- console.log(chalk24.bold(" \u{1F916} Bob's CLI"));
5824
- console.log(chalk24.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"));
5825
- console.log(` ${chalk24.cyan("Status:")} ${config.loggedIn ? chalk24.green("Logged in as " + config.email) : "Not logged in"}`);
5826
- console.log(` ${chalk24.cyan("Tier:")} ${config.tier === "platform" ? "Platform (Tier 3)" : "Local-first (Tier 1)"}`);
5827
- console.log(` ${chalk24.cyan("Provider:")} ${config.provider || "Not configured"}`);
5828
- console.log(` ${chalk24.cyan("Mode:")} ${config.personalizationMode ? "Personalized" : config.consultantMode ? "Consultant" : "Standard"}`);
5829
- console.log(` ${chalk24.cyan("IDRP:")} ${config.idrp ? "Enabled" : "Disabled"}`);
5830
- console.log(` ${chalk24.cyan("Project:")} ${projectName} (${process.cwd()})`);
5831
- console.log(` ${chalk24.cyan("Session:")} ${config.conversationId ? config.conversationId.slice(0, 20) + "..." : "None"}`);
6916
+ console.log(chalk26.bold(" \u{1F916} Bob's CLI"));
6917
+ console.log(chalk26.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"));
6918
+ console.log(` ${chalk26.cyan("Status:")} ${config.loggedIn ? chalk26.green("Logged in as " + config.email) : "Not logged in"}`);
6919
+ console.log(` ${chalk26.cyan("Tier:")} ${config.tier === "platform" ? "Platform (Tier 3)" : "Local-first (Tier 1)"}`);
6920
+ console.log(` ${chalk26.cyan("Provider:")} ${config.provider || "Not configured"}`);
6921
+ console.log(` ${chalk26.cyan("Mode:")} ${config.personalizationMode ? "Personalized" : config.consultantMode ? "Consultant" : "Standard"}`);
6922
+ console.log(` ${chalk26.cyan("IDRP:")} ${config.idrp ? "Enabled" : "Disabled"}`);
6923
+ console.log(` ${chalk26.cyan("Project:")} ${projectName} (${process.cwd()})`);
6924
+ console.log(` ${chalk26.cyan("Session:")} ${config.conversationId ? config.conversationId.slice(0, 20) + "..." : "None"}`);
5832
6925
  console.log("");
5833
6926
  if (!config.loggedIn) {
5834
- console.log(chalk24.gray(" Run `bob login` to authenticate."));
6927
+ console.log(chalk26.gray(" Run `bob login` to authenticate."));
5835
6928
  console.log("");
5836
6929
  }
5837
6930
  });
@@ -5850,23 +6943,25 @@ registerAutonomyCommand(program);
5850
6943
  registerServeCommand(program);
5851
6944
  registerRemoteCommand(program);
5852
6945
  registerProfileCommand(program);
6946
+ registerUserBobCommand(program);
6947
+ registerCommandCenterCommand(program);
5853
6948
  process.on("uncaughtException", (error) => {
5854
6949
  console.error("");
5855
- console.error(chalk24.hex("#EF5350")(" \u274C An unexpected error occurred."));
5856
- console.error(chalk24.hex("#78909C")(` ${error.message || "Unknown error"}`));
6950
+ console.error(chalk26.hex("#EF5350")(" \u274C An unexpected error occurred."));
6951
+ console.error(chalk26.hex("#78909C")(` ${error.message || "Unknown error"}`));
5857
6952
  console.error("");
5858
- console.error(chalk24.hex("#78909C")(" If this persists, please report it:"));
5859
- console.error(chalk24.hex("#26C6DA")(" https://github.com/bobsworkshop/bob-cli/issues"));
6953
+ console.error(chalk26.hex("#78909C")(" If this persists, please report it:"));
6954
+ console.error(chalk26.hex("#26C6DA")(" https://github.com/bobsworkshop/bob-cli/issues"));
5860
6955
  console.error("");
5861
6956
  process.exit(1);
5862
6957
  });
5863
6958
  process.on("unhandledRejection", (reason) => {
5864
6959
  console.error("");
5865
- console.error(chalk24.hex("#EF5350")(" \u274C An unexpected error occurred."));
5866
- console.error(chalk24.hex("#78909C")(` ${reason?.message || reason || "Unknown error"}`));
6960
+ console.error(chalk26.hex("#EF5350")(" \u274C An unexpected error occurred."));
6961
+ console.error(chalk26.hex("#78909C")(` ${reason?.message || reason || "Unknown error"}`));
5867
6962
  console.error("");
5868
- console.error(chalk24.hex("#78909C")(" If this persists, please report it:"));
5869
- console.error(chalk24.hex("#26C6DA")(" https://github.com/bobsworkshop/bob-cli/issues"));
6963
+ console.error(chalk26.hex("#78909C")(" If this persists, please report it:"));
6964
+ console.error(chalk26.hex("#26C6DA")(" https://github.com/bobsworkshop/bob-cli/issues"));
5870
6965
  console.error("");
5871
6966
  process.exit(1);
5872
6967
  });