@stackmemoryai/stackmemory
Version:
Lossless, project-scoped memory for AI coding tools. Durable context across sessions with 56 MCP tools, FTS5 search, conductor orchestrator, loop/watch monitoring, snapshot capture, pre-flight overlap checks, Claude/Codex/OpenCode wrappers, Linear sync, a
88 lines (87 loc) • 3.07 kB
JavaScript
import { fileURLToPath as __fileURLToPath } from 'url';
import { dirname as __pathDirname } from 'path';
const __filename = __fileURLToPath(import.meta.url);
const __dirname = __pathDirname(__filename);
import { Command } from "commander";
import chalk from "chalk";
import {
PreflightChecker
} from "../../core/worktree/preflight.js";
function createPreflightCommand() {
const cmd = new Command("preflight").alias("pf").description("Check file overlap before running parallel tasks").argument("<tasks...>", "Task descriptions (quoted strings)").option(
"-k, --keywords <keywords>",
"Comma-separated keywords per task (task1:kw1,kw2;task2:kw3)"
).option(
"-f, --files <files>",
"Comma-separated files per task (task1:file1,file2;task2:file3)"
).option("--json", "Output as JSON").action((taskArgs, options) => {
const checker = new PreflightChecker();
const tasks = taskArgs.map((desc, i) => {
const task = {
name: `task-${i + 1}`,
description: desc
};
if (options.keywords) {
const kwParts = options.keywords.split(";");
if (kwParts[i]) {
const [, kws] = kwParts[i].split(":");
if (kws) task.keywords = kws.split(",");
}
}
if (options.files) {
const fileParts = options.files.split(";");
if (fileParts[i]) {
const [, fs] = fileParts[i].split(":");
if (fs) task.files = fs.split(",");
}
}
if (desc.length <= 40) {
task.name = desc;
}
return task;
});
const result = checker.check(tasks);
if (options.json) {
console.log(JSON.stringify(result, null, 2));
return;
}
console.log(chalk.cyan("\nPre-flight Check\n"));
console.log(chalk.gray(`Tasks: ${tasks.length}`));
console.log(chalk.gray(`Overlaps: ${result.allOverlaps.length}
`));
if (result.parallelSafe.length === 1 && result.allOverlaps.length === 0) {
console.log(chalk.green("All tasks are parallel-safe.\n"));
for (const task of result.parallelSafe[0]) {
console.log(chalk.green(` + ${task.name}`));
}
} else {
for (let i = 0; i < result.parallelSafe.length; i++) {
const group = result.parallelSafe[i];
console.log(chalk.cyan(`Group ${i + 1} (parallel-safe):`));
for (const task of group) {
console.log(chalk.green(` + ${task.name}`));
}
}
}
if (result.sequential.length > 0) {
console.log(chalk.yellow("\nSequential (file overlaps detected):"));
for (const entry of result.sequential) {
console.log(
chalk.yellow(` "${entry.task.name}" -> after "${entry.after}"`)
);
for (const overlap of entry.overlaps.slice(0, 5)) {
const conf = Math.round(overlap.confidence * 100);
console.log(
chalk.gray(` ${overlap.file} (${overlap.source}, ${conf}%)`)
);
}
}
}
console.log(chalk.gray(`
${result.summary}`));
});
return cmd;
}
export {
createPreflightCommand
};