fabiana 0.2.0 → 0.4.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 CHANGED
@@ -57,6 +57,21 @@ She's built on [Pi SDK](https://github.com/mariozechner/pi) — which means she
57
57
 
58
58
  Memory is tiered — hot files load every session, warm files load when relevant, cold files sit in the archive, searchable when needed. She writes and organizes it herself. You can read any of it any time.
59
59
 
60
+ ### Everything lives in `~/.fabiana`
61
+
62
+ Your data, config, and even her system prompt all live in one place:
63
+
64
+ ```
65
+ ~/.fabiana/
66
+ ├── data/memory/ ← everything she remembers about you
67
+ ├── config/system.md ← her base personality and instructions
68
+ ├── config/system-chat.md ← how she behaves in conversation
69
+ ├── config/manifest.json ← what files she's allowed to touch
70
+ └── .env ← your API keys
71
+ ```
72
+
73
+ No black boxes. Open `~/.fabiana/config/system.md` to see exactly what she's been told to do — or edit it to change how she thinks, speaks, or behaves. Want her to be more terse? More philosophical? Less likely to roast you at 1am? That's the file.
74
+
60
75
  ---
61
76
 
62
77
  ## Installation
package/ascii.txt ADDED
@@ -0,0 +1,10 @@
1
+ ________ ____ _______ .-./`) ____ ,---. .--. ____
2
+ | | .' __ `. \ ____ \\ .-.') .' __ `. | \ | | .' __ `.
3
+ | .----'/ ' \ \| | \ |/ `-' \/ ' \ \| , \ | |/ ' \ \
4
+ | _|____ |___| / || |____/ / `-'`"`|___| / || |\_ \| ||___| / |
5
+ |_( )_ | _.-` || _ _ '. .---. _.-` || _( )_\ | _.-` |
6
+ (_ o._)__|.' _ || ( ' ) \| | .' _ || (_ o _) |.' _ |
7
+ |(_,_) | _( )_ || (_{;}_) || | | _( )_ || (_,_)\ || _( )_ |
8
+ | | \ (_ o _) /| (_,_) /| | \ (_ o _) /| | | |\ (_ o _) /
9
+ '---' '.(_,_).' /_______.' '---' '.(_,_).' '--' '--' '.(_,_).'
10
+
@@ -9,7 +9,7 @@ import { Logger } from '../utils/logger.js';
9
9
  import { createFabianaTools } from '../tools/index.js';
10
10
  import { loadContext, buildPrompt } from '../loaders/context.js';
11
11
  import { loadPlugins } from '../loaders/plugins.js';
12
- import { paths, PLUGINS_DIR } from '../paths.js';
12
+ import { paths, PLUGINS_DIR, FABIANA_HOME } from '../paths.js';
13
13
  async function loadConfig() {
14
14
  try {
15
15
  const content = await fs.readFile(paths.configJson, 'utf-8');
@@ -48,6 +48,8 @@ export async function runPiSession(mode, incomingMessage, channel, incomingMsg,
48
48
  let systemPromptContent = modeSystemPrompt
49
49
  ? `${baseSystemPrompt}\n\n---\n\n${modeSystemPrompt}`
50
50
  : baseSystemPrompt;
51
+ // Resolve .fabiana/ references to the actual home path so Fabiana uses correct absolute paths
52
+ systemPromptContent = systemPromptContent.replaceAll('.fabiana/', `${FABIANA_HOME}/`);
51
53
  // Inject owner name and conversation purpose into external system prompt
52
54
  if (mode.startsWith('external-')) {
53
55
  const identity = await fs.readFile(paths.memory('identity.md'), 'utf-8').catch(() => '');
@@ -1,11 +1,15 @@
1
1
  import fs from 'fs/promises';
2
2
  import { paths } from '../paths.js';
3
+ const TODAY_LOG_MAX_LINES = 80;
3
4
  export async function loadContext(mode, incomingMessage, conversationState) {
4
5
  const timestamp = new Date().toISOString();
6
+ const today = timestamp.slice(0, 10);
5
7
  const identity = await readFile(paths.memory('identity.md'), '(No identity file yet)');
6
8
  const core = await readFile(paths.memory('core.md'), '(No core memory yet)');
7
9
  const recentMemory = await readFile(paths.memory('recent', 'this-week.md'), '(No recent memory yet)');
8
- return { mode, identity, core, recentMemory, incomingMessage, timestamp, conversationState };
10
+ const rawLog = await readFile(paths.logs(`conversation-${today}.log`), '');
11
+ const todayLog = tailLines(rawLog, TODAY_LOG_MAX_LINES);
12
+ return { mode, identity, core, recentMemory, todayLog, incomingMessage, timestamp, conversationState };
9
13
  }
10
14
  async function readFile(filePath, fallback) {
11
15
  try {
@@ -15,7 +19,19 @@ async function readFile(filePath, fallback) {
15
19
  return fallback;
16
20
  }
17
21
  }
22
+ function tailLines(text, maxLines) {
23
+ if (!text)
24
+ return '';
25
+ const lines = text.split('\n').filter(l => l.trim());
26
+ if (lines.length <= maxLines)
27
+ return lines.join('\n');
28
+ const omitted = lines.length - maxLines;
29
+ return `(${omitted} earlier lines omitted — full log in ${paths.logs('conversation-' + new Date().toISOString().slice(0, 10) + '.log')})\n...\n` + lines.slice(-maxLines).join('\n');
30
+ }
18
31
  export function buildPrompt(ctx) {
32
+ const todaySection = ctx.todayLog
33
+ ? `\n\n### Today's Conversation\n${ctx.todayLog}`
34
+ : '';
19
35
  const base = `# Session Start — ${ctx.timestamp}
20
36
  **Mode**: ${ctx.mode}
21
37
 
@@ -30,7 +46,7 @@ ${ctx.identity}
30
46
  ${ctx.core}
31
47
 
32
48
  ### Recent (This Week)
33
- ${ctx.recentMemory}`;
49
+ ${ctx.recentMemory}${todaySection}`;
34
50
  if (ctx.mode === 'chat' && ctx.incomingMessage) {
35
51
  return `${base}
36
52
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fabiana",
3
- "version": "0.2.0",
3
+ "version": "0.4.0",
4
4
  "description": "Personal AI assistant that actually feels personal",
5
5
  "type": "module",
6
6
  "bin": {
@@ -17,7 +17,8 @@
17
17
  },
18
18
  "files": [
19
19
  "bin/",
20
- "dist/"
20
+ "dist/",
21
+ "ascii.txt"
21
22
  ],
22
23
  "keywords": [
23
24
  "ai",