@bobsworkshop/cli 1.1.0 → 1.2.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/README.md +7 -0
- package/dist/bob.js +35 -41
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -621,6 +621,13 @@ Tier 1 — Local (Free) Tier 3 — Platform (Subscription)
|
|
|
621
621
|
Same commands. Scale without changing tools.
|
|
622
622
|
|
|
623
623
|
---
|
|
624
|
+
## What's New in v1.2.0
|
|
625
|
+
|
|
626
|
+
- **Per-project conversation scoping** — `conversationId` is now stored in each project's `~/.bob/projects/{name}/project.json` instead of the global config. When you `cd` between projects, `bob chat` automatically resumes the correct conversation for that project. No more cross-contamination between codebases.
|
|
627
|
+
- **Backward compatible migration** — Existing installs are unaffected. If no project-level `conversationId` exists yet, Bob falls back to the global config value seamlessly. The new value is written to `project.json` on first interaction.
|
|
628
|
+
- **`project.json` now tracks `lastActive`** — Every time a conversation ID is written to a project, the `lastActive` timestamp is updated. Useful for future project-aware features.
|
|
629
|
+
- **Bug fix: `remote.ts` conversation ID** — `bob remote` now reads the active conversation ID from project scope, not the global config. Connecting to an Active Bob correctly reflects the current project's conversation.
|
|
630
|
+
- **Bug fix: `serve.ts` conversation ID** — `bob serve` now resolves the conversation ID from project scope before registering the daemon session, ensuring SovereignLink binds to the correct project conversation.
|
|
624
631
|
|
|
625
632
|
## What's New in v1.1.0
|
|
626
633
|
|
package/dist/bob.js
CHANGED
|
@@ -4721,7 +4721,8 @@ function registerServeCommand(program2) {
|
|
|
4721
4721
|
console.log("");
|
|
4722
4722
|
return;
|
|
4723
4723
|
}
|
|
4724
|
-
|
|
4724
|
+
const conversationId = getActiveConversationId(process.cwd()) || config.conversationId;
|
|
4725
|
+
if (!conversationId) {
|
|
4725
4726
|
console.log("");
|
|
4726
4727
|
console.log(RED2(" \u274C No active conversation."));
|
|
4727
4728
|
console.log(GRAY2(" Active Bob must be bound to a conversation."));
|
|
@@ -4773,10 +4774,10 @@ function registerServeCommand(program2) {
|
|
|
4773
4774
|
const machineId = os2.hostname();
|
|
4774
4775
|
const projectName = path10.basename(process.cwd());
|
|
4775
4776
|
const sessionId = `${machineId}_${Date.now()}`;
|
|
4776
|
-
await startActiveBob(config, sessionId, machineId, projectName, tierConfig, userTier);
|
|
4777
|
+
await startActiveBob(config, conversationId, sessionId, machineId, projectName, tierConfig, userTier);
|
|
4777
4778
|
});
|
|
4778
4779
|
}
|
|
4779
|
-
async function startActiveBob(config, sessionId, machineId, projectName, tierConfig, userTier) {
|
|
4780
|
+
async function startActiveBob(config, conversationId, sessionId, machineId, projectName, tierConfig, userTier) {
|
|
4780
4781
|
console.log("");
|
|
4781
4782
|
console.log(BORDER5(" \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"));
|
|
4782
4783
|
console.log(BORDER5(" \u2551") + CYAN2(" \u{1F310} Bob Serve \u2014 Active Bob Online ") + BORDER5("\u2551"));
|
|
@@ -4785,7 +4786,7 @@ async function startActiveBob(config, sessionId, machineId, projectName, tierCon
|
|
|
4785
4786
|
console.log(BORDER5(" \u2551") + GRAY2(` Machine: ${machineId}`));
|
|
4786
4787
|
console.log(BORDER5(" \u2551") + GRAY2(` Project: ${projectName} (${process.cwd()})`));
|
|
4787
4788
|
console.log(BORDER5(" \u2551") + GRAY2(` Session: ${sessionId.slice(0, 30)}...`));
|
|
4788
|
-
console.log(BORDER5(" \u2551") + GRAY2(` Convo: ${
|
|
4789
|
+
console.log(BORDER5(" \u2551") + GRAY2(` Convo: ${conversationId?.slice(0, 24)}...`));
|
|
4789
4790
|
console.log(BORDER5(" \u2551") + AMBER4(` Tier: ${userTier}`));
|
|
4790
4791
|
console.log(BORDER5(" \u2551") + GRAY2(` Polling: every ${tierConfig.activeInterval / 1e3}s`));
|
|
4791
4792
|
if (tierConfig.sleepInterval) {
|
|
@@ -4805,7 +4806,7 @@ async function startActiveBob(config, sessionId, machineId, projectName, tierCon
|
|
|
4805
4806
|
console.log("");
|
|
4806
4807
|
try {
|
|
4807
4808
|
await callCloudFunction("registerRemoteDaemonSession", {
|
|
4808
|
-
conversationId
|
|
4809
|
+
conversationId,
|
|
4809
4810
|
sessionId,
|
|
4810
4811
|
machineId,
|
|
4811
4812
|
projectName,
|
|
@@ -4827,7 +4828,7 @@ async function startActiveBob(config, sessionId, machineId, projectName, tierCon
|
|
|
4827
4828
|
console.log(GRAY2(" \u{1F50C} Shutting down Active Bob..."));
|
|
4828
4829
|
try {
|
|
4829
4830
|
await callCloudFunction("deregisterRemoteDaemonSession", {
|
|
4830
|
-
conversationId
|
|
4831
|
+
conversationId,
|
|
4831
4832
|
sessionId
|
|
4832
4833
|
});
|
|
4833
4834
|
console.log(GRAY2(" \u2705 Session deregistered. Bob is offline."));
|
|
@@ -4853,7 +4854,7 @@ async function startActiveBob(config, sessionId, machineId, projectName, tierCon
|
|
|
4853
4854
|
console.log("");
|
|
4854
4855
|
try {
|
|
4855
4856
|
await callCloudFunction("deregisterRemoteDaemonSession", {
|
|
4856
|
-
conversationId
|
|
4857
|
+
conversationId,
|
|
4857
4858
|
sessionId
|
|
4858
4859
|
});
|
|
4859
4860
|
} catch {
|
|
@@ -4871,7 +4872,7 @@ async function startActiveBob(config, sessionId, machineId, projectName, tierCon
|
|
|
4871
4872
|
const currentInterval = isSleeping && tierConfig.sleepInterval ? tierConfig.sleepInterval : tierConfig.activeInterval;
|
|
4872
4873
|
try {
|
|
4873
4874
|
const result = await callCloudFunction("pollRemoteCommands", {
|
|
4874
|
-
conversationId
|
|
4875
|
+
conversationId,
|
|
4875
4876
|
sessionId
|
|
4876
4877
|
});
|
|
4877
4878
|
if (result?.command) {
|
|
@@ -4887,7 +4888,7 @@ async function startActiveBob(config, sessionId, machineId, projectName, tierCon
|
|
|
4887
4888
|
console.log(AMBER4(` [${timestamp}] \u23F3 Received: ${type}${payload.message ? ` "${payload.message.slice(0, 40)}${payload.message.length > 40 ? "..." : ""}"` : ""}`));
|
|
4888
4889
|
const commandResult = await executeRemoteCommand(type, payload, config);
|
|
4889
4890
|
await callCloudFunction("completeRemoteCommand", {
|
|
4890
|
-
conversationId
|
|
4891
|
+
conversationId,
|
|
4891
4892
|
commandId: cmd.id,
|
|
4892
4893
|
sessionId,
|
|
4893
4894
|
result: commandResult
|
|
@@ -5320,7 +5321,6 @@ async function executeRestore(payload, config) {
|
|
|
5320
5321
|
isGlobal,
|
|
5321
5322
|
isSource,
|
|
5322
5323
|
s3VersionId: null
|
|
5323
|
-
// always latest in headless mode
|
|
5324
5324
|
});
|
|
5325
5325
|
const response = await axios.get(downloadResult.downloadUrl, {
|
|
5326
5326
|
responseType: "arraybuffer",
|
|
@@ -5385,16 +5385,17 @@ function registerRemoteCommand(program2) {
|
|
|
5385
5385
|
console.log("");
|
|
5386
5386
|
return;
|
|
5387
5387
|
}
|
|
5388
|
-
|
|
5388
|
+
const activeConvoId = getActiveConversationId(process.cwd()) || config.conversationId;
|
|
5389
|
+
if (options.new || !activeConvoId) {
|
|
5389
5390
|
await discoverAndConnect(config);
|
|
5390
5391
|
return;
|
|
5391
5392
|
}
|
|
5392
5393
|
if (options.interactive || !type && !options.new) {
|
|
5393
|
-
await runInteractiveRemote(config, options.session);
|
|
5394
|
+
await runInteractiveRemote(config, activeConvoId, options.session);
|
|
5394
5395
|
return;
|
|
5395
5396
|
}
|
|
5396
5397
|
if (!type) {
|
|
5397
|
-
await showConnectionStatus(config);
|
|
5398
|
+
await showConnectionStatus(config, activeConvoId);
|
|
5398
5399
|
return;
|
|
5399
5400
|
}
|
|
5400
5401
|
const validTypes = [
|
|
@@ -5414,7 +5415,7 @@ function registerRemoteCommand(program2) {
|
|
|
5414
5415
|
console.log("");
|
|
5415
5416
|
return;
|
|
5416
5417
|
}
|
|
5417
|
-
const payload = { conversationId:
|
|
5418
|
+
const payload = { conversationId: activeConvoId };
|
|
5418
5419
|
if (message) payload.message = message;
|
|
5419
5420
|
if (options.auto) payload.auto = true;
|
|
5420
5421
|
if (options.source) payload.isSource = true;
|
|
@@ -5427,15 +5428,15 @@ function registerRemoteCommand(program2) {
|
|
|
5427
5428
|
console.log("");
|
|
5428
5429
|
return;
|
|
5429
5430
|
}
|
|
5430
|
-
await dispatchCommand(config, type, payload, options.session);
|
|
5431
|
+
await dispatchCommand(config, activeConvoId, type, payload, options.session);
|
|
5431
5432
|
});
|
|
5432
5433
|
}
|
|
5433
|
-
async function runInteractiveRemote(config, targetSession) {
|
|
5434
|
+
async function runInteractiveRemote(config, activeConvoId, targetSession) {
|
|
5434
5435
|
const spinner = ora7({ text: INFO14(" Connecting to Active Bob..."), spinner: "dots" }).start();
|
|
5435
5436
|
let activeBobName = "Unknown";
|
|
5436
5437
|
try {
|
|
5437
5438
|
const result = await callCloudFunction("listActiveBobs", {
|
|
5438
|
-
conversationId:
|
|
5439
|
+
conversationId: activeConvoId
|
|
5439
5440
|
});
|
|
5440
5441
|
const sessions = (result?.sessions || []).filter((s) => s.active);
|
|
5441
5442
|
if (sessions.length === 0) {
|
|
@@ -5457,7 +5458,7 @@ async function runInteractiveRemote(config, targetSession) {
|
|
|
5457
5458
|
console.log(BORDER6(" \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"));
|
|
5458
5459
|
console.log(BORDER6(" \u2551") + INFO14(" \u{1F310} Active Bob \u2014 Remote Session") + MUTED14(` (${activeBobName})`));
|
|
5459
5460
|
console.log(BORDER6(" \u2560\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2563"));
|
|
5460
|
-
console.log(BORDER6(" \u2551") + MUTED14(` Conversation: ${
|
|
5461
|
+
console.log(BORDER6(" \u2551") + MUTED14(` Conversation: ${activeConvoId?.slice(0, 28)}...`));
|
|
5461
5462
|
console.log(BORDER6(" \u2551") + MUTED14(" Commands dispatched to the remote machine."));
|
|
5462
5463
|
console.log(BORDER6(" \u2551"));
|
|
5463
5464
|
console.log(BORDER6(" \u2551") + chalk20.white(" Slash Commands:"));
|
|
@@ -5494,7 +5495,7 @@ async function runInteractiveRemote(config, targetSession) {
|
|
|
5494
5495
|
if (trimmed.startsWith("/consult ")) {
|
|
5495
5496
|
const msg = trimmed.slice(9).trim().replace(/^["']|["']$/g, "");
|
|
5496
5497
|
if (msg) {
|
|
5497
|
-
await dispatchAndShow(config, "consult", { message: msg }, targetSession);
|
|
5498
|
+
await dispatchAndShow(config, activeConvoId, "consult", { message: msg }, targetSession);
|
|
5498
5499
|
} else {
|
|
5499
5500
|
console.log(ERROR12(' \u274C Provide a message: /consult "your question"'));
|
|
5500
5501
|
}
|
|
@@ -5504,7 +5505,7 @@ async function runInteractiveRemote(config, targetSession) {
|
|
|
5504
5505
|
if (trimmed.startsWith("/push ")) {
|
|
5505
5506
|
const msg = trimmed.slice(6).trim().replace(/^["']|["']$/g, "");
|
|
5506
5507
|
if (msg) {
|
|
5507
|
-
await dispatchAndShow(config, "push", { message: msg }, targetSession);
|
|
5508
|
+
await dispatchAndShow(config, activeConvoId, "push", { message: msg }, targetSession);
|
|
5508
5509
|
} else {
|
|
5509
5510
|
console.log(ERROR12(' \u274C Provide a commit message: /push "your message"'));
|
|
5510
5511
|
}
|
|
@@ -5512,12 +5513,12 @@ async function runInteractiveRemote(config, targetSession) {
|
|
|
5512
5513
|
return;
|
|
5513
5514
|
}
|
|
5514
5515
|
if (trimmed === "/index") {
|
|
5515
|
-
await dispatchAndShow(config, "index", {}, targetSession);
|
|
5516
|
+
await dispatchAndShow(config, activeConvoId, "index", {}, targetSession);
|
|
5516
5517
|
prompt();
|
|
5517
5518
|
return;
|
|
5518
5519
|
}
|
|
5519
5520
|
if (trimmed === "/analyse" || trimmed === "/analyze") {
|
|
5520
|
-
await dispatchAndShow(config, "analyse", {}, targetSession);
|
|
5521
|
+
await dispatchAndShow(config, activeConvoId, "analyse", {}, targetSession);
|
|
5521
5522
|
prompt();
|
|
5522
5523
|
return;
|
|
5523
5524
|
}
|
|
@@ -5527,7 +5528,7 @@ async function runInteractiveRemote(config, targetSession) {
|
|
|
5527
5528
|
const backupPayload = {};
|
|
5528
5529
|
if (flag === "source") backupPayload.isSource = true;
|
|
5529
5530
|
if (flag === "global") backupPayload.isGlobal = true;
|
|
5530
|
-
await dispatchAndShow(config, "backup", backupPayload, targetSession);
|
|
5531
|
+
await dispatchAndShow(config, activeConvoId, "backup", backupPayload, targetSession);
|
|
5531
5532
|
prompt();
|
|
5532
5533
|
return;
|
|
5533
5534
|
}
|
|
@@ -5537,17 +5538,17 @@ async function runInteractiveRemote(config, targetSession) {
|
|
|
5537
5538
|
const restorePayload = {};
|
|
5538
5539
|
if (flag === "source") restorePayload.isSource = true;
|
|
5539
5540
|
if (flag === "global") restorePayload.isGlobal = true;
|
|
5540
|
-
await dispatchAndShow(config, "restore", restorePayload, targetSession);
|
|
5541
|
+
await dispatchAndShow(config, activeConvoId, "restore", restorePayload, targetSession);
|
|
5541
5542
|
prompt();
|
|
5542
5543
|
return;
|
|
5543
5544
|
}
|
|
5544
|
-
await dispatchAndShow(config, "chat", { message: trimmed }, targetSession);
|
|
5545
|
+
await dispatchAndShow(config, activeConvoId, "chat", { message: trimmed }, targetSession);
|
|
5545
5546
|
prompt();
|
|
5546
5547
|
});
|
|
5547
5548
|
};
|
|
5548
5549
|
prompt();
|
|
5549
5550
|
}
|
|
5550
|
-
async function dispatchAndShow(config, type, payload, targetSession) {
|
|
5551
|
+
async function dispatchAndShow(config, activeConvoId, type, payload, targetSession) {
|
|
5551
5552
|
const spinner = ora7({
|
|
5552
5553
|
text: BRAND_SECONDARY13(` \u{1F4E1} Active Bob executing: ${type}...`),
|
|
5553
5554
|
spinner: "dots"
|
|
@@ -5556,9 +5557,9 @@ async function dispatchAndShow(config, type, payload, targetSession) {
|
|
|
5556
5557
|
const MAX_POLLS = 300;
|
|
5557
5558
|
try {
|
|
5558
5559
|
const result = await callCloudFunction("sendRemoteCommand", {
|
|
5559
|
-
conversationId:
|
|
5560
|
+
conversationId: activeConvoId,
|
|
5560
5561
|
type,
|
|
5561
|
-
payload: { ...payload, conversationId:
|
|
5562
|
+
payload: { ...payload, conversationId: activeConvoId },
|
|
5562
5563
|
targetSession: targetSession || null
|
|
5563
5564
|
});
|
|
5564
5565
|
if (!result?.success) {
|
|
@@ -5572,7 +5573,7 @@ async function dispatchAndShow(config, type, payload, targetSession) {
|
|
|
5572
5573
|
pollCount++;
|
|
5573
5574
|
try {
|
|
5574
5575
|
const pollResult = await callCloudFunction("getRemoteCommandResult", {
|
|
5575
|
-
conversationId:
|
|
5576
|
+
conversationId: activeConvoId,
|
|
5576
5577
|
commandId
|
|
5577
5578
|
});
|
|
5578
5579
|
if (pollResult?.status === "completed") {
|
|
@@ -5631,17 +5632,10 @@ async function dispatchAndShow(config, type, payload, targetSession) {
|
|
|
5631
5632
|
console.log("");
|
|
5632
5633
|
}
|
|
5633
5634
|
}
|
|
5634
|
-
async function showConnectionStatus(config) {
|
|
5635
|
-
if (!config.conversationId) {
|
|
5636
|
-
console.log("");
|
|
5637
|
-
console.log(ERROR12(" \u{1F534} No conversation selected."));
|
|
5638
|
-
console.log(MUTED14(" Run `bob remote --new` to find and connect to an Active Bob."));
|
|
5639
|
-
console.log("");
|
|
5640
|
-
return;
|
|
5641
|
-
}
|
|
5635
|
+
async function showConnectionStatus(config, activeConvoId) {
|
|
5642
5636
|
const spinner = ora7({ text: INFO14(" Checking Active Bob status..."), spinner: "dots" }).start();
|
|
5643
5637
|
try {
|
|
5644
|
-
const result = await callCloudFunction("listActiveBobs", { conversationId:
|
|
5638
|
+
const result = await callCloudFunction("listActiveBobs", { conversationId: activeConvoId });
|
|
5645
5639
|
spinner.stop();
|
|
5646
5640
|
const sessions = result?.sessions || [];
|
|
5647
5641
|
const activeSessions = sessions.filter((s) => s.active);
|
|
@@ -5649,7 +5643,7 @@ async function showConnectionStatus(config) {
|
|
|
5649
5643
|
console.log(BORDER6(" \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"));
|
|
5650
5644
|
console.log(BORDER6(" \u2551") + INFO14(" \u{1F310} Remote Connection Status"));
|
|
5651
5645
|
console.log(BORDER6(" \u2560\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2563"));
|
|
5652
|
-
console.log(BORDER6(" \u2551") + MUTED14(` Conversation: ${
|
|
5646
|
+
console.log(BORDER6(" \u2551") + MUTED14(` Conversation: ${activeConvoId?.slice(0, 28)}...`));
|
|
5653
5647
|
console.log(BORDER6(" \u2551"));
|
|
5654
5648
|
if (activeSessions.length === 0) {
|
|
5655
5649
|
console.log(BORDER6(" \u2551") + ERROR12(" \u{1F534} No Active Bob found on this conversation."));
|
|
@@ -5733,8 +5727,8 @@ async function discoverAndConnect(config) {
|
|
|
5733
5727
|
console.log("");
|
|
5734
5728
|
}
|
|
5735
5729
|
}
|
|
5736
|
-
async function dispatchCommand(config, type, payload, targetSession) {
|
|
5737
|
-
await dispatchAndShow(config, type, payload, targetSession);
|
|
5730
|
+
async function dispatchCommand(config, activeConvoId, type, payload, targetSession) {
|
|
5731
|
+
await dispatchAndShow(config, activeConvoId, type, payload, targetSession);
|
|
5738
5732
|
}
|
|
5739
5733
|
function getTimeAgo2(isoDate) {
|
|
5740
5734
|
const now = Date.now();
|