@mrclrchtr/supi-extras 4.1.0 → 4.2.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 +2 -0
- package/node_modules/@mrclrchtr/supi-core/package.json +1 -1
- package/package.json +2 -2
- package/src/clone-session.ts +59 -0
- package/src/index.ts +2 -0
package/README.md
CHANGED
|
@@ -33,6 +33,7 @@ This package mixes a few commands and shortcuts with a few always-on UI tweaks.
|
|
|
33
33
|
- `/exit` — exit pi
|
|
34
34
|
- `/e` — alias for `/exit`
|
|
35
35
|
- `/clear` — start a new session (alias for `/new`)
|
|
36
|
+
- `/clone-session <session-id>` — clone a session into the current worktree and switch to it; autocomplete searches IDs and session names
|
|
36
37
|
- `/supi-stash` — browse, restore, copy, delete, or clear saved prompt drafts
|
|
37
38
|
|
|
38
39
|
## Shortcuts
|
|
@@ -83,6 +84,7 @@ That prevents git subprocesses from hanging while waiting for an interactive edi
|
|
|
83
84
|
## Source
|
|
84
85
|
|
|
85
86
|
- `src/aliases.ts` — command aliases
|
|
87
|
+
- `src/clone-session.ts` — cross-worktree session cloning by ID
|
|
86
88
|
- `src/prompt-stash.ts` — prompt stash shortcuts, persistence, and overlay
|
|
87
89
|
- `src/skill-shortcut.ts` — `$skill-name` expansion and autocomplete
|
|
88
90
|
- `src/tab-spinner.ts` — terminal tab-title spinner
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mrclrchtr/supi-extras",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.2.0",
|
|
4
4
|
"description": "SuPi extras — command aliases, skill shorthand, tab spinner, /supi-stash prompt stash with TUI overlay, and other small utilities",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
],
|
|
34
34
|
"dependencies": {
|
|
35
35
|
"clipboardy": "^5.3.1",
|
|
36
|
-
"@mrclrchtr/supi-core": "4.
|
|
36
|
+
"@mrclrchtr/supi-core": "4.2.0"
|
|
37
37
|
},
|
|
38
38
|
"bundledDependencies": [
|
|
39
39
|
"@mrclrchtr/supi-core"
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { type ExtensionAPI, SessionManager } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
|
|
3
|
+
export default function cloneSession(pi: ExtensionAPI) {
|
|
4
|
+
let completionSessions: Awaited<ReturnType<typeof SessionManager.listAll>> | undefined;
|
|
5
|
+
|
|
6
|
+
pi.registerCommand("clone-session", {
|
|
7
|
+
description: "Clone a session by ID into this worktree and switch to it",
|
|
8
|
+
getArgumentCompletions: async (prefix) => {
|
|
9
|
+
completionSessions ??= await SessionManager.listAll();
|
|
10
|
+
const query = prefix.trim().toLowerCase();
|
|
11
|
+
const matches = completionSessions.filter(
|
|
12
|
+
(session) => session.id.startsWith(query) || session.name?.toLowerCase().includes(query),
|
|
13
|
+
);
|
|
14
|
+
return matches.length > 0
|
|
15
|
+
? matches.map((session) => ({
|
|
16
|
+
value: session.id,
|
|
17
|
+
label: session.id,
|
|
18
|
+
description: [session.name, session.cwd].filter(Boolean).join(" — ") || undefined,
|
|
19
|
+
}))
|
|
20
|
+
: null;
|
|
21
|
+
},
|
|
22
|
+
handler: async (args, ctx) => {
|
|
23
|
+
const sessionId = args.trim();
|
|
24
|
+
if (!sessionId) {
|
|
25
|
+
ctx.ui.notify("Usage: /clone-session <session-id>", "warning");
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
let sessionFile: string;
|
|
30
|
+
try {
|
|
31
|
+
const sourceSession = (await SessionManager.listAll()).find(
|
|
32
|
+
(session) => session.id === sessionId,
|
|
33
|
+
);
|
|
34
|
+
if (!sourceSession) {
|
|
35
|
+
ctx.ui.notify(`Session not found: ${sessionId}`, "warning");
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const clonedSessionFile = SessionManager.forkFrom(
|
|
40
|
+
sourceSession.path,
|
|
41
|
+
ctx.cwd,
|
|
42
|
+
).getSessionFile();
|
|
43
|
+
if (!clonedSessionFile) throw new Error("cloned session was not persisted");
|
|
44
|
+
sessionFile = clonedSessionFile;
|
|
45
|
+
} catch (error) {
|
|
46
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
47
|
+
ctx.ui.notify(`Could not clone session: ${message}`, "error");
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const result = await ctx.switchSession(sessionFile, {
|
|
52
|
+
withSession: async (nextCtx) => {
|
|
53
|
+
nextCtx.ui.notify("Session cloned into this worktree", "info");
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
if (result.cancelled) ctx.ui.notify(`Session cloned to ${sessionFile}`, "info");
|
|
57
|
+
},
|
|
58
|
+
});
|
|
59
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import aliases from "./aliases.ts";
|
|
2
|
+
import cloneSession from "./clone-session.ts";
|
|
2
3
|
import copyPrompt from "./copy-prompt.ts";
|
|
3
4
|
import gitEditor from "./git-editor.ts";
|
|
4
5
|
import promptStash from "./prompt-stash.ts";
|
|
@@ -19,6 +20,7 @@ export default function (pi: Parameters<typeof tabSpinner>[0]) {
|
|
|
19
20
|
tabSpinner(pi);
|
|
20
21
|
promptStash(pi);
|
|
21
22
|
copyPrompt(pi);
|
|
23
|
+
cloneSession(pi);
|
|
22
24
|
gitEditor(pi);
|
|
23
25
|
aliases(pi);
|
|
24
26
|
skillShortcut(pi);
|