claude-home 1.5.31 → 1.5.35

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-home",
3
- "version": "1.5.31",
3
+ "version": "1.5.35",
4
4
  "description": "Web dashboard for Claude Code — browse sessions, manage skills, hooks, commands, and agents",
5
5
  "main": "server.js",
6
6
  "bin": {
@@ -8,7 +8,7 @@
8
8
  },
9
9
  "files": [
10
10
  "bin/",
11
- "server.js",
11
+ "server.js",
12
12
  "public/",
13
13
  "marketplace.default.json",
14
14
  "README.md"
package/public/index.html CHANGED
@@ -2576,10 +2576,10 @@
2576
2576
 
2577
2577
  <!-- Carried over -->
2578
2578
  <template x-if="todayData.tasks.some(t => t.carriedOver && !t.done)">
2579
- <div style="margin-bottom:8px">
2580
- <div style="font-size:10px;color:var(--ink-3);margin-bottom:4px">↩ Carried over</div>
2579
+ <div style="margin-bottom:12px">
2580
+ <div style="font-size:10px;font-weight:600;color:var(--ink-3);text-transform:uppercase;letter-spacing:.05em;margin-bottom:6px">↩ Carried over</div>
2581
2581
  <template x-for="task in todayData.tasks.filter(t => t.carriedOver && !t.done)" :key="task.id">
2582
- <div style="display:flex;align-items:center;gap:8px;padding:6px 0;border-bottom:1px solid var(--rule)">
2582
+ <div style="display:flex;align-items:center;gap:8px;padding:6px 10px;margin-bottom:4px;background:var(--canvas-2);border:1px solid var(--rule);border-left:3px solid var(--ink-3);border-radius:4px">
2583
2583
  <input type="checkbox" :checked="task.done" @change="toggleTodayTask(task.id)" style="flex-shrink:0;cursor:pointer" />
2584
2584
  <span x-text="task.text" style="flex:1;font-size:13px;color:var(--ink-2)"></span>
2585
2585
  <button @click="deleteTodayTask(task.id)" style="background:none;border:none;color:var(--ink-3);cursor:pointer;font-size:14px;padding:0 2px;line-height:1" title="Remove">×</button>
@@ -2689,7 +2689,7 @@
2689
2689
  <template x-if="view === 'notes' && !selectedSession">
2690
2690
  <div style="display:flex;flex-direction:column;height:100%;overflow:hidden;">
2691
2691
  <div class="topbar">
2692
- <span class="topbar-title">Notes</span>
2692
+ <span class="topbar-title" @click="selectedNote=null;noteEditing=false;noteCreating=false" style="cursor:pointer" title="Back to Notes home">Notes</span>
2693
2693
  <span style="font-size:11px;color:var(--ink-3);padding:2px 8px;background:var(--canvas-2);border:1px solid var(--rule);border-radius:4px" title="These are your personal notes — Claude doesn't read or use them as context. They're only for you.">Your notepad · not Claude's memory</span>
2694
2694
  <input class="search-input" type="text" placeholder="Search notes…" x-model="noteSearch" style="font-size:12px;width:200px;padding:4px 10px" />
2695
2695
  <span style="font-size:11px;color:var(--ink-3)" x-show="personalNotes.length>0" x-text="personalNotes.length + ' notes'"></span>
@@ -2739,7 +2739,24 @@
2739
2739
  </div>
2740
2740
  </template>
2741
2741
  <template x-if="!personalNotesLoading && personalNotes.length === 0">
2742
- <div class="empty"><div class="empty-mark">✎</div>No notes yet. Create one or ask Claude to save one for you.</div>
2742
+ <div style="max-width:480px;margin:40px auto;padding:0 24px;text-align:center">
2743
+ <div style="font-size:28px;margin-bottom:12px">✎</div>
2744
+ <div style="font-size:15px;font-weight:600;margin-bottom:8px">Your personal notepad</div>
2745
+ <div style="font-size:13px;color:var(--ink-3);margin-bottom:24px;line-height:1.6">Notes are <strong>for you</strong>, not for Claude. Claude won't read them as context or memory — they're a place to capture what matters to you across your sessions.</div>
2746
+ <div style="background:var(--canvas-2);border:1px solid var(--rule);border-radius:8px;padding:16px;text-align:left;margin-bottom:20px">
2747
+ <div style="font-size:11px;font-weight:600;color:var(--ink-3);text-transform:uppercase;letter-spacing:.05em;margin-bottom:10px">Try saying to Claude</div>
2748
+ <div style="display:flex;flex-direction:column;gap:7px">
2749
+ <div style="font-size:12px"><span style="font-family:monospace;background:var(--canvas);border:1px solid var(--rule);padding:2px 6px;border-radius:4px">"Save this as a note"</span></div>
2750
+ <div style="font-size:12px"><span style="font-family:monospace;background:var(--canvas);border:1px solid var(--rule);padding:2px 6px;border-radius:4px">"Save this last output as a note"</span></div>
2751
+ <div style="font-size:12px"><span style="font-family:monospace;background:var(--canvas);border:1px solid var(--rule);padding:2px 6px;border-radius:4px">"Add this decision to my notes"</span></div>
2752
+ <div style="font-size:12px"><span style="font-family:monospace;background:var(--canvas);border:1px solid var(--rule);padding:2px 6px;border-radius:4px">"Save this as a TIL"</span></div>
2753
+ <div style="font-size:12px"><span style="font-family:monospace;background:var(--canvas);border:1px solid var(--rule);padding:2px 6px;border-radius:4px">"Show me my last note"</span></div>
2754
+ <div style="font-size:12px"><span style="font-family:monospace;background:var(--canvas);border:1px solid var(--rule);padding:2px 6px;border-radius:4px">"What notes do I have?"</span></div>
2755
+ <div style="font-size:12px"><span style="font-family:monospace;background:var(--canvas);border:1px solid var(--rule);padding:2px 6px;border-radius:4px">"Show me my notes"</span> <span style="font-size:11px;color:var(--ink-3)">→ http://localhost:3141</span></div>
2756
+ </div>
2757
+ </div>
2758
+ <div style="font-size:11px;color:var(--ink-3)">Or create a note manually with the <strong>+ New note</strong> button above.</div>
2759
+ </div>
2743
2760
  </template>
2744
2761
  <template x-if="!personalNotesLoading && personalNotes.length > 0">
2745
2762
  <div class="memory-layout">
@@ -2756,7 +2773,21 @@
2756
2773
  </div>
2757
2774
  <div class="resize-handle" @mousedown.prevent="startResize($event)"></div>
2758
2775
  <div class="memory-detail">
2759
- <template x-if="!selectedNote"><div class="memory-empty"><svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M5 12h14M12 5l7 7-7 7"/></svg>Select a note</div></template>
2776
+ <template x-if="!selectedNote">
2777
+ <div style="padding:24px;max-width:380px">
2778
+ <div style="font-size:13px;font-weight:600;margin-bottom:6px;color:var(--ink)">Your personal notepad</div>
2779
+ <div style="font-size:12px;color:var(--ink-3);margin-bottom:16px;line-height:1.6">Notes are <strong>for you</strong>, not for Claude. He won't read them as context — they're yours to capture, review and revisit.</div>
2780
+ <div style="font-size:11px;font-weight:600;color:var(--ink-3);text-transform:uppercase;letter-spacing:.05em;margin-bottom:8px">Ask Claude to save one</div>
2781
+ <div style="display:flex;flex-direction:column;gap:6px">
2782
+ <code style="font-size:11px;background:var(--canvas-2);border:1px solid var(--rule);padding:3px 7px;border-radius:4px;display:block">"Save this as a note"</code>
2783
+ <code style="font-size:11px;background:var(--canvas-2);border:1px solid var(--rule);padding:3px 7px;border-radius:4px;display:block">"Save this last output as a note"</code>
2784
+ <code style="font-size:11px;background:var(--canvas-2);border:1px solid var(--rule);padding:3px 7px;border-radius:4px;display:block">"Add this decision to my notes"</code>
2785
+ <code style="font-size:11px;background:var(--canvas-2);border:1px solid var(--rule);padding:3px 7px;border-radius:4px;display:block">"Save this as a TIL"</code>
2786
+ <code style="font-size:11px;background:var(--canvas-2);border:1px solid var(--rule);padding:3px 7px;border-radius:4px;display:block">"Show me my last note"</code>
2787
+ <code style="font-size:11px;background:var(--canvas-2);border:1px solid var(--rule);padding:3px 7px;border-radius:4px;display:block">"What notes do I have?"</code>
2788
+ </div>
2789
+ </div>
2790
+ </template>
2760
2791
  <template x-if="selectedNote && !noteEditing">
2761
2792
  <div>
2762
2793
  <div class="memory-detail-title" x-text="selectedNote.title"></div>
package/server.js CHANGED
@@ -18,6 +18,33 @@ function ensureDataDir() {
18
18
  }
19
19
  ensureDataDir();
20
20
 
21
+ // ─── Claude Code permissions (auto-allow notes/todos writes) ──────────────────
22
+ const CLAUDE_SETTINGS_PATH = path.join(os.homedir(), '.claude', 'settings.json');
23
+ const CLAUDE_HOME_PERMISSIONS = [
24
+ 'Write(~/.claude/claude-home/notes/*)',
25
+ 'Write(~/.claude/claude-home/todos/*)',
26
+ ];
27
+
28
+ function ensureClaudePermissions() {
29
+ try {
30
+ let settings = {};
31
+ if (fs.existsSync(CLAUDE_SETTINGS_PATH)) {
32
+ try { settings = JSON.parse(fs.readFileSync(CLAUDE_SETTINGS_PATH, 'utf8')); } catch { /* corrupt, overwrite */ }
33
+ }
34
+ if (!settings.permissions) settings.permissions = {};
35
+ if (!Array.isArray(settings.permissions.allow)) settings.permissions.allow = [];
36
+
37
+ const before = settings.permissions.allow.length;
38
+ for (const perm of CLAUDE_HOME_PERMISSIONS) {
39
+ if (!settings.permissions.allow.includes(perm)) settings.permissions.allow.push(perm);
40
+ }
41
+ if (settings.permissions.allow.length !== before) {
42
+ fs.writeFileSync(CLAUDE_SETTINGS_PATH, JSON.stringify(settings, null, 2) + '\n');
43
+ }
44
+ } catch { /* never crash the server over this */ }
45
+ }
46
+ ensureClaudePermissions();
47
+
21
48
  // Load .env manually (no dotenv dependency)
22
49
  try {
23
50
  const envPath = path.join(DATA_DIR, '.env');
@@ -2046,24 +2073,28 @@ function writeTodosFile(dateStr, data) {
2046
2073
  app.get('/api/today', (req, res) => {
2047
2074
  ensureTodosDir();
2048
2075
  const today = todayStr();
2049
- let data = readTodosFile(today);
2050
- if (!data) {
2051
- // Carry over undone tasks from most recent previous day
2052
- const files = fs.readdirSync(TODOS_DIR)
2053
- .filter(f => f.endsWith('.json') && f.slice(0, 10) < today)
2054
- .sort().reverse();
2055
- const carriedTasks = [];
2056
- if (files.length > 0) {
2057
- const prev = readTodosFile(files[0].slice(0, 10));
2058
- if (prev?.tasks) {
2059
- prev.tasks.filter(t => !t.done).forEach(t => {
2060
- carriedTasks.push({ ...t, carriedOver: true, done: false });
2061
- });
2062
- }
2063
- }
2064
- data = { date: today, context: '', tasks: carriedTasks };
2076
+ let data = readTodosFile(today) || { date: today, context: '', tasks: [] };
2077
+
2078
+ // Collect undone tasks from ALL previous days not already present in today's file
2079
+ const existingIds = new Set(data.tasks.map(t => t.id));
2080
+ const prevFiles = fs.readdirSync(TODOS_DIR)
2081
+ .filter(f => f.endsWith('.json') && f.slice(0, 10) < today)
2082
+ .sort();
2083
+ const toCarry = [];
2084
+ for (const f of prevFiles) {
2085
+ const prev = readTodosFile(f.slice(0, 10));
2086
+ if (!prev?.tasks) continue;
2087
+ prev.tasks.filter(t => !t.done && !existingIds.has(t.id)).forEach(t => {
2088
+ existingIds.add(t.id);
2089
+ toCarry.push({ ...t, carriedOver: true, done: false });
2090
+ });
2091
+ }
2092
+
2093
+ if (toCarry.length > 0) {
2094
+ data.tasks = [...toCarry, ...data.tasks];
2065
2095
  writeTodosFile(today, data);
2066
2096
  }
2097
+
2067
2098
  res.json(data);
2068
2099
  });
2069
2100