@stackwright-pro/raft 1.0.0-alpha.31 → 1.0.0-alpha.33
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 +22 -0
- package/dist/index.js +5 -7
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -18,6 +18,8 @@ This provides the `raft-puppy` binary (and `code-puppy` alias) with two fixes re
|
|
|
18
18
|
Source: https://github.com/Per-Aspera-LLC/stackwright-puppy
|
|
19
19
|
Upstream: https://github.com/mpfaffenberger/code_puppy (MIT)
|
|
20
20
|
|
|
21
|
+
No specific credentials or API keys are required by the raft itself — see [Authentication](#authentication) below.
|
|
22
|
+
|
|
21
23
|
## Usage
|
|
22
24
|
|
|
23
25
|
```bash
|
|
@@ -32,6 +34,26 @@ npx @stackwright-pro/raft [options]
|
|
|
32
34
|
| `--verbose` | Enable verbose logging |
|
|
33
35
|
| `--help`, `-h` | Show help |
|
|
34
36
|
|
|
37
|
+
## Authentication
|
|
38
|
+
|
|
39
|
+
The raft does **not** check for API keys or credentials — that is `raft-puppy`/`code-puppy`'s responsibility. Any auth mechanism supported by your binary works:
|
|
40
|
+
|
|
41
|
+
- `claude auth login` — OAuth browser login (interactive sessions)
|
|
42
|
+
- `ANTHROPIC_API_KEY` — Direct Anthropic API key
|
|
43
|
+
- AWS Bedrock, Google Vertex, Ollama, custom inference — configured via your `raft-puppy`/`code-puppy` setup
|
|
44
|
+
|
|
45
|
+
If your binary can talk to a model, the raft will launch successfully.
|
|
46
|
+
|
|
47
|
+
## Air-gapped & custom deployments
|
|
48
|
+
|
|
49
|
+
To skip the binary version pre-flight check entirely (useful when running a custom or pinned binary that reports a non-standard version string):
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
STACKWRIGHT_SKIP_PREFLIGHT=true npx @stackwright-pro/raft
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
This bypasses all raft-level validation and spawns your binary directly. The binary itself is still responsible for validating its own environment.
|
|
56
|
+
|
|
35
57
|
## Binary resolution
|
|
36
58
|
|
|
37
59
|
`raft` searches for the Python binary in this order:
|
package/dist/index.js
CHANGED
|
@@ -291,12 +291,10 @@ function semverGte(a, b) {
|
|
|
291
291
|
if (aMin !== bMin) return aMin > bMin;
|
|
292
292
|
return aPatch >= bPatch;
|
|
293
293
|
}
|
|
294
|
-
function
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
"ANTHROPIC_API_KEY is not set or is empty.\n\nSet it in your current shell:\n export ANTHROPIC_API_KEY=sk-ant-...\n\nOr add it to your ~/.bashrc / ~/.zshrc to persist across sessions.\nGet your key at: https://console.anthropic.com/settings/keys"
|
|
299
|
-
);
|
|
294
|
+
function validateBinaryVersion(binaryPath) {
|
|
295
|
+
if (process.env["STACKWRIGHT_SKIP_PREFLIGHT"] === "true") {
|
|
296
|
+
log("Pre-flight checks skipped via STACKWRIGHT_SKIP_PREFLIGHT");
|
|
297
|
+
return;
|
|
300
298
|
}
|
|
301
299
|
let versionOutput;
|
|
302
300
|
try {
|
|
@@ -534,7 +532,7 @@ function main() {
|
|
|
534
532
|
printResumeStatus(projectRoot);
|
|
535
533
|
const executable = findCodePuppy();
|
|
536
534
|
verbose(`Resolved raft-puppy / code-puppy: ${executable}`, args.verbose);
|
|
537
|
-
|
|
535
|
+
validateBinaryVersion(executable);
|
|
538
536
|
log("Spawning raft-puppy / code-puppy raft session...");
|
|
539
537
|
const spawnArgs = ["Begin", "--interactive", "--agent", "stackwright-pro-foreman-otter"];
|
|
540
538
|
verbose(`cmd: ${executable} ${spawnArgs.join(" ")}`, args.verbose);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/lib.ts"],"sourcesContent":["/**\n * @stackwright-pro/raft — Launch the Pro Otter Raft\n *\n * Writes init-context, verifies otter integrity, and spawns code-puppy\n * in foreman mode. The MCP tools handle everything after that.\n *\n * Replaces the deprecated Python cli_adapter.py → ForemanSession → os.execvpe() chain.\n */\n\nimport { existsSync, writeFileSync, mkdirSync } from 'fs';\nimport { join, resolve } from 'path';\nimport { spawn } from 'child_process';\nimport { verifyAllOtters } from '@stackwright-pro/mcp/integrity';\nimport { buildTypeSchemaSummary } from '@stackwright-pro/mcp/type-schemas';\nimport {\n parseArgs,\n printHelp,\n writeInitContext,\n findCodePuppy,\n validateCodePuppyEnv,\n ensureMcpConfig,\n syncAgents,\n printResumeStatus,\n resolveOtterDir,\n die,\n log,\n verbose,\n} from './lib.js';\n\n// ─── Main ────────────────────────────────────────────────────────────────────\n\nfunction main(): void {\n const args = parseArgs(process.argv);\n\n if (args.help) {\n printHelp();\n process.exit(0);\n }\n\n const projectRoot = resolve(args.projectRoot);\n if (!existsSync(projectRoot)) {\n die(`Project root does not exist: ${projectRoot}`);\n }\n\n // Sanity check: is this a Stackwright project?\n if (!existsSync(join(projectRoot, 'package.json'))) {\n die('No package.json found. Run npx @stackwright-pro/launch-stackwright-pro first.');\n }\n\n log('Launching Pro Otter Raft...');\n\n // 1. Write/enrich init context\n writeInitContext(projectRoot);\n verbose('Init context written', args.verbose);\n\n // 1a. Write type schemas sink for foreman routing\n try {\n const stackwrightDir = join(projectRoot, '.stackwright');\n mkdirSync(stackwrightDir, { recursive: true });\n const schemaSummary = buildTypeSchemaSummary();\n writeFileSync(\n join(stackwrightDir, 'type-schemas.json'),\n JSON.stringify(schemaSummary, null, 2) + '\\n'\n );\n verbose('Type schemas sink written', args.verbose);\n } catch (err) {\n // Non-blocking — foreman can still operate without type-schemas.json\n console.warn('⚠️ Could not write type-schemas.json:', String(err));\n }\n\n // 1b. Register MCP server — do this BEFORE any die() calls so clean installs\n // get MCP config even if otter install is incomplete\n ensureMcpConfig(projectRoot);\n\n // 1c. Sync agent files from installed @stackwright-pro/otters — always reflects\n // the installed version without relying on postinstall hooks\n syncAgents(projectRoot, args.verbose);\n\n // 2. Verify otter integrity\n const otterDir = resolveOtterDir(projectRoot);\n if (!otterDir) {\n die(\n 'Could not find otter directory. Is @stackwright-pro/otters installed?\\n' +\n ' Run: pnpm add @stackwright-pro/otters'\n );\n }\n\n const result = verifyAllOtters(otterDir);\n if (result.failed.length > 0) {\n console.warn('⚠️ Otter integrity check warnings (non-blocking):');\n for (const f of result.failed) {\n console.warn(` ${f.filename}: ${f.error}`);\n }\n console.warn(' Note: SHA-256 pinning will be replaced by PKI-signed deployment manifests.');\n console.warn(\n ' See: https://github.com/Per-Aspera-LLC/stackwright-pro/issues (signing model issue)'\n );\n } else {\n log(`✅ All ${result.verified.length} otters verified`);\n }\n\n // 3. Print resume status\n printResumeStatus(projectRoot);\n\n // 4. Resolve raft-puppy / code-puppy\n const executable = findCodePuppy();\n verbose(`Resolved raft-puppy / code-puppy: ${executable}`, args.verbose);\n\n // 4a. Pre-flight: validate API key and binary version before spawning\n validateCodePuppyEnv(executable);\n\n // 5. Spawn raft-puppy / code-puppy\n log('Spawning raft-puppy / code-puppy raft session...');\n\n const spawnArgs = ['Begin', '--interactive', '--agent', 'stackwright-pro-foreman-otter'];\n\n verbose(`cmd: ${executable} ${spawnArgs.join(' ')}`, args.verbose);\n\n const child = spawn(executable, spawnArgs, {\n stdio: 'inherit',\n cwd: projectRoot,\n env: {\n ...process.env,\n STACKWRIGHT_PROJECT_ROOT: projectRoot,\n },\n });\n\n // Forward signals to child — let it clean up gracefully\n const forward = (signal: NodeJS.Signals) => {\n if (child.pid) child.kill(signal);\n };\n const onSigint = () => forward('SIGINT');\n const onSigterm = () => forward('SIGTERM');\n process.on('SIGINT', onSigint);\n process.on('SIGTERM', onSigterm);\n\n child.on('error', (err) => die(`Failed to spawn raft-puppy / code-puppy: ${err.message}`));\n child.on('close', (code, signal) => {\n process.off('SIGINT', onSigint);\n process.off('SIGTERM', onSigterm);\n if (signal) {\n process.kill(process.pid, signal);\n } else {\n process.exit(code ?? 1);\n }\n });\n}\n\nmain();\n","/**\n * @stackwright-pro/raft — Pure utility functions\n *\n * Extracted from the CLI entry point so they're independently testable.\n * All side-effectful helpers (die, log, verbose) live here too —\n * the CLI entry point (`index.ts`) just wires them into `main()`.\n */\n\nimport { execSync } from 'child_process';\nimport {\n existsSync,\n lstatSync,\n mkdirSync,\n readFileSync,\n readdirSync,\n realpathSync,\n renameSync,\n writeFileSync,\n rmSync,\n} from 'fs';\nimport { join, resolve } from 'path';\nimport { homedir, hostname } from 'os';\n\n// ─── Pre-flight Constants ────────────────────────────────────────────────────\n\n/** Minimum code-puppy / raft-puppy version required by this raft release. */\nexport const MIN_SUPPORTED_CODE_PUPPY_VERSION = '0.1.0';\n\n// ─── CLI Argument Parsing ────────────────────────────────────────────────────\n\nexport interface ParsedArgs {\n projectRoot: string;\n verbose: boolean;\n help: boolean;\n}\n\nexport function parseArgs(argv: string[]): ParsedArgs {\n const args: ParsedArgs = {\n projectRoot: process.cwd(),\n verbose: false,\n help: false,\n };\n\n const raw = argv.slice(2);\n for (let i = 0; i < raw.length; i++) {\n const token = raw[i];\n switch (token) {\n case '--project-root':\n args.projectRoot = raw[++i] ?? die('--project-root requires a path argument');\n break;\n case '--verbose':\n args.verbose = true;\n break;\n case '--help':\n case '-h':\n args.help = true;\n break;\n default:\n die(`Unknown option: ${token}\\nRun with --help for usage.`);\n }\n }\n\n return args;\n}\n\nexport function printHelp(): void {\n console.log(\n `\n🦦 @stackwright-pro/raft — Spawn raft-puppy (or code-puppy) in foreman mode\n\nUsage: launch-raft [options]\n\nOptions:\n --project-root <path> Project root directory (default: cwd)\n --verbose Enable verbose logging\n --help, -h Show this help\n\nPrerequisites:\n pip install stackwright-puppy # provides raft-puppy + code-puppy alias\n Or: pip install code-puppy # fallback (MCP tools may not auto-start)\n`.trim()\n );\n}\n\n// ─── Utilities ───────────────────────────────────────────────────────────────\n\nexport function die(message: string): never {\n console.error(`❌ ${message}`);\n process.exit(1);\n}\n\nexport function log(message: string): void {\n console.log(`🦦 ${message}`);\n}\n\nexport function verbose(message: string, isVerbose: boolean): void {\n if (isVerbose) {\n console.log(` ${message}`);\n }\n}\n\n// ─── Pipeline Lock ──────────────────────────────────────────────────────────\n\nconst LOCK_FILE = '.stackwright/.lock';\n\nexport function acquireLock(projectRoot: string): boolean {\n const lockPath = join(projectRoot, LOCK_FILE);\n\n // Symlink guard\n if (existsSync(lockPath) && lstatSync(lockPath).isSymbolicLink()) {\n die('.stackwright/.lock is a symlink — refusing to acquire lock. Check for tampering.');\n }\n\n const pid = process.pid;\n const host = hostname();\n const timestamp = new Date().toISOString();\n\n const lockContent = JSON.stringify({\n pid,\n hostname: host,\n acquiredAt: timestamp,\n version: '1.0',\n });\n\n mkdirSync(join(projectRoot, '.stackwright'), { recursive: true });\n\n try {\n // O_EXCL makes this atomic on POSIX — fails if file already exists\n writeFileSync(lockPath, lockContent, { flag: 'wx' });\n return true;\n } catch (err) {\n // EEXIST means lock already held by another process\n if (err instanceof Error && 'code' in err && (err as { code: string }).code === 'EEXIST') {\n // Lock exists — try to read it and check if the process is still alive\n try {\n const existing = JSON.parse(readFileSync(lockPath, 'utf8')) as Record<string, unknown>;\n const oldPid = existing['pid'] as number;\n\n // On Unix, check if process still exists via kill(0, pid)\n try {\n process.kill(oldPid, 0); // Signal 0 = check existence only\n // Process exists — lock is held by live process, cannot acquire\n return false;\n } catch {\n // Process is dead — stale lock, can take over\n writeFileSync(lockPath, lockContent, 'utf-8');\n return true;\n }\n } catch {\n // Can't read lock file or not JSON — treat as stale, take over\n writeFileSync(lockPath, lockContent, 'utf-8');\n return true;\n }\n }\n throw err;\n }\n}\n\nexport function releaseLock(projectRoot: string): void {\n const lockPath = join(projectRoot, LOCK_FILE);\n try {\n rmSync(lockPath);\n } catch {\n // Lock file may not exist — that's fine\n }\n}\n\n// ─── Write Init Context ─────────────────────────────────────────────────────\n\nexport function writeInitContext(projectRoot: string): void {\n // Acquire pipeline lock — prevent concurrent launch-raft processes\n if (!acquireLock(projectRoot)) {\n let existingPid: string | number = 'unknown';\n try {\n const lockPath = join(projectRoot, LOCK_FILE);\n if (existsSync(lockPath)) {\n const lockData = JSON.parse(readFileSync(lockPath, 'utf8')) as Record<string, unknown>;\n existingPid = lockData['pid'] ?? 'unknown';\n }\n } catch {\n // Couldn't read lock file\n }\n die(\n `Pipeline lock already held by PID ${existingPid}. Another launch-raft process is running.`\n );\n }\n\n const stackwrightDir = join(projectRoot, '.stackwright');\n const initContextPath = join(stackwrightDir, 'init-context.json');\n\n // Merge, don't clobber — respect anything the launcher already wrote\n const MAX_INIT_CONTEXT_BYTES = 1 * 1024 * 1024; // 1MB\n let existing: Record<string, unknown> = {};\n try {\n const raw = readFileSync(initContextPath, 'utf-8');\n\n // Size guard — reject oversized init-context.json before parsing\n if (raw.length > MAX_INIT_CONTEXT_BYTES) {\n die(\n `init-context.json exceeds ${MAX_INIT_CONTEXT_BYTES.toLocaleString()} bytes (got ${raw.length.toLocaleString()}). Refusing to parse. This may be an attack or a corrupted file.`\n );\n }\n\n existing = JSON.parse(raw) as Record<string, unknown>;\n } catch {\n // Fresh project or malformed file — start from scratch\n }\n\n // Enrich: only fill in gaps\n existing['projectRoot'] = projectRoot;\n\n if (!existing['projectName']) {\n try {\n const pkgRaw = readFileSync(join(projectRoot, 'package.json'), 'utf-8');\n const pkg = JSON.parse(pkgRaw) as Record<string, unknown>;\n if (typeof pkg['name'] === 'string') {\n existing['projectName'] = pkg['name'];\n }\n } catch {\n // No package.json name — that's fine\n }\n }\n\n if (!existing['specPath']) {\n try {\n const specsDir = join(projectRoot, 'specs');\n if (existsSync(specsDir)) {\n const files = readdirSync(specsDir);\n const first = files[0];\n if (first) {\n existing['specPath'] = join('specs', first);\n }\n }\n } catch {\n // No specs dir — that's fine\n }\n }\n\n if (!existing['theme']) {\n try {\n const ymlPath = join(projectRoot, 'stackwright.yml');\n const ymlContent = readFileSync(ymlPath, 'utf-8');\n const match = /theme:\\s*\\n\\s+id:\\s*(.+)/.exec(ymlContent);\n if (match?.[1]) {\n existing['theme'] = match[1].trim();\n }\n } catch {\n // No stackwright.yml — that's fine\n }\n }\n\n existing['generatedBy'] = 'launch-raft';\n existing['version'] = '1.0';\n\n mkdirSync(stackwrightDir, { recursive: true });\n\n // Symlink guard — refuse to follow symlinks (prevents symlink-based overwrites)\n if (existsSync(stackwrightDir) && lstatSync(stackwrightDir).isSymbolicLink()) {\n die('.stackwright is a symlink — refusing to write. Check for tampering.');\n }\n if (existsSync(initContextPath) && lstatSync(initContextPath).isSymbolicLink()) {\n die('init-context.json is a symlink — refusing to write. Check for tampering.');\n }\n\n writeFileSync(initContextPath, JSON.stringify(existing, null, 2), 'utf-8');\n}\n\n// ─── Shutdown handler — release lock on exit ──────────────────────────────────\n\nprocess.on('exit', () => {\n try {\n releaseLock(process.cwd());\n } catch {\n // Lock release is best-effort on shutdown — don't block exit\n }\n});\nprocess.on('SIGINT', () => {\n try {\n releaseLock(process.cwd());\n } catch {\n // Lock release is best-effort on signal — don't block exit\n }\n process.exit(0);\n});\nprocess.on('SIGTERM', () => {\n try {\n releaseLock(process.cwd());\n } catch {\n // Lock release is best-effort on signal — don't block exit\n }\n process.exit(0);\n});\n\n// ─── Find code-puppy Executable ─────────────────────────────────────────────\n\nexport function findCodePuppy(): string {\n let candidate: string | null = null;\n\n // 1. Explicit env var override — highest priority\n const envPath = process.env['STACKWRIGHT_CODE_PUPPY_PATH'];\n if (envPath) {\n candidate = envPath;\n }\n\n // 2. Prefer raft-puppy (stackwright-puppy fork) over vanilla code-puppy.\n // raft-puppy ships the MCP auto-enable fix and local .code-puppy.json\n // loading — both required for the raft to work on a clean install.\n // Falls back to code-puppy so existing installs don't break.\n if (!candidate) {\n for (const bin of ['raft-puppy', 'code-puppy']) {\n try {\n candidate = execSync(`which ${bin}`, { encoding: 'utf-8' }).trim();\n if (candidate) break;\n } catch {\n // Not on PATH, try next\n }\n }\n }\n\n if (!candidate) {\n die(\n 'raft-puppy (or code-puppy) not found.\\n' +\n '\\n' +\n 'Install the Stackwright-patched build (recommended):\\n' +\n ' pip install stackwright-puppy\\n' +\n '\\n' +\n 'Or install vanilla code-puppy (MCP tools may not auto-start):\\n' +\n ' pip install code-puppy\\n' +\n '\\n' +\n 'Or set STACKWRIGHT_CODE_PUPPY_PATH to the binary path.'\n );\n }\n\n // Resolve to absolute path — prevents bare-name or relative-path shenanigans\n const resolved = resolve(candidate);\n\n if (!existsSync(resolved)) {\n die(`raft-puppy/code-puppy not found at resolved path: ${resolved}`);\n }\n\n // Follow the full symlink chain to the real binary.\n // pip/pipx/uvx installs create a wrapper symlink in ~/.local/bin/ that points\n // to the actual binary inside a virtualenv — this is expected and safe.\n let realBinary: string;\n try {\n realBinary = realpathSync(resolved);\n } catch {\n die(\n `raft-puppy at ${resolved} has a broken symlink — cannot resolve to a real path. ` +\n `Try reinstalling stackwright-puppy or set STACKWRIGHT_CODE_PUPPY_PATH to the real binary.`\n );\n }\n\n if (!existsSync(realBinary)) {\n die(`raft-puppy symlink at ${resolved} points to a missing file: ${realBinary}`);\n }\n\n // Security checks — applied to the real binary, not the symlink entry point\n const stat = lstatSync(realBinary);\n\n // Refuse world-writable or group-writable binaries\n if (stat.mode & 0o022) {\n die(\n `raft-puppy at ${realBinary} is group- or world-writable (mode: ${(stat.mode & 0o777).toString(8)}) — refusing to exec.`\n );\n }\n\n // Refuse setuid/setgid binaries\n if (stat.mode & 0o6000) {\n die(`raft-puppy at ${realBinary} has setuid/setgid bits — refusing to exec.`);\n }\n\n return realBinary;\n}\n\n// ─── Pre-flight Environment Validation ──────────────────────────────────────\n\nfunction parseSemver(version: string): [number, number, number] {\n const parts = version.split('-')[0]!.split('.').map(Number);\n return [parts[0] ?? 0, parts[1] ?? 0, parts[2] ?? 0];\n}\n\nfunction semverGte(a: string, b: string): boolean {\n const [aMaj, aMin, aPatch] = parseSemver(a);\n const [bMaj, bMin, bPatch] = parseSemver(b);\n if (aMaj !== bMaj) return aMaj > bMaj;\n if (aMin !== bMin) return aMin > bMin;\n return aPatch >= bPatch;\n}\n\n/**\n * Validates the runtime environment before spawning code-puppy.\n * Calls die() (process.exit(1)) with a human-readable remediation message\n * on any failure — never reaches the spawn if a check fails.\n *\n * Checks:\n * 1. ANTHROPIC_API_KEY is set and non-empty\n * 2. code-puppy --version reports >= MIN_SUPPORTED_CODE_PUPPY_VERSION\n */\nexport function validateCodePuppyEnv(binaryPath: string): void {\n // 1. API key check — fast, no subprocess needed\n const apiKey = process.env['ANTHROPIC_API_KEY'];\n if (!apiKey || apiKey.trim() === '') {\n die(\n 'ANTHROPIC_API_KEY is not set or is empty.\\n' +\n '\\n' +\n 'Set it in your current shell:\\n' +\n ' export ANTHROPIC_API_KEY=sk-ant-...\\n' +\n '\\n' +\n 'Or add it to your ~/.bashrc / ~/.zshrc to persist across sessions.\\n' +\n 'Get your key at: https://console.anthropic.com/settings/keys'\n );\n }\n\n // 2. Version check — run binary with --version, parse semver, compare\n let versionOutput: string;\n try {\n versionOutput = execSync(`${JSON.stringify(binaryPath)} --version`, {\n encoding: 'utf-8',\n timeout: 5000,\n stdio: ['ignore', 'pipe', 'pipe'],\n }).trim();\n } catch {\n die(\n `Could not determine raft-puppy / code-puppy version.\\n` +\n ` Binary: ${binaryPath}\\n` +\n ` Minimum required: ${MIN_SUPPORTED_CODE_PUPPY_VERSION}\\n` +\n `\\n` +\n ` Run: pip install --upgrade stackwright-puppy\\n` +\n ` Or: pip install --upgrade code-puppy`\n );\n }\n\n const match = /(\\d+\\.\\d+\\.\\d+(?:-[^\\s]+)?)/.exec(versionOutput);\n if (!match || !match[1]) {\n die(\n `Could not parse version from raft-puppy / code-puppy output: ${JSON.stringify(versionOutput)}\\n` +\n ` Minimum required: ${MIN_SUPPORTED_CODE_PUPPY_VERSION}\\n` +\n `\\n` +\n ` Run: pip install --upgrade stackwright-puppy\\n` +\n ` Or: pip install --upgrade code-puppy`\n );\n }\n\n const installedVersion = match[1];\n if (!semverGte(installedVersion, MIN_SUPPORTED_CODE_PUPPY_VERSION)) {\n die(\n `raft-puppy / code-puppy ${installedVersion} is below the minimum required version.\\n` +\n ` Installed: ${installedVersion}\\n` +\n ` Minimum required: ${MIN_SUPPORTED_CODE_PUPPY_VERSION}\\n` +\n `\\n` +\n ` Run: pip install --upgrade stackwright-puppy\\n` +\n ` Or: pip install --upgrade code-puppy`\n );\n }\n}\n\n// ─── Ensure MCP Config ─────────────────────────────────────────────────────\n\nexport function ensureMcpConfig(projectRoot: string): void {\n const xdgConfigHome = process.env['XDG_CONFIG_HOME'];\n const configDir = xdgConfigHome\n ? join(xdgConfigHome, 'code_puppy')\n : join(homedir(), '.code_puppy');\n const configPath = join(configDir, 'mcp_servers.json');\n\n // Symlink guard — consistent with other security patterns\n if (existsSync(configPath) && lstatSync(configPath).isSymbolicLink()) {\n die('`~/.code_puppy/mcp_servers.json` is a symlink — refusing to write. Check for tampering.');\n }\n\n mkdirSync(configDir, { recursive: true });\n\n const localServerPath = join(\n projectRoot,\n 'node_modules',\n '@stackwright-pro',\n 'mcp',\n 'dist',\n 'server.js'\n );\n\n // Resolve from raft's own node_modules — raft has @stackwright-pro/mcp as a\n // direct dep, so this is always available when running via `npx @stackwright-pro/raft`.\n // This is the reliable middle fallback: works even if the scaffolded project\n // never had mcp added to its own deps (e.g. old published launch-stackwright-pro).\n //\n // Note: require.resolve('@stackwright-pro/mcp') resolves via the `main` field\n // → dist/server.js. We cannot use the subpath './dist/server.js' directly\n // because it's not listed in the package's `exports` map.\n let raftOwnServerPath: string | null = null;\n try {\n raftOwnServerPath = require.resolve('@stackwright-pro/mcp');\n } catch {\n // mcp not resolvable from raft's own node_modules — unusual, fall through to npx\n }\n\n const serverConfig = existsSync(localServerPath)\n ? { type: 'stdio', command: 'node', args: [localServerPath] }\n : raftOwnServerPath !== null\n ? { type: 'stdio', command: 'node', args: [raftOwnServerPath] }\n : { type: 'stdio', command: 'npx', args: ['--yes', '@stackwright-pro/mcp@latest'] };\n\n // Read existing → merge, don't clobber other registered servers\n let existing: { mcp_servers?: Record<string, unknown> } = {};\n if (existsSync(configPath)) {\n try {\n const raw = readFileSync(configPath, 'utf-8');\n existing = JSON.parse(raw) as { mcp_servers?: Record<string, unknown> };\n } catch {\n // Malformed file — start fresh\n }\n }\n\n const merged = {\n ...existing,\n mcp_servers: {\n ...(existing.mcp_servers ?? {}),\n 'stackwright-pro': serverConfig,\n },\n };\n\n // Migration: remove the legacy 'stackwright' placeholder entry written by\n // scaffold-hooks@0.x. It pointed to @modelcontextprotocol/server-filesystem\n // with a literal '/path/to/dir' arg — never a real server, just a template\n // stub. Our auto-enable patch (stackwright-puppy Fix 1) now starts every\n // enabled server on launch, so leaving this entry causes an immediate\n // TaskGroup crash: \"ENOENT: no such file or directory, stat '/path/to/dir'\".\n //\n // We delete it unconditionally when the correct 'stackwright-pro' entry is\n // being written. If someone actually *wants* a server under the key\n // 'stackwright' they can add it back manually — but the placeholder never\n // represents a live server.\n //\n // See: CHANGES_FROM_UPSTREAM.md in stackwright-puppy (Fix 1 notes)\n if (merged.mcp_servers && 'stackwright' in merged.mcp_servers) {\n const stale = merged.mcp_servers['stackwright'] as Record<string, unknown>;\n const args = stale?.['args'] as unknown[] | undefined;\n const isPlaceholder =\n args?.includes('/path/to/dir') ||\n (stale?.['command'] === 'npx' &&\n (args as string[] | undefined)?.some((a) => String(a).includes('server-filesystem')));\n if (isPlaceholder) {\n delete merged.mcp_servers['stackwright'];\n log(\n 'Removed stale `stackwright` placeholder from mcp_servers.json ' +\n '(was: @modelcontextprotocol/server-filesystem /path/to/dir — not a real server)'\n );\n }\n }\n\n // Atomic write via .tmp rename swap\n const tmpPath = `${configPath}.tmp`;\n writeFileSync(tmpPath, JSON.stringify(merged, null, 2), 'utf-8');\n renameSync(tmpPath, configPath);\n\n log('MCP server registered → ~/.code_puppy/mcp_servers.json');\n}\n\n// ─── Print Resume Status ────────────────────────────────────────────────────\n\nexport function printResumeStatus(projectRoot: string): void {\n const pipelineStatePath = join(projectRoot, '.stackwright', 'pipeline-state.json');\n\n try {\n const raw = readFileSync(pipelineStatePath, 'utf-8');\n const state = JSON.parse(raw) as Record<string, unknown>;\n const status = state['status'];\n const phases = state['phases'];\n\n if (typeof phases !== 'object' || phases === null || Array.isArray(phases)) {\n return;\n }\n\n const phaseEntries = Object.values(phases as Record<string, Record<string, unknown>>);\n const totalPhases = phaseEntries.length || 8;\n\n switch (status) {\n case 'setup':\n log('📍 Starting fresh');\n break;\n case 'questions': {\n const answered = phaseEntries.filter((p) => p['answered'] === true).length;\n log(`📍 Resuming: questions phase (${answered}/${totalPhases} phases answered)`);\n break;\n }\n case 'execution': {\n const executed = phaseEntries.filter((p) => p['executed'] === true).length;\n log(`📍 Resuming: execution phase (${executed}/${totalPhases} phases complete)`);\n break;\n }\n case 'done':\n log('📍 Pipeline complete — re-entering to review');\n break;\n default:\n break;\n }\n } catch {\n // No pipeline state yet — fresh project\n }\n}\n\n// ─── Resolve Otter Directory ────────────────────────────────────────────────\n\nexport function resolveOtterDir(projectRoot: string): string | null {\n const candidates = [\n join(projectRoot, 'node_modules', '@stackwright-pro', 'otters', 'src'),\n join(projectRoot, 'packages', 'otters', 'src'),\n ];\n\n for (const candidate of candidates) {\n if (existsSync(candidate)) {\n return candidate;\n }\n }\n\n return null;\n}\n\n// ─── Sync Agents ────────────────────────────────────────────────────────────\n\n/**\n * Copy all *-otter.json files from the resolved otters package to\n * ~/.code_puppy/agents/ on every raft startup.\n *\n * This mirrors the pattern used by ensureMcpConfig() for mcp_servers.json.\n * Relying solely on the postinstall hook in @stackwright-pro/otters is fragile:\n * pnpm/npm don't always re-run scripts on package updates, and postinstall\n * order is non-deterministic when multiple packages run scripts. Active sync\n * on every raft launch guarantees agents are always the installed version.\n */\nexport function syncAgents(projectRoot: string, isVerbose: boolean = false): void {\n const xdgConfigHome = process.env['XDG_CONFIG_HOME'];\n const agentsDir = xdgConfigHome\n ? join(xdgConfigHome, 'code_puppy', 'agents')\n : join(homedir(), '.code_puppy', 'agents');\n\n const otterDir = resolveOtterDir(projectRoot);\n if (!otterDir) {\n verbose('No otters directory found — skipping agent sync', isVerbose);\n return;\n }\n\n // Symlink guard on agents dir\n if (existsSync(agentsDir) && lstatSync(agentsDir).isSymbolicLink()) {\n die('~/.code_puppy/agents is a symlink — refusing to write. Check for tampering.');\n }\n\n mkdirSync(agentsDir, { recursive: true });\n\n let synced = 0;\n let skipped = 0;\n\n try {\n const files = readdirSync(otterDir);\n for (const file of files) {\n if (!file.endsWith('-otter.json')) continue;\n\n const src = join(otterDir, file);\n const dest = join(agentsDir, file);\n\n // Symlink guard on individual file\n if (existsSync(dest) && lstatSync(dest).isSymbolicLink()) {\n verbose(`Skipping ${file} — dest is a symlink`, isVerbose);\n skipped++;\n continue;\n }\n\n // Atomic write: copy to .tmp then rename\n const tmp = `${dest}.tmp`;\n const content = readFileSync(src);\n writeFileSync(tmp, content);\n renameSync(tmp, dest);\n verbose(`Synced: ${file}`, isVerbose);\n synced++;\n }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n // Non-fatal: log and continue — a stale agent is better than a crash\n console.warn(`⚠️ Agent sync partial failure: ${msg}`);\n return;\n }\n\n if (synced > 0) {\n log(\n `Agents synced → ~/.code_puppy/agents/ (${synced} otters${skipped > 0 ? `, ${skipped} skipped` : ''})`\n );\n }\n}\n"],"mappings":"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","names":["import_fs","import_path","import_child_process"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/lib.ts"],"sourcesContent":["/**\n * @stackwright-pro/raft — Launch the Pro Otter Raft\n *\n * Writes init-context, verifies otter integrity, and spawns code-puppy\n * in foreman mode. The MCP tools handle everything after that.\n *\n * Replaces the deprecated Python cli_adapter.py → ForemanSession → os.execvpe() chain.\n */\n\nimport { existsSync, writeFileSync, mkdirSync } from 'fs';\nimport { join, resolve } from 'path';\nimport { spawn } from 'child_process';\nimport { verifyAllOtters } from '@stackwright-pro/mcp/integrity';\nimport { buildTypeSchemaSummary } from '@stackwright-pro/mcp/type-schemas';\nimport {\n parseArgs,\n printHelp,\n writeInitContext,\n findCodePuppy,\n validateBinaryVersion,\n ensureMcpConfig,\n syncAgents,\n printResumeStatus,\n resolveOtterDir,\n die,\n log,\n verbose,\n} from './lib.js';\n\n// ─── Main ────────────────────────────────────────────────────────────────────\n\nfunction main(): void {\n const args = parseArgs(process.argv);\n\n if (args.help) {\n printHelp();\n process.exit(0);\n }\n\n const projectRoot = resolve(args.projectRoot);\n if (!existsSync(projectRoot)) {\n die(`Project root does not exist: ${projectRoot}`);\n }\n\n // Sanity check: is this a Stackwright project?\n if (!existsSync(join(projectRoot, 'package.json'))) {\n die('No package.json found. Run npx @stackwright-pro/launch-stackwright-pro first.');\n }\n\n log('Launching Pro Otter Raft...');\n\n // 1. Write/enrich init context\n writeInitContext(projectRoot);\n verbose('Init context written', args.verbose);\n\n // 1a. Write type schemas sink for foreman routing\n try {\n const stackwrightDir = join(projectRoot, '.stackwright');\n mkdirSync(stackwrightDir, { recursive: true });\n const schemaSummary = buildTypeSchemaSummary();\n writeFileSync(\n join(stackwrightDir, 'type-schemas.json'),\n JSON.stringify(schemaSummary, null, 2) + '\\n'\n );\n verbose('Type schemas sink written', args.verbose);\n } catch (err) {\n // Non-blocking — foreman can still operate without type-schemas.json\n console.warn('⚠️ Could not write type-schemas.json:', String(err));\n }\n\n // 1b. Register MCP server — do this BEFORE any die() calls so clean installs\n // get MCP config even if otter install is incomplete\n ensureMcpConfig(projectRoot);\n\n // 1c. Sync agent files from installed @stackwright-pro/otters — always reflects\n // the installed version without relying on postinstall hooks\n syncAgents(projectRoot, args.verbose);\n\n // 2. Verify otter integrity\n const otterDir = resolveOtterDir(projectRoot);\n if (!otterDir) {\n die(\n 'Could not find otter directory. Is @stackwright-pro/otters installed?\\n' +\n ' Run: pnpm add @stackwright-pro/otters'\n );\n }\n\n const result = verifyAllOtters(otterDir);\n if (result.failed.length > 0) {\n console.warn('⚠️ Otter integrity check warnings (non-blocking):');\n for (const f of result.failed) {\n console.warn(` ${f.filename}: ${f.error}`);\n }\n console.warn(' Note: SHA-256 pinning will be replaced by PKI-signed deployment manifests.');\n console.warn(\n ' See: https://github.com/Per-Aspera-LLC/stackwright-pro/issues (signing model issue)'\n );\n } else {\n log(`✅ All ${result.verified.length} otters verified`);\n }\n\n // 3. Print resume status\n printResumeStatus(projectRoot);\n\n // 4. Resolve raft-puppy / code-puppy\n const executable = findCodePuppy();\n verbose(`Resolved raft-puppy / code-puppy: ${executable}`, args.verbose);\n\n // 4a. Pre-flight: validate binary version before spawning\n validateBinaryVersion(executable);\n\n // 5. Spawn raft-puppy / code-puppy\n log('Spawning raft-puppy / code-puppy raft session...');\n\n const spawnArgs = ['Begin', '--interactive', '--agent', 'stackwright-pro-foreman-otter'];\n\n verbose(`cmd: ${executable} ${spawnArgs.join(' ')}`, args.verbose);\n\n const child = spawn(executable, spawnArgs, {\n stdio: 'inherit',\n cwd: projectRoot,\n env: {\n ...process.env,\n STACKWRIGHT_PROJECT_ROOT: projectRoot,\n },\n });\n\n // Forward signals to child — let it clean up gracefully\n const forward = (signal: NodeJS.Signals) => {\n if (child.pid) child.kill(signal);\n };\n const onSigint = () => forward('SIGINT');\n const onSigterm = () => forward('SIGTERM');\n process.on('SIGINT', onSigint);\n process.on('SIGTERM', onSigterm);\n\n child.on('error', (err) => die(`Failed to spawn raft-puppy / code-puppy: ${err.message}`));\n child.on('close', (code, signal) => {\n process.off('SIGINT', onSigint);\n process.off('SIGTERM', onSigterm);\n if (signal) {\n process.kill(process.pid, signal);\n } else {\n process.exit(code ?? 1);\n }\n });\n}\n\nmain();\n","/**\n * @stackwright-pro/raft — Pure utility functions\n *\n * Extracted from the CLI entry point so they're independently testable.\n * All side-effectful helpers (die, log, verbose) live here too —\n * the CLI entry point (`index.ts`) just wires them into `main()`.\n */\n\nimport { execSync } from 'child_process';\nimport {\n existsSync,\n lstatSync,\n mkdirSync,\n readFileSync,\n readdirSync,\n realpathSync,\n renameSync,\n writeFileSync,\n rmSync,\n} from 'fs';\nimport { join, resolve } from 'path';\nimport { homedir, hostname } from 'os';\n\n// ─── Pre-flight Constants ────────────────────────────────────────────────────\n\n/** Minimum code-puppy / raft-puppy version required by this raft release. */\nexport const MIN_SUPPORTED_CODE_PUPPY_VERSION = '0.1.0';\n\n// ─── CLI Argument Parsing ────────────────────────────────────────────────────\n\nexport interface ParsedArgs {\n projectRoot: string;\n verbose: boolean;\n help: boolean;\n}\n\nexport function parseArgs(argv: string[]): ParsedArgs {\n const args: ParsedArgs = {\n projectRoot: process.cwd(),\n verbose: false,\n help: false,\n };\n\n const raw = argv.slice(2);\n for (let i = 0; i < raw.length; i++) {\n const token = raw[i];\n switch (token) {\n case '--project-root':\n args.projectRoot = raw[++i] ?? die('--project-root requires a path argument');\n break;\n case '--verbose':\n args.verbose = true;\n break;\n case '--help':\n case '-h':\n args.help = true;\n break;\n default:\n die(`Unknown option: ${token}\\nRun with --help for usage.`);\n }\n }\n\n return args;\n}\n\nexport function printHelp(): void {\n console.log(\n `\n🦦 @stackwright-pro/raft — Spawn raft-puppy (or code-puppy) in foreman mode\n\nUsage: launch-raft [options]\n\nOptions:\n --project-root <path> Project root directory (default: cwd)\n --verbose Enable verbose logging\n --help, -h Show this help\n\nPrerequisites:\n pip install stackwright-puppy # provides raft-puppy + code-puppy alias\n Or: pip install code-puppy # fallback (MCP tools may not auto-start)\n`.trim()\n );\n}\n\n// ─── Utilities ───────────────────────────────────────────────────────────────\n\nexport function die(message: string): never {\n console.error(`❌ ${message}`);\n process.exit(1);\n}\n\nexport function log(message: string): void {\n console.log(`🦦 ${message}`);\n}\n\nexport function verbose(message: string, isVerbose: boolean): void {\n if (isVerbose) {\n console.log(` ${message}`);\n }\n}\n\n// ─── Pipeline Lock ──────────────────────────────────────────────────────────\n\nconst LOCK_FILE = '.stackwright/.lock';\n\nexport function acquireLock(projectRoot: string): boolean {\n const lockPath = join(projectRoot, LOCK_FILE);\n\n // Symlink guard\n if (existsSync(lockPath) && lstatSync(lockPath).isSymbolicLink()) {\n die('.stackwright/.lock is a symlink — refusing to acquire lock. Check for tampering.');\n }\n\n const pid = process.pid;\n const host = hostname();\n const timestamp = new Date().toISOString();\n\n const lockContent = JSON.stringify({\n pid,\n hostname: host,\n acquiredAt: timestamp,\n version: '1.0',\n });\n\n mkdirSync(join(projectRoot, '.stackwright'), { recursive: true });\n\n try {\n // O_EXCL makes this atomic on POSIX — fails if file already exists\n writeFileSync(lockPath, lockContent, { flag: 'wx' });\n return true;\n } catch (err) {\n // EEXIST means lock already held by another process\n if (err instanceof Error && 'code' in err && (err as { code: string }).code === 'EEXIST') {\n // Lock exists — try to read it and check if the process is still alive\n try {\n const existing = JSON.parse(readFileSync(lockPath, 'utf8')) as Record<string, unknown>;\n const oldPid = existing['pid'] as number;\n\n // On Unix, check if process still exists via kill(0, pid)\n try {\n process.kill(oldPid, 0); // Signal 0 = check existence only\n // Process exists — lock is held by live process, cannot acquire\n return false;\n } catch {\n // Process is dead — stale lock, can take over\n writeFileSync(lockPath, lockContent, 'utf-8');\n return true;\n }\n } catch {\n // Can't read lock file or not JSON — treat as stale, take over\n writeFileSync(lockPath, lockContent, 'utf-8');\n return true;\n }\n }\n throw err;\n }\n}\n\nexport function releaseLock(projectRoot: string): void {\n const lockPath = join(projectRoot, LOCK_FILE);\n try {\n rmSync(lockPath);\n } catch {\n // Lock file may not exist — that's fine\n }\n}\n\n// ─── Write Init Context ─────────────────────────────────────────────────────\n\nexport function writeInitContext(projectRoot: string): void {\n // Acquire pipeline lock — prevent concurrent launch-raft processes\n if (!acquireLock(projectRoot)) {\n let existingPid: string | number = 'unknown';\n try {\n const lockPath = join(projectRoot, LOCK_FILE);\n if (existsSync(lockPath)) {\n const lockData = JSON.parse(readFileSync(lockPath, 'utf8')) as Record<string, unknown>;\n existingPid = lockData['pid'] ?? 'unknown';\n }\n } catch {\n // Couldn't read lock file\n }\n die(\n `Pipeline lock already held by PID ${existingPid}. Another launch-raft process is running.`\n );\n }\n\n const stackwrightDir = join(projectRoot, '.stackwright');\n const initContextPath = join(stackwrightDir, 'init-context.json');\n\n // Merge, don't clobber — respect anything the launcher already wrote\n const MAX_INIT_CONTEXT_BYTES = 1 * 1024 * 1024; // 1MB\n let existing: Record<string, unknown> = {};\n try {\n const raw = readFileSync(initContextPath, 'utf-8');\n\n // Size guard — reject oversized init-context.json before parsing\n if (raw.length > MAX_INIT_CONTEXT_BYTES) {\n die(\n `init-context.json exceeds ${MAX_INIT_CONTEXT_BYTES.toLocaleString()} bytes (got ${raw.length.toLocaleString()}). Refusing to parse. This may be an attack or a corrupted file.`\n );\n }\n\n existing = JSON.parse(raw) as Record<string, unknown>;\n } catch {\n // Fresh project or malformed file — start from scratch\n }\n\n // Enrich: only fill in gaps\n existing['projectRoot'] = projectRoot;\n\n if (!existing['projectName']) {\n try {\n const pkgRaw = readFileSync(join(projectRoot, 'package.json'), 'utf-8');\n const pkg = JSON.parse(pkgRaw) as Record<string, unknown>;\n if (typeof pkg['name'] === 'string') {\n existing['projectName'] = pkg['name'];\n }\n } catch {\n // No package.json name — that's fine\n }\n }\n\n if (!existing['specPath']) {\n try {\n const specsDir = join(projectRoot, 'specs');\n if (existsSync(specsDir)) {\n const files = readdirSync(specsDir);\n const first = files[0];\n if (first) {\n existing['specPath'] = join('specs', first);\n }\n }\n } catch {\n // No specs dir — that's fine\n }\n }\n\n if (!existing['theme']) {\n try {\n const ymlPath = join(projectRoot, 'stackwright.yml');\n const ymlContent = readFileSync(ymlPath, 'utf-8');\n const match = /theme:\\s*\\n\\s+id:\\s*(.+)/.exec(ymlContent);\n if (match?.[1]) {\n existing['theme'] = match[1].trim();\n }\n } catch {\n // No stackwright.yml — that's fine\n }\n }\n\n existing['generatedBy'] = 'launch-raft';\n existing['version'] = '1.0';\n\n mkdirSync(stackwrightDir, { recursive: true });\n\n // Symlink guard — refuse to follow symlinks (prevents symlink-based overwrites)\n if (existsSync(stackwrightDir) && lstatSync(stackwrightDir).isSymbolicLink()) {\n die('.stackwright is a symlink — refusing to write. Check for tampering.');\n }\n if (existsSync(initContextPath) && lstatSync(initContextPath).isSymbolicLink()) {\n die('init-context.json is a symlink — refusing to write. Check for tampering.');\n }\n\n writeFileSync(initContextPath, JSON.stringify(existing, null, 2), 'utf-8');\n}\n\n// ─── Shutdown handler — release lock on exit ──────────────────────────────────\n\nprocess.on('exit', () => {\n try {\n releaseLock(process.cwd());\n } catch {\n // Lock release is best-effort on shutdown — don't block exit\n }\n});\nprocess.on('SIGINT', () => {\n try {\n releaseLock(process.cwd());\n } catch {\n // Lock release is best-effort on signal — don't block exit\n }\n process.exit(0);\n});\nprocess.on('SIGTERM', () => {\n try {\n releaseLock(process.cwd());\n } catch {\n // Lock release is best-effort on signal — don't block exit\n }\n process.exit(0);\n});\n\n// ─── Find code-puppy Executable ─────────────────────────────────────────────\n\nexport function findCodePuppy(): string {\n let candidate: string | null = null;\n\n // 1. Explicit env var override — highest priority\n const envPath = process.env['STACKWRIGHT_CODE_PUPPY_PATH'];\n if (envPath) {\n candidate = envPath;\n }\n\n // 2. Prefer raft-puppy (stackwright-puppy fork) over vanilla code-puppy.\n // raft-puppy ships the MCP auto-enable fix and local .code-puppy.json\n // loading — both required for the raft to work on a clean install.\n // Falls back to code-puppy so existing installs don't break.\n if (!candidate) {\n for (const bin of ['raft-puppy', 'code-puppy']) {\n try {\n candidate = execSync(`which ${bin}`, { encoding: 'utf-8' }).trim();\n if (candidate) break;\n } catch {\n // Not on PATH, try next\n }\n }\n }\n\n if (!candidate) {\n die(\n 'raft-puppy (or code-puppy) not found.\\n' +\n '\\n' +\n 'Install the Stackwright-patched build (recommended):\\n' +\n ' pip install stackwright-puppy\\n' +\n '\\n' +\n 'Or install vanilla code-puppy (MCP tools may not auto-start):\\n' +\n ' pip install code-puppy\\n' +\n '\\n' +\n 'Or set STACKWRIGHT_CODE_PUPPY_PATH to the binary path.'\n );\n }\n\n // Resolve to absolute path — prevents bare-name or relative-path shenanigans\n const resolved = resolve(candidate);\n\n if (!existsSync(resolved)) {\n die(`raft-puppy/code-puppy not found at resolved path: ${resolved}`);\n }\n\n // Follow the full symlink chain to the real binary.\n // pip/pipx/uvx installs create a wrapper symlink in ~/.local/bin/ that points\n // to the actual binary inside a virtualenv — this is expected and safe.\n let realBinary: string;\n try {\n realBinary = realpathSync(resolved);\n } catch {\n die(\n `raft-puppy at ${resolved} has a broken symlink — cannot resolve to a real path. ` +\n `Try reinstalling stackwright-puppy or set STACKWRIGHT_CODE_PUPPY_PATH to the real binary.`\n );\n }\n\n if (!existsSync(realBinary)) {\n die(`raft-puppy symlink at ${resolved} points to a missing file: ${realBinary}`);\n }\n\n // Security checks — applied to the real binary, not the symlink entry point\n const stat = lstatSync(realBinary);\n\n // Refuse world-writable or group-writable binaries\n if (stat.mode & 0o022) {\n die(\n `raft-puppy at ${realBinary} is group- or world-writable (mode: ${(stat.mode & 0o777).toString(8)}) — refusing to exec.`\n );\n }\n\n // Refuse setuid/setgid binaries\n if (stat.mode & 0o6000) {\n die(`raft-puppy at ${realBinary} has setuid/setgid bits — refusing to exec.`);\n }\n\n return realBinary;\n}\n\n// ─── Pre-flight Environment Validation ──────────────────────────────────────\n\nfunction parseSemver(version: string): [number, number, number] {\n const parts = version.split('-')[0]!.split('.').map(Number);\n return [parts[0] ?? 0, parts[1] ?? 0, parts[2] ?? 0];\n}\n\nfunction semverGte(a: string, b: string): boolean {\n const [aMaj, aMin, aPatch] = parseSemver(a);\n const [bMaj, bMin, bPatch] = parseSemver(b);\n if (aMaj !== bMaj) return aMaj > bMaj;\n if (aMin !== bMin) return aMin > bMin;\n return aPatch >= bPatch;\n}\n\n/**\n * Validates the runtime environment before spawning code-puppy.\n * Calls die() (process.exit(1)) with a human-readable remediation message\n * on failure — never reaches the spawn if a check fails.\n *\n * Auth checking is intentionally NOT done here — code-puppy/raft-puppy owns\n * the auth layer and will surface a clear error at spawn time for any\n * missing/invalid credentials. This keeps the raft agnostic to model\n * providers (Anthropic API key, claude auth login OAuth, AWS Bedrock,\n * Google Vertex, Ollama, air-gapped inference, etc.).\n *\n * Checks:\n * 1. STACKWRIGHT_SKIP_PREFLIGHT — if 'true', skip all checks and return\n * 2. code-puppy --version reports >= MIN_SUPPORTED_CODE_PUPPY_VERSION\n */\nexport function validateBinaryVersion(binaryPath: string): void {\n // Escape hatch for air-gapped / custom model-provider deployments.\n // Set STACKWRIGHT_SKIP_PREFLIGHT=true to bypass pre-flight checks.\n if (process.env['STACKWRIGHT_SKIP_PREFLIGHT'] === 'true') {\n log('Pre-flight checks skipped via STACKWRIGHT_SKIP_PREFLIGHT');\n return;\n }\n\n // 1. Version check — run binary with --version, parse semver, compare\n let versionOutput: string;\n try {\n versionOutput = execSync(`${JSON.stringify(binaryPath)} --version`, {\n encoding: 'utf-8',\n timeout: 5000,\n stdio: ['ignore', 'pipe', 'pipe'],\n }).trim();\n } catch {\n die(\n `Could not determine raft-puppy / code-puppy version.\\n` +\n ` Binary: ${binaryPath}\\n` +\n ` Minimum required: ${MIN_SUPPORTED_CODE_PUPPY_VERSION}\\n` +\n `\\n` +\n ` Run: pip install --upgrade stackwright-puppy\\n` +\n ` Or: pip install --upgrade code-puppy`\n );\n }\n\n const match = /(\\d+\\.\\d+\\.\\d+(?:-[^\\s]+)?)/.exec(versionOutput);\n if (!match || !match[1]) {\n die(\n `Could not parse version from raft-puppy / code-puppy output: ${JSON.stringify(versionOutput)}\\n` +\n ` Minimum required: ${MIN_SUPPORTED_CODE_PUPPY_VERSION}\\n` +\n `\\n` +\n ` Run: pip install --upgrade stackwright-puppy\\n` +\n ` Or: pip install --upgrade code-puppy`\n );\n }\n\n const installedVersion = match[1];\n if (!semverGte(installedVersion, MIN_SUPPORTED_CODE_PUPPY_VERSION)) {\n die(\n `raft-puppy / code-puppy ${installedVersion} is below the minimum required version.\\n` +\n ` Installed: ${installedVersion}\\n` +\n ` Minimum required: ${MIN_SUPPORTED_CODE_PUPPY_VERSION}\\n` +\n `\\n` +\n ` Run: pip install --upgrade stackwright-puppy\\n` +\n ` Or: pip install --upgrade code-puppy`\n );\n }\n}\n\n// ─── Ensure MCP Config ─────────────────────────────────────────────────────\n\nexport function ensureMcpConfig(projectRoot: string): void {\n const xdgConfigHome = process.env['XDG_CONFIG_HOME'];\n const configDir = xdgConfigHome\n ? join(xdgConfigHome, 'code_puppy')\n : join(homedir(), '.code_puppy');\n const configPath = join(configDir, 'mcp_servers.json');\n\n // Symlink guard — consistent with other security patterns\n if (existsSync(configPath) && lstatSync(configPath).isSymbolicLink()) {\n die('`~/.code_puppy/mcp_servers.json` is a symlink — refusing to write. Check for tampering.');\n }\n\n mkdirSync(configDir, { recursive: true });\n\n const localServerPath = join(\n projectRoot,\n 'node_modules',\n '@stackwright-pro',\n 'mcp',\n 'dist',\n 'server.js'\n );\n\n // Resolve from raft's own node_modules — raft has @stackwright-pro/mcp as a\n // direct dep, so this is always available when running via `npx @stackwright-pro/raft`.\n // This is the reliable middle fallback: works even if the scaffolded project\n // never had mcp added to its own deps (e.g. old published launch-stackwright-pro).\n //\n // Note: require.resolve('@stackwright-pro/mcp') resolves via the `main` field\n // → dist/server.js. We cannot use the subpath './dist/server.js' directly\n // because it's not listed in the package's `exports` map.\n let raftOwnServerPath: string | null = null;\n try {\n raftOwnServerPath = require.resolve('@stackwright-pro/mcp');\n } catch {\n // mcp not resolvable from raft's own node_modules — unusual, fall through to npx\n }\n\n const serverConfig = existsSync(localServerPath)\n ? { type: 'stdio', command: 'node', args: [localServerPath] }\n : raftOwnServerPath !== null\n ? { type: 'stdio', command: 'node', args: [raftOwnServerPath] }\n : { type: 'stdio', command: 'npx', args: ['--yes', '@stackwright-pro/mcp@latest'] };\n\n // Read existing → merge, don't clobber other registered servers\n let existing: { mcp_servers?: Record<string, unknown> } = {};\n if (existsSync(configPath)) {\n try {\n const raw = readFileSync(configPath, 'utf-8');\n existing = JSON.parse(raw) as { mcp_servers?: Record<string, unknown> };\n } catch {\n // Malformed file — start fresh\n }\n }\n\n const merged = {\n ...existing,\n mcp_servers: {\n ...(existing.mcp_servers ?? {}),\n 'stackwright-pro': serverConfig,\n },\n };\n\n // Migration: remove the legacy 'stackwright' placeholder entry written by\n // scaffold-hooks@0.x. It pointed to @modelcontextprotocol/server-filesystem\n // with a literal '/path/to/dir' arg — never a real server, just a template\n // stub. Our auto-enable patch (stackwright-puppy Fix 1) now starts every\n // enabled server on launch, so leaving this entry causes an immediate\n // TaskGroup crash: \"ENOENT: no such file or directory, stat '/path/to/dir'\".\n //\n // We delete it unconditionally when the correct 'stackwright-pro' entry is\n // being written. If someone actually *wants* a server under the key\n // 'stackwright' they can add it back manually — but the placeholder never\n // represents a live server.\n //\n // See: CHANGES_FROM_UPSTREAM.md in stackwright-puppy (Fix 1 notes)\n if (merged.mcp_servers && 'stackwright' in merged.mcp_servers) {\n const stale = merged.mcp_servers['stackwright'] as Record<string, unknown>;\n const args = stale?.['args'] as unknown[] | undefined;\n const isPlaceholder =\n args?.includes('/path/to/dir') ||\n (stale?.['command'] === 'npx' &&\n (args as string[] | undefined)?.some((a) => String(a).includes('server-filesystem')));\n if (isPlaceholder) {\n delete merged.mcp_servers['stackwright'];\n log(\n 'Removed stale `stackwright` placeholder from mcp_servers.json ' +\n '(was: @modelcontextprotocol/server-filesystem /path/to/dir — not a real server)'\n );\n }\n }\n\n // Atomic write via .tmp rename swap\n const tmpPath = `${configPath}.tmp`;\n writeFileSync(tmpPath, JSON.stringify(merged, null, 2), 'utf-8');\n renameSync(tmpPath, configPath);\n\n log('MCP server registered → ~/.code_puppy/mcp_servers.json');\n}\n\n// ─── Print Resume Status ────────────────────────────────────────────────────\n\nexport function printResumeStatus(projectRoot: string): void {\n const pipelineStatePath = join(projectRoot, '.stackwright', 'pipeline-state.json');\n\n try {\n const raw = readFileSync(pipelineStatePath, 'utf-8');\n const state = JSON.parse(raw) as Record<string, unknown>;\n const status = state['status'];\n const phases = state['phases'];\n\n if (typeof phases !== 'object' || phases === null || Array.isArray(phases)) {\n return;\n }\n\n const phaseEntries = Object.values(phases as Record<string, Record<string, unknown>>);\n const totalPhases = phaseEntries.length || 8;\n\n switch (status) {\n case 'setup':\n log('📍 Starting fresh');\n break;\n case 'questions': {\n const answered = phaseEntries.filter((p) => p['answered'] === true).length;\n log(`📍 Resuming: questions phase (${answered}/${totalPhases} phases answered)`);\n break;\n }\n case 'execution': {\n const executed = phaseEntries.filter((p) => p['executed'] === true).length;\n log(`📍 Resuming: execution phase (${executed}/${totalPhases} phases complete)`);\n break;\n }\n case 'done':\n log('📍 Pipeline complete — re-entering to review');\n break;\n default:\n break;\n }\n } catch {\n // No pipeline state yet — fresh project\n }\n}\n\n// ─── Resolve Otter Directory ────────────────────────────────────────────────\n\nexport function resolveOtterDir(projectRoot: string): string | null {\n const candidates = [\n join(projectRoot, 'node_modules', '@stackwright-pro', 'otters', 'src'),\n join(projectRoot, 'packages', 'otters', 'src'),\n ];\n\n for (const candidate of candidates) {\n if (existsSync(candidate)) {\n return candidate;\n }\n }\n\n return null;\n}\n\n// ─── Sync Agents ────────────────────────────────────────────────────────────\n\n/**\n * Copy all *-otter.json files from the resolved otters package to\n * ~/.code_puppy/agents/ on every raft startup.\n *\n * This mirrors the pattern used by ensureMcpConfig() for mcp_servers.json.\n * Relying solely on the postinstall hook in @stackwright-pro/otters is fragile:\n * pnpm/npm don't always re-run scripts on package updates, and postinstall\n * order is non-deterministic when multiple packages run scripts. Active sync\n * on every raft launch guarantees agents are always the installed version.\n */\nexport function syncAgents(projectRoot: string, isVerbose: boolean = false): void {\n const xdgConfigHome = process.env['XDG_CONFIG_HOME'];\n const agentsDir = xdgConfigHome\n ? join(xdgConfigHome, 'code_puppy', 'agents')\n : join(homedir(), '.code_puppy', 'agents');\n\n const otterDir = resolveOtterDir(projectRoot);\n if (!otterDir) {\n verbose('No otters directory found — skipping agent sync', isVerbose);\n return;\n }\n\n // Symlink guard on agents dir\n if (existsSync(agentsDir) && lstatSync(agentsDir).isSymbolicLink()) {\n die('~/.code_puppy/agents is a symlink — refusing to write. Check for tampering.');\n }\n\n mkdirSync(agentsDir, { recursive: true });\n\n let synced = 0;\n let skipped = 0;\n\n try {\n const files = readdirSync(otterDir);\n for (const file of files) {\n if (!file.endsWith('-otter.json')) continue;\n\n const src = join(otterDir, file);\n const dest = join(agentsDir, file);\n\n // Symlink guard on individual file\n if (existsSync(dest) && lstatSync(dest).isSymbolicLink()) {\n verbose(`Skipping ${file} — dest is a symlink`, isVerbose);\n skipped++;\n continue;\n }\n\n // Atomic write: copy to .tmp then rename\n const tmp = `${dest}.tmp`;\n const content = readFileSync(src);\n writeFileSync(tmp, content);\n renameSync(tmp, dest);\n verbose(`Synced: ${file}`, isVerbose);\n synced++;\n }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n // Non-fatal: log and continue — a stale agent is better than a crash\n console.warn(`⚠️ Agent sync partial failure: ${msg}`);\n return;\n }\n\n if (synced > 0) {\n log(\n `Agents synced → ~/.code_puppy/agents/ (${synced} otters${skipped > 0 ? `, ${skipped} skipped` : ''})`\n );\n }\n}\n"],"mappings":"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","names":["import_fs","import_path","import_child_process"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stackwright-pro/raft",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.33",
|
|
4
4
|
"description": "Launch the Pro Otter Raft — verifies integrity, writes init context, spawns code-puppy in foreman mode",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"access": "public"
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"@stackwright-pro/mcp": "0.2.0-alpha.
|
|
20
|
+
"@stackwright-pro/mcp": "0.2.0-alpha.29"
|
|
21
21
|
},
|
|
22
22
|
"peerDependencies": {
|
|
23
23
|
"@stackwright-pro/otters": ">=1.0.0-alpha.29"
|