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";
|
} from "./config.js";
|
||||||
import { type RawMessage, serializeMessage } from "./messages.js";
|
import { type RawMessage, serializeMessage } from "./messages.js";
|
||||||
import { type RemoteServer, startServer } from "./server.js";
|
import { type RemoteServer, startServer } from "./server.js";
|
||||||
import { registerSpikeCommand } from "./spike.js";
|
|
||||||
|
|
||||||
// ── Extension entry point ────────────────────────────────────────────────────
|
// ── Extension entry point ────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
|
@ -34,9 +33,6 @@ const QRCode = _require("qrcode") as {
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function remoteControl(pi: ExtensionAPI) {
|
export default function remoteControl(pi: ExtensionAPI) {
|
||||||
// Register spike command for Phase 0 PoC
|
|
||||||
registerSpikeCommand(pi);
|
|
||||||
|
|
||||||
let server: RemoteServer | undefined;
|
let server: RemoteServer | undefined;
|
||||||
let pendingSyncTimer: ReturnType<typeof setTimeout> | undefined;
|
let pendingSyncTimer: ReturnType<typeof setTimeout> | undefined;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,9 +14,8 @@
|
||||||
import * as fs from "node:fs";
|
import * as fs from "node:fs";
|
||||||
import * as path from "node:path";
|
import * as path from "node:path";
|
||||||
import * as os from "node:os";
|
import * as os from "node:os";
|
||||||
import { spawn, execSync } from "node:child_process";
|
import { execSync } from "node:child_process";
|
||||||
import { WebSocketServer } from "ws";
|
import { WebSocketServer } from "ws";
|
||||||
import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
||||||
|
|
||||||
const SPIKE_SESSION = "pi-spike";
|
const SPIKE_SESSION = "pi-spike";
|
||||||
const WS_PORT = 7799;
|
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 {
|
function printInstructions(sessionName: string): void {
|
||||||
console.log(`[spike] Attaching to tmux session: ${sessionName}`);
|
console.log("");
|
||||||
console.log(`[spike] To detach: Ctrl+B, then D`);
|
console.log("=== Spike Server Running ===");
|
||||||
console.log(`[spike] WebSocket available at: ws://127.0.0.1:${WS_PORT}/spike`);
|
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("");
|
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
|
* 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");
|
console.log("=== Phase 0 Spike: tmux Stream PoC ===\n");
|
||||||
|
|
||||||
let cleanupFn: (() => void) | null = null;
|
let cleanupFn: (() => void) | null = null;
|
||||||
|
|
||||||
// Setup cleanup handlers
|
// Setup cleanup handlers
|
||||||
process.on("SIGINT", () => cleanup(cleanupFn));
|
const cleanupHandler = () => cleanup(cleanupFn);
|
||||||
process.on("SIGTERM", () => cleanup(cleanupFn));
|
process.on("SIGINT", cleanupHandler);
|
||||||
|
process.on("SIGTERM", cleanupHandler);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Step 1: Create or reuse tmux session
|
// 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
|
// Give the server a moment to start
|
||||||
await new Promise(resolve => setTimeout(resolve, 500));
|
await new Promise(resolve => setTimeout(resolve, 500));
|
||||||
|
|
||||||
// Step 4: Attach to session
|
// Step 4: Print instructions
|
||||||
attachToSession(SPIKE_SESSION);
|
printInstructions(SPIKE_SESSION);
|
||||||
|
|
||||||
|
// Keep the process alive
|
||||||
|
// User can Ctrl+C to stop
|
||||||
|
await new Promise(() => {}); // Never resolves
|
||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("[spike] Error:", err);
|
console.error("[spike] Error:", err);
|
||||||
|
|
@ -195,14 +200,7 @@ export async function runSpike(_ctx: ExtensionContext): Promise<void> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// Run if invoked directly
|
||||||
* Register the spike command with pi
|
if (import.meta.url === `file://${process.argv[1]}`) {
|
||||||
*/
|
runSpike();
|
||||||
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);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@
|
||||||
"@earendil-works/pi-tui": "*"
|
"@earendil-works/pi-tui": "*"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
"spike": "./run-spike.sh",
|
||||||
"lint": "biome check --write .",
|
"lint": "biome check --write .",
|
||||||
"lint:check": "biome check .",
|
"lint:check": "biome check .",
|
||||||
"prepare": "node .husky/install.mjs"
|
"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