Add new skills and utilities for enhanced writing and testing
- Introduced graphviz conventions for visualizing process flows in writing skills. - Added a comprehensive guide on persuasion principles to improve skill design effectiveness. - Implemented a script to render graphviz diagrams from markdown files to SVG format. - Created a detailed reference for testing skills with subagents, emphasizing TDD principles. - Established a task tracker template for live task management. - Developed a shell script to check the integrity of the antigravity profile and required files. - Added test scripts to validate the initialization of agent projects. - Created workflows for brainstorming, executing plans, and writing plans to streamline processes.
This commit is contained in:
37
src/cli.js
Normal file
37
src/cli.js
Normal file
@@ -0,0 +1,37 @@
|
||||
import { initCommand } from "./commands/init.js";
|
||||
|
||||
function helpText() {
|
||||
return [
|
||||
"antigravity-superpowers",
|
||||
"",
|
||||
"Usage:",
|
||||
" antigravity-superpowers init [target-directory] [--force]",
|
||||
"",
|
||||
"Commands:",
|
||||
" init Initialize .agent profile in a project",
|
||||
"",
|
||||
"Options:",
|
||||
" -f, --force Overwrite existing .agent directory",
|
||||
" -h, --help Show help",
|
||||
].join("\n");
|
||||
}
|
||||
|
||||
export async function runCli(args, io = process) {
|
||||
const [command, ...rest] = args;
|
||||
|
||||
if (!command || command === "-h" || command === "--help" || command === "help") {
|
||||
io.stdout.write(`${helpText()}\n`);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (command === "init") {
|
||||
return initCommand(rest, {
|
||||
cwd: io.cwd?.() ?? process.cwd(),
|
||||
stdout: io.stdout,
|
||||
stderr: io.stderr,
|
||||
});
|
||||
}
|
||||
|
||||
io.stderr.write(`Unknown command: ${command}\n\n${helpText()}\n`);
|
||||
return 1;
|
||||
}
|
||||
109
src/commands/init.js
Normal file
109
src/commands/init.js
Normal file
@@ -0,0 +1,109 @@
|
||||
import { access, cp, rm, stat } from "node:fs/promises";
|
||||
import { constants as fsConstants } from "node:fs";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { join, resolve } from "node:path";
|
||||
|
||||
function getTemplateDir() {
|
||||
return fileURLToPath(new URL("../../templates/.agent", import.meta.url));
|
||||
}
|
||||
|
||||
async function exists(path) {
|
||||
try {
|
||||
await access(path, fsConstants.F_OK);
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function parseInitArgs(args) {
|
||||
const parsed = {
|
||||
target: ".",
|
||||
force: false,
|
||||
};
|
||||
let targetSet = false;
|
||||
|
||||
for (const arg of args) {
|
||||
if (arg === "--force" || arg === "-f") {
|
||||
parsed.force = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (arg.startsWith("-")) {
|
||||
throw new Error(`Unknown option for init: ${arg}`);
|
||||
}
|
||||
|
||||
if (targetSet) {
|
||||
throw new Error("Too many positional arguments. Only one target directory is supported.");
|
||||
}
|
||||
|
||||
parsed.target = arg;
|
||||
targetSet = true;
|
||||
}
|
||||
|
||||
return parsed;
|
||||
}
|
||||
|
||||
async function validateTargetDir(targetDir) {
|
||||
let targetStat;
|
||||
try {
|
||||
targetStat = await stat(targetDir);
|
||||
} catch {
|
||||
throw new Error(`Target directory does not exist: ${targetDir}`);
|
||||
}
|
||||
|
||||
if (!targetStat.isDirectory()) {
|
||||
throw new Error(`Target path is not a directory: ${targetDir}`);
|
||||
}
|
||||
}
|
||||
|
||||
export async function initCommand(args, { cwd, stdout, stderr }) {
|
||||
let parsed;
|
||||
try {
|
||||
parsed = parseInitArgs(args);
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : String(error);
|
||||
stderr.write(`${message}\n`);
|
||||
return 1;
|
||||
}
|
||||
|
||||
const targetDir = resolve(cwd, parsed.target);
|
||||
const agentDir = join(targetDir, ".agent");
|
||||
const templateDir = getTemplateDir();
|
||||
|
||||
try {
|
||||
await validateTargetDir(targetDir);
|
||||
|
||||
const templateExists = await exists(templateDir);
|
||||
if (!templateExists) {
|
||||
throw new Error(
|
||||
"Bundled template is missing. Run `npm run sync:template` before using init from source.",
|
||||
);
|
||||
}
|
||||
|
||||
const agentExists = await exists(agentDir);
|
||||
if (agentExists && !parsed.force) {
|
||||
stderr.write(
|
||||
`.agent already exists at ${agentDir}. Re-run with --force to replace it.\n`,
|
||||
);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (agentExists && parsed.force) {
|
||||
await rm(agentDir, { recursive: true, force: true });
|
||||
}
|
||||
|
||||
await cp(templateDir, agentDir, { recursive: true });
|
||||
|
||||
stdout.write(`Initialized Antigravity Superpowers profile at ${agentDir}\n`);
|
||||
stdout.write("Next step: bash .agent/tests/run-tests.sh\n");
|
||||
stdout.write(
|
||||
"Note: docs/plans/task.md is created at runtime by skills when task tracking starts.\n",
|
||||
);
|
||||
return 0;
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : String(error);
|
||||
stderr.write(`Init failed: ${message}\n`);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user