feat: free-form sessions, rename/end from the panel, live Claude Context (0.2.0)
- Sessions no longer need a project folder: any name works and starts in DEVDESK_DEFAULT_DIR unless it matches a project; `devdesk new NAME [PROJECT]`. - Rename (✎) and end/forget (×) sessions from the Sessions panel, plus `devdesk rename`. The browser runs them as `devdesk attach --new|--rename|--end` through ttyd. Renames keep the running Claude and its recorded conversation: the hook, the run-wrapper and the statusline ask tmux for the current name. - Claude Context panel is live: devdesk-statusline snapshots model, context-window use, cost and edits per session, which --list reports; Claude's footer gets a one-line summary. The panel now sits under Sessions. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+16
-4
@@ -53,12 +53,25 @@ export function tokenUrl(location) {
|
||||
return `${location.protocol}//${location.host}${basePath(location)}token`;
|
||||
}
|
||||
|
||||
export function wsUrl(location, arg) {
|
||||
// ttyd --url-arg appends each ?arg= to the command line: `devdesk attach <args…>`.
|
||||
export function wsUrl(location, args) {
|
||||
const scheme = location.protocol === 'https:' ? 'wss:' : 'ws:';
|
||||
const query = arg ? `?arg=${encodeURIComponent(arg)}` : '';
|
||||
const list = Array.isArray(args) ? args : args ? [args] : [];
|
||||
const query = list.length ? `?${list.map((a) => `arg=${encodeURIComponent(a)}`).join('&')}` : '';
|
||||
return `${scheme}//${location.host}${basePath(location)}ws${query}`;
|
||||
}
|
||||
|
||||
// Session names are [A-Za-z0-9_-]; turn free text ("PBS upgrade!") into one ("PBS-upgrade").
|
||||
export function slugify(text) {
|
||||
return String(text || '').trim().replace(/[^A-Za-z0-9_-]+/g, '-')
|
||||
.replace(/^[-_]+/, '').replace(/-+$/, '').slice(0, 64);
|
||||
}
|
||||
|
||||
export function stripAnsi(text) {
|
||||
// eslint-disable-next-line no-control-regex
|
||||
return text.replace(/\x1b\[[0-9;?]*[ -/]*[@-~]/g, '').replace(/\x1b\][^\x07\x1b]*(\x07|\x1b\\)/g, '');
|
||||
}
|
||||
|
||||
export function sessionFromSearch(search) {
|
||||
const value = new URLSearchParams(search).get('arg');
|
||||
return value && SESSION_RE.test(value) ? value : null;
|
||||
@@ -74,8 +87,7 @@ export function parseTitle(title) {
|
||||
// Output of `devdesk attach --list` arrives through a pty: CRLF line endings and
|
||||
// possibly split across frames. Pull the JSON object out of the joined text.
|
||||
export function parseListOutput(raw) {
|
||||
// eslint-disable-next-line no-control-regex
|
||||
const text = raw.replace(/\x1b\[[0-9;?]*[ -/]*[@-~]/g, ''); // tools may colorize on a tty
|
||||
const text = stripAnsi(raw); // tools may colorize on a tty
|
||||
const start = text.indexOf('{');
|
||||
const end = text.lastIndexOf('}');
|
||||
if (start < 0 || end < start) throw new Error('no session list in output');
|
||||
|
||||
Reference in New Issue
Block a user