pneuma-skills 0.3.0 → 0.5.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 +1 -1
- package/bin/pneuma.ts +80 -1
- package/dist/assets/EditorPanel-CpYodpiX.js +31 -0
- package/dist/assets/TerminalPanel--aSGlXk2.js +39 -0
- package/dist/assets/TerminalPanel-6GBZ9nXN.css +32 -0
- package/dist/assets/index-DotlmM58.css +1 -0
- package/dist/assets/index-WbXrvKao.js +96 -0
- package/dist/index.html +2 -2
- package/package.json +14 -2
- package/server/file-watcher.ts +11 -1
- package/server/index.ts +288 -4
- package/server/session-types.ts +17 -2
- package/server/terminal-manager.ts +171 -0
- package/server/ws-bridge-types.ts +6 -1
- package/server/ws-bridge.ts +139 -2
- package/dist/assets/index-C3xcHnxM.css +0 -1
- package/dist/assets/index-MpOcQtLI.js +0 -90
package/README.md
CHANGED
|
@@ -126,7 +126,7 @@ pneuma-skills/
|
|
|
126
126
|
│ ├── StreamingText.tsx # Streaming response display
|
|
127
127
|
│ ├── ActivityIndicator.tsx # Thinking/tool progress indicator
|
|
128
128
|
│ ├── PermissionBanner.tsx # Tool permission approval UI
|
|
129
|
-
│ └──
|
|
129
|
+
│ └── TopBar.tsx # Tab navigation + connection status
|
|
130
130
|
├── skill/
|
|
131
131
|
│ └── doc/SKILL.md # Doc Mode skill prompt for Claude Code
|
|
132
132
|
├── docs/adr/ # Architecture Decision Records
|
package/bin/pneuma.ts
CHANGED
|
@@ -41,6 +41,22 @@ function saveSession(workspace: string, session: PersistedSession): void {
|
|
|
41
41
|
writeFileSync(join(dir, "session.json"), JSON.stringify(session, null, 2));
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
+
function loadHistory(workspace: string): unknown[] {
|
|
45
|
+
try {
|
|
46
|
+
const content = readFileSync(join(workspace, ".pneuma", "history.json"), "utf-8");
|
|
47
|
+
const data = JSON.parse(content);
|
|
48
|
+
return Array.isArray(data) ? data : [];
|
|
49
|
+
} catch {
|
|
50
|
+
return [];
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function saveHistory(workspace: string, history: unknown[]): void {
|
|
55
|
+
const dir = join(workspace, ".pneuma");
|
|
56
|
+
mkdirSync(dir, { recursive: true });
|
|
57
|
+
writeFileSync(join(dir, "history.json"), JSON.stringify(history));
|
|
58
|
+
}
|
|
59
|
+
|
|
44
60
|
// ── CLI arg parsing ──────────────────────────────────────────────────────────
|
|
45
61
|
|
|
46
62
|
function parseArgs(argv: string[]) {
|
|
@@ -78,7 +94,29 @@ function ask(question: string): Promise<string> {
|
|
|
78
94
|
|
|
79
95
|
// ── Main ─────────────────────────────────────────────────────────────────────
|
|
80
96
|
|
|
97
|
+
function checkBunVersion() {
|
|
98
|
+
const MIN_BUN = "1.3.5"; // Required for Bun.spawn terminal (PTY) support
|
|
99
|
+
const current = typeof Bun !== "undefined" ? Bun.version : null;
|
|
100
|
+
if (!current) {
|
|
101
|
+
console.warn("[pneuma] Warning: Not running under Bun. Pneuma requires Bun >= " + MIN_BUN);
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
const [curMajor, curMinor, curPatch] = current.split(".").map(Number);
|
|
105
|
+
const [minMajor, minMinor, minPatch] = MIN_BUN.split(".").map(Number);
|
|
106
|
+
const ok =
|
|
107
|
+
curMajor > minMajor ||
|
|
108
|
+
(curMajor === minMajor && curMinor > minMinor) ||
|
|
109
|
+
(curMajor === minMajor && curMinor === minMinor && curPatch >= minPatch);
|
|
110
|
+
if (!ok) {
|
|
111
|
+
console.warn(
|
|
112
|
+
`[pneuma] Warning: Bun ${current} detected, but >= ${MIN_BUN} is required.` +
|
|
113
|
+
` Terminal features may not work. Run \`bun upgrade\` to update.`
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
81
118
|
async function main() {
|
|
119
|
+
checkBunVersion();
|
|
82
120
|
const { mode, workspace, port, noOpen } = parseArgs(process.argv);
|
|
83
121
|
|
|
84
122
|
if (!mode || mode !== "doc") {
|
|
@@ -186,8 +224,42 @@ async function main() {
|
|
|
186
224
|
|
|
187
225
|
console.log(`[pneuma] CLI session started: ${session.sessionId}`);
|
|
188
226
|
|
|
189
|
-
//
|
|
227
|
+
// Auto-greeting for fresh sessions — sends a hidden prompt so Claude greets the user
|
|
228
|
+
if (!resuming) {
|
|
229
|
+
const greeting = "The user just opened the Pneuma document editor workspace. Briefly greet them and let them know you're ready to help edit and create documents. Keep it to 1-2 sentences.";
|
|
230
|
+
wsBridge.injectGreeting(session.sessionId, greeting);
|
|
231
|
+
console.log("[pneuma] Sent auto-greeting for fresh session");
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// Load persisted message history into WsBridge
|
|
235
|
+
const savedHistory = loadHistory(workspace);
|
|
236
|
+
if (savedHistory.length > 0) {
|
|
237
|
+
wsBridge.loadMessageHistory(session.sessionId, savedHistory as any);
|
|
238
|
+
console.log(`[pneuma] Restored ${savedHistory.length} messages from history`);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// Periodically persist message history (debounced — every 5s)
|
|
242
|
+
const historyInterval = setInterval(() => {
|
|
243
|
+
const history = wsBridge.getMessageHistory(session.sessionId);
|
|
244
|
+
if (history.length > 0) {
|
|
245
|
+
saveHistory(workspace, history);
|
|
246
|
+
}
|
|
247
|
+
}, 5_000);
|
|
248
|
+
|
|
249
|
+
// Handle CLI exit: surface errors + clear stale resume state
|
|
190
250
|
launcher.onSessionExited((exitedId, exitCode) => {
|
|
251
|
+
// Broadcast CLI errors to browser
|
|
252
|
+
if (exitCode !== 0 && exitCode !== 143 /* SIGTERM = normal shutdown */) {
|
|
253
|
+
let errorMsg: string;
|
|
254
|
+
if (exitCode === 127) {
|
|
255
|
+
errorMsg = "Claude Code CLI not found. Please install it: https://docs.anthropic.com/claude-code";
|
|
256
|
+
} else {
|
|
257
|
+
errorMsg = `Claude Code exited unexpectedly (code ${exitCode}). Check CLI installation and subscription status.`;
|
|
258
|
+
}
|
|
259
|
+
wsBridge.broadcastToSession(exitedId, { type: "error", message: errorMsg });
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// If resume fails (CLI exits quickly), clear cliSessionId from persistence
|
|
191
263
|
if (exitedId === session.sessionId && resuming) {
|
|
192
264
|
const info = launcher.getSession(exitedId);
|
|
193
265
|
if (info && !info.cliSessionId) {
|
|
@@ -261,6 +333,13 @@ async function main() {
|
|
|
261
333
|
// Graceful shutdown
|
|
262
334
|
const shutdown = async () => {
|
|
263
335
|
console.log("\n[pneuma] Shutting down...");
|
|
336
|
+
clearInterval(historyInterval);
|
|
337
|
+
// Final history save
|
|
338
|
+
const history = wsBridge.getMessageHistory(session.sessionId);
|
|
339
|
+
if (history.length > 0) {
|
|
340
|
+
saveHistory(workspace, history);
|
|
341
|
+
console.log(`[pneuma] Saved ${history.length} messages to history`);
|
|
342
|
+
}
|
|
264
343
|
viteProc?.kill();
|
|
265
344
|
await launcher.killAll();
|
|
266
345
|
server.stop(true);
|