claude-home 1.4.0 → 1.4.2
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 +1 -1
- package/public/index.html +24 -13
- package/server.js +9 -2
package/package.json
CHANGED
package/public/index.html
CHANGED
|
@@ -343,6 +343,9 @@
|
|
|
343
343
|
|
|
344
344
|
.session-resume-btn:hover { background: var(--red); }
|
|
345
345
|
.session-resume-btn.copied { background: var(--green) !important; }
|
|
346
|
+
.session-resume-btn:disabled { opacity: 0.35; cursor: not-allowed; background: var(--surface-2); color: var(--ink-3); }
|
|
347
|
+
.session-resume-btn:disabled:hover { background: var(--surface-2); }
|
|
348
|
+
.session-row:hover .session-resume-btn:disabled { opacity: 0.4; }
|
|
346
349
|
|
|
347
350
|
/* ── Chat view ────────────────────────────────────────── */
|
|
348
351
|
.chat-header {
|
|
@@ -1700,7 +1703,7 @@
|
|
|
1700
1703
|
</template>
|
|
1701
1704
|
<span x-text="formatDate(sessions[0].modified)"></span>
|
|
1702
1705
|
<span x-text="sessions[0].messageCount + ' msgs'"></span>
|
|
1703
|
-
<button class="btn btn-primary btn-sm" style="margin-left:auto" :id="'resume-db'" @click.stop="resumeSession(sessions[0].sessionId,'resume-db')">Resume →</button>
|
|
1706
|
+
<button class="btn btn-primary btn-sm" style="margin-left:auto" :id="'resume-db'" :disabled="!sessions[0].resumable" :title="!sessions[0].resumable ? 'Archivo de sesión eliminado — no se puede retomar' : 'Copiar comando para retomar esta sesión'" @click.stop="sessions[0].resumable && resumeSession(sessions[0].sessionId,'resume-db', sessions[0].projectPath)">Resume →</button>
|
|
1704
1707
|
</div>
|
|
1705
1708
|
</div>
|
|
1706
1709
|
</template>
|
|
@@ -1864,7 +1867,7 @@
|
|
|
1864
1867
|
</div>
|
|
1865
1868
|
</div>
|
|
1866
1869
|
<div class="session-right">
|
|
1867
|
-
<button class="session-resume-btn" :id="'resume-' + s.sessionId" @click.stop="resumeSession(s.sessionId, 'resume-' + s.sessionId)">Resume →</button>
|
|
1870
|
+
<button class="session-resume-btn" :id="'resume-' + s.sessionId" :disabled="!s.resumable" :title="!s.resumable ? 'Archivo de sesión eliminado — no se puede retomar' : 'Copiar comando para retomar esta sesión'" @click.stop="s.resumable && resumeSession(s.sessionId, 'resume-' + s.sessionId, s.projectPath)">Resume →</button>
|
|
1868
1871
|
</div>
|
|
1869
1872
|
</div>
|
|
1870
1873
|
</template>
|
|
@@ -1981,7 +1984,7 @@
|
|
|
1981
1984
|
</div>
|
|
1982
1985
|
<button class="btn btn-sm" style="background:var(--red-dim,#3a1a1a);color:var(--red);border:1px solid var(--red)" @click="deleteSession()" x-show="!deletingSession">Delete</button>
|
|
1983
1986
|
<span x-show="deletingSession" style="font-size:12px;color:var(--ink-3)">Deleting…</span>
|
|
1984
|
-
<button class="btn btn-primary btn-sm" id="resume-detail" @click="resumeSession(selectedSession.sessionId, 'resume-detail')">
|
|
1987
|
+
<button class="btn btn-primary btn-sm" id="resume-detail" :disabled="!sessionDetail?.resumable" :title="!sessionDetail?.resumable ? 'Archivo de sesión eliminado — no se puede retomar' : 'Copiar comando para retomar esta sesión'" @click="sessionDetail?.resumable && resumeSession(selectedSession.sessionId, 'resume-detail', selectedSession.projectPath)">
|
|
1985
1988
|
Resume →
|
|
1986
1989
|
</button>
|
|
1987
1990
|
<span x-show="exportMsg" x-text="exportMsg" style="font-size:12px;color:var(--green)" x-transition></span>
|
|
@@ -3638,8 +3641,10 @@
|
|
|
3638
3641
|
<input class="perm-add-input" style="width:100%" x-model="ruleBuilder.specifier"
|
|
3639
3642
|
placeholder="npm run * / git commit * / * --help *"
|
|
3640
3643
|
@keydown.enter="ruleBuilderAdd()" />
|
|
3641
|
-
<div style="font-size:11px;color:var(--ink-3);margin-top:5px">
|
|
3642
|
-
<code>Bash(ls *)</code> coincide con <code>ls -la</code> pero no con <code>lsof</code> — el espacio antes de <code>*</code> actúa como límite de palabra
|
|
3644
|
+
<div style="font-size:11px;color:var(--ink-3);margin-top:5px;display:flex;flex-direction:column;gap:4px">
|
|
3645
|
+
<span><code>Bash(ls *)</code> coincide con <code>ls -la</code> pero no con <code>lsof</code> — el espacio antes de <code>*</code> actúa como límite de palabra.</span>
|
|
3646
|
+
<span>⚠️ Comandos con <code>&&</code>, <code>|</code> o redirecciones pueden ser bloqueados por la detección automática de patrones peligrosos, aunque estén en allow.</span>
|
|
3647
|
+
<span>💡 Para comandos de una sola herramienta usa el prefijo sin encadenar: <code>npm publish *</code> en lugar de <code>cd /dir && npm publish</code>.</span>
|
|
3643
3648
|
</div>
|
|
3644
3649
|
</div>
|
|
3645
3650
|
</template>
|
|
@@ -4072,15 +4077,21 @@
|
|
|
4072
4077
|
await this.openSession(s);
|
|
4073
4078
|
},
|
|
4074
4079
|
|
|
4075
|
-
async resumeSession(sessionId, btnId) {
|
|
4076
|
-
const cmd =
|
|
4077
|
-
|
|
4080
|
+
async resumeSession(sessionId, btnId, projectPath) {
|
|
4081
|
+
const cmd = projectPath
|
|
4082
|
+
? `cd "${projectPath}" && claude -r ${sessionId}`
|
|
4083
|
+
: `claude -r ${sessionId}`;
|
|
4078
4084
|
const btn = document.getElementById(btnId);
|
|
4079
|
-
|
|
4080
|
-
|
|
4081
|
-
btn
|
|
4082
|
-
|
|
4083
|
-
|
|
4085
|
+
try {
|
|
4086
|
+
await navigator.clipboard.writeText(cmd);
|
|
4087
|
+
if (btn) {
|
|
4088
|
+
const orig = btn.textContent;
|
|
4089
|
+
btn.textContent = 'Copied!';
|
|
4090
|
+
btn.classList.add('btn-copied', 'copied');
|
|
4091
|
+
setTimeout(() => { btn.textContent = orig; btn.classList.remove('btn-copied', 'copied'); }, 2000);
|
|
4092
|
+
}
|
|
4093
|
+
} catch {
|
|
4094
|
+
prompt('Copia este comando:', cmd);
|
|
4084
4095
|
}
|
|
4085
4096
|
},
|
|
4086
4097
|
|
package/server.js
CHANGED
|
@@ -272,7 +272,13 @@ async function loadSessionIndex(dirName) {
|
|
|
272
272
|
};
|
|
273
273
|
}));
|
|
274
274
|
|
|
275
|
-
const allEntries = [
|
|
275
|
+
const allEntries = [
|
|
276
|
+
...indexedEntries.map(e => {
|
|
277
|
+
const exists = fs.existsSync(e.fullPath || path.join(dir, `${e.sessionId}.jsonl`));
|
|
278
|
+
return { ...e, orphaned: !exists, resumable: exists };
|
|
279
|
+
}),
|
|
280
|
+
...unindexedEntries.map(e => ({ ...e, resumable: true })),
|
|
281
|
+
];
|
|
276
282
|
indexCache.set(dirName, { indexMtime, dirMtime: dirStat, entries: allEntries });
|
|
277
283
|
return allEntries;
|
|
278
284
|
}
|
|
@@ -438,6 +444,7 @@ app.get('/api/sessions/:project/:sessionId', async (req, res) => {
|
|
|
438
444
|
const { project, sessionId } = req.params;
|
|
439
445
|
const filePath = path.join(PROJECTS_DIR, project, `${sessionId}.jsonl`);
|
|
440
446
|
try {
|
|
447
|
+
const resumable = fs.existsSync(filePath);
|
|
441
448
|
const messages = await parseJsonl(filePath);
|
|
442
449
|
const tokens = aggregateTokens(messages);
|
|
443
450
|
const models = [...new Set(
|
|
@@ -449,7 +456,7 @@ app.get('/api/sessions/:project/:sessionId', async (req, res) => {
|
|
|
449
456
|
const cost = calculateCost(tokens, primaryModel);
|
|
450
457
|
const savings = cacheSavings(tokens, primaryModel);
|
|
451
458
|
const carbon = calculateCarbon(tokens, primaryModel);
|
|
452
|
-
res.json({ sessionId, tokens, models, cost, savings, carbon, messages });
|
|
459
|
+
res.json({ sessionId, tokens, models, cost, savings, carbon, messages, resumable });
|
|
453
460
|
} catch (e) {
|
|
454
461
|
res.status(500).json({ error: e.message });
|
|
455
462
|
}
|