@vitorcen/context-resume 1.0.1 → 1.0.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/dist/adapters/index.js +3 -2
- package/dist/index.js +4 -1
- package/dist/ui/app.js +37 -13
- package/package.json +1 -1
package/dist/adapters/index.js
CHANGED
|
@@ -4,10 +4,11 @@ import { glob } from 'glob';
|
|
|
4
4
|
import os from 'os';
|
|
5
5
|
// --- Claude Adapter ---
|
|
6
6
|
function getClaudeEncodedPath(projectPath) {
|
|
7
|
-
// Claude encodes paths by replacing
|
|
7
|
+
// Claude encodes paths by replacing /, ., and _ with -
|
|
8
8
|
// e.g. /home/user/project -> -home-user-project
|
|
9
9
|
// e.g. /path/v1.0 -> -path-v1-0
|
|
10
|
-
|
|
10
|
+
// e.g. /home/work_ro -> -home-work-ro
|
|
11
|
+
return projectPath.replace(/[\/\._]/g, '-');
|
|
11
12
|
}
|
|
12
13
|
export async function getClaudeSessions(cwd, limit = 10) {
|
|
13
14
|
const homeDir = os.homedir();
|
package/dist/index.js
CHANGED
|
@@ -3,11 +3,14 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
3
3
|
import { Command } from 'commander';
|
|
4
4
|
import { render } from 'ink';
|
|
5
5
|
import App from './ui/app.js';
|
|
6
|
+
import { createRequire } from 'module';
|
|
7
|
+
const require = createRequire(import.meta.url);
|
|
8
|
+
const { version } = require('../package.json');
|
|
6
9
|
const program = new Command();
|
|
7
10
|
program
|
|
8
11
|
.name('context')
|
|
9
12
|
.description('Context Resume CLI')
|
|
10
|
-
.version(
|
|
13
|
+
.version(version, '-v, --version');
|
|
11
14
|
program
|
|
12
15
|
.option('-n, --number <count>', 'Number of sessions to show per source (claude/codex)', '10')
|
|
13
16
|
.action(async (options) => {
|
package/dist/ui/app.js
CHANGED
|
@@ -3,6 +3,22 @@ import { useState, useEffect } from 'react';
|
|
|
3
3
|
import { Box, Text, useInput, useApp } from 'ink';
|
|
4
4
|
import SelectInput from 'ink-select-input';
|
|
5
5
|
import { getClaudeSessions, getCodexSessions } from '../adapters/index.js';
|
|
6
|
+
import stringWidth from 'string-width';
|
|
7
|
+
// Truncate by display width (handles CJK characters correctly)
|
|
8
|
+
const truncateByWidth = (str, maxWidth) => {
|
|
9
|
+
if (stringWidth(str) <= maxWidth)
|
|
10
|
+
return str;
|
|
11
|
+
let result = '';
|
|
12
|
+
let width = 0;
|
|
13
|
+
for (const char of str) {
|
|
14
|
+
const charWidth = stringWidth(char);
|
|
15
|
+
if (width + charWidth > maxWidth)
|
|
16
|
+
break;
|
|
17
|
+
result += char;
|
|
18
|
+
width += charWidth;
|
|
19
|
+
}
|
|
20
|
+
return result + '...';
|
|
21
|
+
};
|
|
6
22
|
const App = ({ cwd, limit = 10, onSubmit }) => {
|
|
7
23
|
const [claudeItems, setClaudeItems] = useState([]);
|
|
8
24
|
const [codexItems, setCodexItems] = useState([]);
|
|
@@ -33,16 +49,24 @@ const App = ({ cwd, limit = 10, onSubmit }) => {
|
|
|
33
49
|
]);
|
|
34
50
|
// Sort by timestamp desc
|
|
35
51
|
const sortFn = (a, b) => b.timestamp - a.timestamp;
|
|
36
|
-
const cItems = claudeSessions.sort(sortFn).map(s =>
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
52
|
+
const cItems = claudeSessions.sort(sortFn).map(s => {
|
|
53
|
+
const title = s.title.replace(/\n/g, ' ').trim();
|
|
54
|
+
const truncatedTitle = truncateByWidth(title, 45);
|
|
55
|
+
return {
|
|
56
|
+
label: `${truncatedTitle} (${new Date(s.timestamp).toLocaleDateString()})`,
|
|
57
|
+
value: s.id,
|
|
58
|
+
session: s
|
|
59
|
+
};
|
|
60
|
+
});
|
|
61
|
+
const cxItems = codexSessions.sort(sortFn).map(s => {
|
|
62
|
+
const title = s.title.replace(/\n/g, ' ').trim();
|
|
63
|
+
const truncatedTitle = truncateByWidth(title, 45);
|
|
64
|
+
return {
|
|
65
|
+
label: `${truncatedTitle} (${new Date(s.timestamp).toLocaleDateString()})`,
|
|
66
|
+
value: s.id,
|
|
67
|
+
session: s
|
|
68
|
+
};
|
|
69
|
+
});
|
|
46
70
|
setClaudeItems(cItems);
|
|
47
71
|
setCodexItems(cxItems);
|
|
48
72
|
if (cItems.length > 0)
|
|
@@ -66,12 +90,12 @@ const App = ({ cwd, limit = 10, onSubmit }) => {
|
|
|
66
90
|
const currentItem = activePanel === 'claude' ? activeClaudeItem : activeCodexItem;
|
|
67
91
|
// Filter out empty prompts
|
|
68
92
|
const prompts = (currentItem?.session.userPrompts || []).filter(p => p && p.trim().length > 0);
|
|
69
|
-
// Truncate prompts logic
|
|
93
|
+
// Truncate prompts logic (~60 display width: ~120 ASCII chars or ~60 CJK chars)
|
|
70
94
|
const previewText = prompts.map((p, i) => {
|
|
71
95
|
const clean = p.replace(/\n/g, ' ').trim();
|
|
72
|
-
const truncated = clean
|
|
96
|
+
const truncated = truncateByWidth(clean, 120);
|
|
73
97
|
return `${i + 1}. ${truncated}`;
|
|
74
98
|
}).join('\n');
|
|
75
|
-
return (_jsxs(Box, { flexDirection: "column",
|
|
99
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { borderStyle: "single", flexDirection: "column", paddingX: 1, children: [_jsx(Text, { bold: true, underline: true, children: "Preview (User Prompts)" }), _jsx(Text, { children: previewText || 'Select a session to view prompts' })] }), _jsxs(Box, { flexDirection: "row", minHeight: 20, children: [_jsxs(Box, { width: "50%", borderStyle: activePanel === 'claude' ? 'double' : 'single', flexDirection: "column", borderColor: activePanel === 'claude' ? 'green' : 'white', children: [_jsx(Text, { bold: true, underline: true, color: activePanel === 'claude' ? 'green' : 'white', children: "Claude Sessions" }), claudeItems.length === 0 ? (_jsx(Text, { children: "No sessions found." })) : (_jsx(SelectInput, { items: claudeItems, onSelect: handleSelect, onHighlight: handleHighlightClaude, isFocused: activePanel === 'claude' }))] }), _jsxs(Box, { width: "50%", borderStyle: activePanel === 'codex' ? 'double' : 'single', flexDirection: "column", borderColor: activePanel === 'codex' ? 'green' : 'white', children: [_jsx(Text, { bold: true, underline: true, color: activePanel === 'codex' ? 'green' : 'white', children: "Codex Sessions" }), codexItems.length === 0 ? (_jsx(Text, { children: "No sessions found." })) : (_jsx(SelectInput, { items: codexItems, onSelect: handleSelect, onHighlight: handleHighlightCodex, isFocused: activePanel === 'codex' }))] })] }), _jsx(Box, { marginTop: 0, children: _jsx(Text, { dimColor: true, children: "TAB/Arrows: Switch Panel | ENTER: Select | ESC: Exit" }) })] }));
|
|
76
100
|
};
|
|
77
101
|
export default App;
|
package/package.json
CHANGED