refactor: make spike a standalone script
- Remove spike command from extension registration - Add run-spike.sh wrapper script - Add npm script 'spike' to run the PoC - Spike can be run via: npm run spike or ./run-spike.sh
This commit is contained in:
parent
befb1fc98b
commit
4aab59947f
|
|
@ -24,7 +24,6 @@ import {
|
|||
} from "./config.js";
|
||||
import { type RawMessage, serializeMessage } from "./messages.js";
|
||||
import { type RemoteServer, startServer } from "./server.js";
|
||||
import { registerSpikeCommand } from "./spike.js";
|
||||
|
||||
// ── Extension entry point ────────────────────────────────────────────────────
|
||||
|
||||
|
|
@ -34,9 +33,6 @@ const QRCode = _require("qrcode") as {
|
|||
};
|
||||
|
||||
export default function remoteControl(pi: ExtensionAPI) {
|
||||
// Register spike command for Phase 0 PoC
|
||||
registerSpikeCommand(pi);
|
||||
|
||||
let server: RemoteServer | undefined;
|
||||
let pendingSyncTimer: ReturnType<typeof setTimeout> | undefined;
|
||||
|
||||
|
|
|
|||
|
|
@ -14,9 +14,8 @@
|
|||
import * as fs from "node:fs";
|
||||
import * as path from "node:path";
|
||||
import * as os from "node:os";
|
||||
import { spawn, execSync } from "node:child_process";
|
||||
import { execSync } from "node:child_process";
|
||||
import { WebSocketServer } from "ws";
|
||||
import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
|
||||
|
||||
const SPIKE_SESSION = "pi-spike";
|
||||
const WS_PORT = 7799;
|
||||
|
|
@ -113,23 +112,24 @@ function startWebSocketServer(fifoPath: string): { wss: WebSocketServer, cleanup
|
|||
}
|
||||
|
||||
/**
|
||||
* Attach to the tmux session in the current terminal
|
||||
* Print instructions for connecting to the session
|
||||
*/
|
||||
function attachToSession(sessionName: string): void {
|
||||
console.log(`[spike] Attaching to tmux session: ${sessionName}`);
|
||||
console.log(`[spike] To detach: Ctrl+B, then D`);
|
||||
console.log(`[spike] WebSocket available at: ws://127.0.0.1:${WS_PORT}/spike`);
|
||||
function printInstructions(sessionName: string): void {
|
||||
console.log("");
|
||||
console.log("=== Spike Server Running ===");
|
||||
console.log("");
|
||||
console.log("To attach to the tmux session (in another terminal):");
|
||||
console.log(` tmux attach -t ${sessionName}`);
|
||||
console.log("");
|
||||
console.log("WebSocket endpoint:");
|
||||
console.log(` ws://127.0.0.1:${WS_PORT}/spike`);
|
||||
console.log("");
|
||||
console.log("To test with the HTML client:");
|
||||
const clientPath = path.join(path.dirname(new URL(import.meta.url).pathname), "spike-client.html");
|
||||
console.log(` open ${clientPath}`);
|
||||
console.log("");
|
||||
console.log("To stop: Ctrl+C in this terminal");
|
||||
console.log("");
|
||||
|
||||
// Spawn tmux attach in the foreground
|
||||
// This will take over the terminal until the user detaches
|
||||
const attach = spawn("tmux", ["attach", "-t", sessionName], {
|
||||
stdio: "inherit",
|
||||
});
|
||||
|
||||
attach.on("exit", (code) => {
|
||||
console.log(`\n[spike] Detached from session (exit code: ${code})`);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -159,14 +159,15 @@ function cleanup(cleanupFn: (() => void) | null): void {
|
|||
/**
|
||||
* Main spike entry point
|
||||
*/
|
||||
export async function runSpike(_ctx: ExtensionContext): Promise<void> {
|
||||
export async function runSpike(): Promise<void> {
|
||||
console.log("=== Phase 0 Spike: tmux Stream PoC ===\n");
|
||||
|
||||
let cleanupFn: (() => void) | null = null;
|
||||
|
||||
// Setup cleanup handlers
|
||||
process.on("SIGINT", () => cleanup(cleanupFn));
|
||||
process.on("SIGTERM", () => cleanup(cleanupFn));
|
||||
const cleanupHandler = () => cleanup(cleanupFn);
|
||||
process.on("SIGINT", cleanupHandler);
|
||||
process.on("SIGTERM", cleanupHandler);
|
||||
|
||||
try {
|
||||
// Step 1: Create or reuse tmux session
|
||||
|
|
@ -186,8 +187,12 @@ export async function runSpike(_ctx: ExtensionContext): Promise<void> {
|
|||
// Give the server a moment to start
|
||||
await new Promise(resolve => setTimeout(resolve, 500));
|
||||
|
||||
// Step 4: Attach to session
|
||||
attachToSession(SPIKE_SESSION);
|
||||
// Step 4: Print instructions
|
||||
printInstructions(SPIKE_SESSION);
|
||||
|
||||
// Keep the process alive
|
||||
// User can Ctrl+C to stop
|
||||
await new Promise(() => {}); // Never resolves
|
||||
|
||||
} catch (err) {
|
||||
console.error("[spike] Error:", err);
|
||||
|
|
@ -195,14 +200,7 @@ export async function runSpike(_ctx: ExtensionContext): Promise<void> {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the spike command with pi
|
||||
*/
|
||||
export function registerSpikeCommand(pi: ExtensionAPI): void {
|
||||
pi.registerCommand("spike", {
|
||||
description: "Phase 0 Spike: Start tmux stream PoC (ws://127.0.0.1:7799/spike)",
|
||||
handler: async (_args, ctx) => {
|
||||
await runSpike(ctx);
|
||||
},
|
||||
});
|
||||
// Run if invoked directly
|
||||
if (import.meta.url === `file://${process.argv[1]}`) {
|
||||
runSpike();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
"@earendil-works/pi-tui": "*"
|
||||
},
|
||||
"scripts": {
|
||||
"spike": "./run-spike.sh",
|
||||
"lint": "biome check --write .",
|
||||
"lint:check": "biome check .",
|
||||
"prepare": "node .husky/install.mjs"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
#!/usr/bin/env bash
|
||||
# Phase 0 Spike runner
|
||||
# Transpiles and runs the spike PoC
|
||||
|
||||
set -e
|
||||
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
echo "=== Building spike.ts ==="
|
||||
npx --yes tsx extensions/remote-control/spike.ts
|
||||
Loading…
Reference in New Issue