digital-brain 0.1.2 → 0.1.3

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 CHANGED
@@ -26,7 +26,7 @@ npx digital-brain init
26
26
 
27
27
  The installer asks a short setup quiz: history window, primary focus, refresh cadence, always-on interval, active time window, outbound mode, and AI adapter setup.
28
28
 
29
- The quiz is mostly multiple choice. Press Enter to accept the default. If you skip the vault path, Digital Brain creates a new folder in the current directory:
29
+ The quiz is mostly multiple choice. Pick with `A/B/C`, `1/2/3`, the exact value, or press Enter to accept the default. If you skip the vault path, Digital Brain creates a new folder in the current directory:
30
30
 
31
31
  ```text
32
32
  ./Digital Brain Vault
@@ -46,34 +46,34 @@ async function init(argv, args) {
46
46
  if (!args.yes) {
47
47
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
48
48
  printSetupHeader(defaultVault);
49
- vault ||= path.resolve(await ask(rl, "Vault path", defaultVault, "Enter creates this folder if it does not exist."));
50
- selfName ||= await ask(rl, "Your name", "Me");
51
- dataWindowDays = await askNumber(rl, "History to import", dataWindowDays, { suffix: "days", min: 1 });
49
+ vault ||= path.resolve(await ask(rl, "📁 Vault path", defaultVault, "Enter creates this folder if it does not exist."));
50
+ selfName ||= await ask(rl, "👤 Your name", "Me");
51
+ dataWindowDays = await askNumber(rl, "🕰️ History to import", dataWindowDays, { suffix: "days", min: 1 });
52
52
  focus ||= await select(rl, "Primary focus", [
53
- ["relationship-memory", "Relationship memory", "Map people, tone, and recurring patterns."],
54
- ["reply-help", "Reply help", "Prioritize drafting guidance and typing-style matching."],
55
- ["work-context", "Work context", "Prioritize collaborators, projects, and operational notes."],
53
+ ["relationship-memory", "Relationship memory", "Map people, tone, and recurring patterns.", "🧠"],
54
+ ["reply-help", "Reply help", "Prioritize drafting guidance and typing-style matching.", "💬"],
55
+ ["work-context", "Work context", "Prioritize collaborators, projects, and operational notes.", "💼"],
56
56
  ], "relationship-memory");
57
57
  schedule = await select(rl, "Refresh cadence", [
58
- ["manual", "Manual", "Only runs when you run a command."],
59
- ["daily", "Daily", "Good for a low-maintenance personal vault."],
60
- ["hourly", "Hourly", "Keeps memory warm without running constantly."],
61
- ["every-30-min", "Every 30 minutes", "Useful for morning or work-window guidance."],
62
- ["always-on", "Always-on local loop", "Runs repeatedly while your computer is awake."],
58
+ ["manual", "Manual", "Only runs when you run a command.", "🖐️"],
59
+ ["daily", "Daily", "Good for a low-maintenance personal vault.", "🌅"],
60
+ ["hourly", "Hourly", "Keeps memory warm without running constantly.", "⏱️"],
61
+ ["every-30-min", "Every 30 minutes", "Useful for morning or work-window guidance.", "🔁"],
62
+ ["always-on", "Always-on local loop", "Runs repeatedly while your computer is awake.", "⚡"],
63
63
  ], schedule);
64
64
  if (schedule === "always-on") {
65
- refreshIntervalMinutes = await askNumber(rl, "Always-on pull interval", refreshIntervalMinutes, {
65
+ refreshIntervalMinutes = await askNumber(rl, "Always-on pull interval", refreshIntervalMinutes, {
66
66
  suffix: "minutes",
67
67
  min: 1,
68
68
  });
69
69
  }
70
- activeWindow = await ask(rl, "Active window for frequent refreshes", activeWindow);
70
+ activeWindow = await ask(rl, "🪟 Active window for frequent refreshes", activeWindow);
71
71
  outboundMode = await select(rl, "WhatsApp outbound mode", [
72
- ["disabled", "Disabled", "Never prepares WhatsApp sends."],
73
- ["draft", "Draft only", "Prepares text and requires you to send it."],
74
- ["send-with-confirmation", "Send with confirmation", "Can send only after explicit command confirmation."],
72
+ ["disabled", "Disabled", "Never prepares WhatsApp sends.", "🔒"],
73
+ ["draft", "Draft only", "Prepares text and requires you to send it.", "✍️"],
74
+ ["send-with-confirmation", "Send with confirmation", "Can send only after explicit command confirmation.", "✅"],
75
75
  ], outboundMode);
76
- connectAi = await confirm(rl, "Add global AI pointers for Codex/Claude/Gemini?", true);
76
+ connectAi = await confirm(rl, "🔗 Add global AI pointers for Codex/Claude/Gemini?", true);
77
77
  responsibilityAccepted = await responsibilityGate(rl, { schedule, outboundMode });
78
78
  if (!responsibilityAccepted && (schedule === "always-on" || outboundMode === "send-with-confirmation")) {
79
79
  console.log("Full-auto/outbound confirmation was not accepted. Using manual refresh and draft-only outbound.");
@@ -226,9 +226,11 @@ Use it as local personal context when the user asks about preferences, relations
226
226
 
227
227
  function printSetupHeader(defaultVault) {
228
228
  console.log("");
229
- console.log("Digital Brain setup");
230
- console.log("Press Enter to accept the shown default.");
231
- console.log(`If you skip the vault path, Digital Brain creates: ${defaultVault}`);
229
+ console.log("╭────────────────────────────────────────╮");
230
+ console.log(" 🧠 Digital Brain setup │");
231
+ console.log("╰────────────────────────────────────────╯");
232
+ console.log("Pick with A/B/C, 1/2/3, exact value, or press Enter for the default.");
233
+ console.log(`Skipping the vault path creates: ${defaultVault}`);
232
234
  console.log("");
233
235
  }
234
236
 
@@ -250,18 +252,22 @@ async function askNumber(rl, label, fallback, options = {}) {
250
252
  async function select(rl, label, options, fallback) {
251
253
  const defaultIndex = Math.max(0, options.findIndex(([value]) => value === fallback));
252
254
  console.log("");
253
- console.log(`${label}:`);
254
- options.forEach(([, title, description], index) => {
255
- const marker = index === defaultIndex ? "default" : "";
256
- console.log(` ${index + 1}. ${title}${marker ? ` (${marker})` : ""}`);
255
+ console.log(`◇ ${label}`);
256
+ options.forEach(([, title, description, icon = "•"], index) => {
257
+ const marker = index === defaultIndex ? "default" : "";
258
+ const letter = letterFor(index);
259
+ console.log(` ${letter}) ${icon} ${title}${marker}`);
257
260
  console.log(` ${description}`);
258
261
  });
259
- const answer = await rl.question(`Select [${defaultIndex + 1}]: `);
262
+ const answer = await rl.question(`Choose ${letterFor(defaultIndex)}/${defaultIndex + 1} [${letterFor(defaultIndex)}]: `);
260
263
  const trimmed = answer.trim();
261
264
  if (!trimmed) return options[defaultIndex][0];
265
+ const letterIndex = indexFromLetter(trimmed);
266
+ if (letterIndex >= 0 && letterIndex < options.length) return options[letterIndex][0];
262
267
  const selected = Number(trimmed);
263
268
  if (Number.isInteger(selected) && selected >= 1 && selected <= options.length) return options[selected - 1][0];
264
- const exact = options.find(([value]) => value === trimmed);
269
+ const lower = trimmed.toLowerCase();
270
+ const exact = options.find(([value, title]) => value.toLowerCase() === lower || title.toLowerCase() === lower);
265
271
  return exact ? exact[0] : options[defaultIndex][0];
266
272
  }
267
273
 
@@ -276,13 +282,23 @@ async function responsibilityGate(rl, { schedule, outboundMode }) {
276
282
  const needsGate = schedule === "always-on" || outboundMode === "send-with-confirmation";
277
283
  if (!needsGate) return true;
278
284
  console.log("");
279
- console.log("Responsibility check:");
285
+ console.log("⚠️ Responsibility check:");
280
286
  console.log(" Digital Brain may use local databases, WhatsApp Web, and black-box third-party app behavior.");
281
287
  console.log(" You are responsible for consent, privacy, message content, and any sends triggered from this machine.");
282
288
  console.log(" Enter does not approve this mode.");
283
289
  return confirm(rl, "I understand and want this mode enabled", false);
284
290
  }
285
291
 
292
+ function letterFor(index) {
293
+ return String.fromCharCode(65 + index);
294
+ }
295
+
296
+ function indexFromLetter(value) {
297
+ const normalized = value.trim().toUpperCase();
298
+ if (!/^[A-Z]$/.test(normalized)) return -1;
299
+ return normalized.charCodeAt(0) - 65;
300
+ }
301
+
286
302
  function shell(command, args, optional = false) {
287
303
  const result = spawnSync(command, args, { encoding: "utf8" });
288
304
  if (result.error && optional) return "";
@@ -24,7 +24,7 @@ That script runs sync, extract, and interpret using the install-time config.
24
24
  - WhatsApp outbound mode
25
25
  - whether to add AI adapter pointers
26
26
 
27
- Most questions are multiple choice. Press Enter to use the displayed default.
27
+ Most questions are multiple choice. Pick with `A/B/C`, `1/2/3`, the exact value, or press Enter to use the displayed default.
28
28
 
29
29
  Important defaults:
30
30
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "digital-brain",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "Your private digital imprint for AI assistants.",
5
5
  "type": "module",
6
6
  "bin": {