archondev 2.3.0 → 2.4.0

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/dist/index.js CHANGED
@@ -10,8 +10,10 @@ import {
10
10
  import {
11
11
  parallelClean,
12
12
  parallelMerge,
13
+ parallelRunWaves,
14
+ parallelSchedule,
13
15
  parallelStatus
14
- } from "./chunk-OI4K3RYO.js";
16
+ } from "./chunk-Y5LQX7LK.js";
15
17
  import {
16
18
  DependencyParser,
17
19
  EnvironmentConfigLoader,
@@ -20,7 +22,7 @@ import {
20
22
  cloudLogs,
21
23
  cloudStatus,
22
24
  execute
23
- } from "./chunk-HGO4UUAC.js";
25
+ } from "./chunk-6TCM6JYX.js";
24
26
  import {
25
27
  list
26
28
  } from "./chunk-7FJ4ATJE.js";
@@ -82,7 +84,7 @@ import "./chunk-QGM4M3NI.js";
82
84
 
83
85
  // src/cli/index.ts
84
86
  import { Command as Command4 } from "commander";
85
- import chalk15 from "chalk";
87
+ import chalk17 from "chalk";
86
88
  import "dotenv/config";
87
89
 
88
90
  // src/cli/promote.ts
@@ -3183,7 +3185,7 @@ async function executeNext() {
3183
3185
  const atomId = await prompt("Enter atom ID to execute (or press Enter for first pending)");
3184
3186
  const targetId = atomId.trim() || pendingAtoms[0]?.id;
3185
3187
  if (targetId) {
3186
- const { execute: execute2 } = await import("./execute-6D6USH33.js");
3188
+ const { execute: execute2 } = await import("./execute-465TGOYD.js");
3187
3189
  await execute2(targetId, {});
3188
3190
  } else {
3189
3191
  console.log(chalk4.yellow("No atom to execute."));
@@ -6889,13 +6891,432 @@ async function generateAtoms(options = {}) {
6889
6891
  console.log();
6890
6892
  }
6891
6893
 
6894
+ // src/cli/eject.ts
6895
+ import chalk15 from "chalk";
6896
+ import { existsSync as existsSync15, rmSync } from "fs";
6897
+ import { readFile as readFile11, writeFile as writeFile9 } from "fs/promises";
6898
+ import { join as join15 } from "path";
6899
+ import readline3 from "readline";
6900
+ var ARCHON_FILES = [
6901
+ ".archon/",
6902
+ "prd.json",
6903
+ "progress.txt",
6904
+ "prompt.md"
6905
+ ];
6906
+ var METADATA_FILES = [
6907
+ "package.json",
6908
+ "README.md"
6909
+ ];
6910
+ async function eject(options = {}) {
6911
+ const cwd = process.cwd();
6912
+ console.log(chalk15.blue("\n\u{1F680} ArchonDev Eject\n"));
6913
+ const archonDir = join15(cwd, ".archon");
6914
+ if (!existsSync15(archonDir)) {
6915
+ console.log(chalk15.yellow("This does not appear to be an ArchonDev project (.archon/ not found)."));
6916
+ return;
6917
+ }
6918
+ console.log(chalk15.dim("The following will be removed/modified:\n"));
6919
+ const filesToRemove = [];
6920
+ for (const file of ARCHON_FILES) {
6921
+ const filePath = join15(cwd, file);
6922
+ if (existsSync15(filePath)) {
6923
+ filesToRemove.push(file);
6924
+ console.log(chalk15.red(` \u2717 ${file}`));
6925
+ }
6926
+ }
6927
+ const archMd = join15(cwd, "ARCHITECTURE.md");
6928
+ if (existsSync15(archMd) && !options.keepArchitecture) {
6929
+ console.log(chalk15.yellow(` ? ARCHITECTURE.md (will be kept by default)`));
6930
+ }
6931
+ console.log();
6932
+ console.log(chalk15.dim("Files to be modified:"));
6933
+ for (const file of METADATA_FILES) {
6934
+ const filePath = join15(cwd, file);
6935
+ if (existsSync15(filePath)) {
6936
+ console.log(chalk15.yellow(` \u25CF ${file}`));
6937
+ }
6938
+ }
6939
+ console.log();
6940
+ if (!options.force) {
6941
+ const confirmed = await promptYesNo3("This will permanently remove ArchonDev from your project. Continue?", false);
6942
+ if (!confirmed) {
6943
+ console.log(chalk15.dim("Eject cancelled."));
6944
+ return;
6945
+ }
6946
+ }
6947
+ console.log();
6948
+ const result = await performEject(cwd, options);
6949
+ if (result.success) {
6950
+ console.log(chalk15.green("\n\u2705 Eject complete!\n"));
6951
+ if (result.filesRemoved.length > 0) {
6952
+ console.log(chalk15.dim("Removed:"));
6953
+ for (const file of result.filesRemoved) {
6954
+ console.log(chalk15.dim(` - ${file}`));
6955
+ }
6956
+ }
6957
+ if (result.filesModified.length > 0) {
6958
+ console.log(chalk15.dim("\nModified:"));
6959
+ for (const file of result.filesModified) {
6960
+ console.log(chalk15.dim(` - ${file}`));
6961
+ }
6962
+ }
6963
+ if (result.warnings.length > 0) {
6964
+ console.log(chalk15.yellow("\nWarnings:"));
6965
+ for (const warning of result.warnings) {
6966
+ console.log(chalk15.yellow(` \u26A0\uFE0F ${warning}`));
6967
+ }
6968
+ }
6969
+ console.log();
6970
+ console.log(chalk15.blue("Your project is now a standard repository."));
6971
+ console.log(chalk15.dim("Thank you for using ArchonDev!"));
6972
+ } else {
6973
+ console.log(chalk15.red("\n\u274C Eject failed."));
6974
+ for (const warning of result.warnings) {
6975
+ console.log(chalk15.red(` ${warning}`));
6976
+ }
6977
+ }
6978
+ }
6979
+ async function performEject(cwd, options) {
6980
+ const result = {
6981
+ success: true,
6982
+ filesRemoved: [],
6983
+ filesModified: [],
6984
+ warnings: []
6985
+ };
6986
+ const archonDir = join15(cwd, ".archon");
6987
+ if (existsSync15(archonDir)) {
6988
+ try {
6989
+ rmSync(archonDir, { recursive: true, force: true });
6990
+ result.filesRemoved.push(".archon/");
6991
+ } catch (error) {
6992
+ result.warnings.push(`Failed to remove .archon/: ${error instanceof Error ? error.message : "Unknown error"}`);
6993
+ }
6994
+ }
6995
+ const prdPath = join15(cwd, "prd.json");
6996
+ if (existsSync15(prdPath)) {
6997
+ try {
6998
+ rmSync(prdPath);
6999
+ result.filesRemoved.push("prd.json");
7000
+ } catch (error) {
7001
+ result.warnings.push(`Failed to remove prd.json: ${error instanceof Error ? error.message : "Unknown error"}`);
7002
+ }
7003
+ }
7004
+ const progressPath = join15(cwd, "progress.txt");
7005
+ if (existsSync15(progressPath)) {
7006
+ try {
7007
+ rmSync(progressPath);
7008
+ result.filesRemoved.push("progress.txt");
7009
+ } catch (error) {
7010
+ result.warnings.push(`Failed to remove progress.txt: ${error instanceof Error ? error.message : "Unknown error"}`);
7011
+ }
7012
+ }
7013
+ const promptPath = join15(cwd, "prompt.md");
7014
+ if (existsSync15(promptPath)) {
7015
+ try {
7016
+ rmSync(promptPath);
7017
+ result.filesRemoved.push("prompt.md");
7018
+ } catch (error) {
7019
+ result.warnings.push(`Failed to remove prompt.md: ${error instanceof Error ? error.message : "Unknown error"}`);
7020
+ }
7021
+ }
7022
+ const pkgPath = join15(cwd, "package.json");
7023
+ if (existsSync15(pkgPath)) {
7024
+ try {
7025
+ const pkgContent = await readFile11(pkgPath, "utf-8");
7026
+ const pkg = JSON.parse(pkgContent);
7027
+ let modified = false;
7028
+ if ("archondev" in pkg) {
7029
+ delete pkg["archondev"];
7030
+ modified = true;
7031
+ }
7032
+ const scripts = pkg["scripts"];
7033
+ if (scripts) {
7034
+ for (const key of Object.keys(scripts)) {
7035
+ if (key.startsWith("archon") || scripts[key]?.includes("archon")) {
7036
+ delete scripts[key];
7037
+ modified = true;
7038
+ }
7039
+ }
7040
+ }
7041
+ if (modified) {
7042
+ await writeFile9(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
7043
+ result.filesModified.push("package.json");
7044
+ }
7045
+ } catch (error) {
7046
+ result.warnings.push(`Failed to clean package.json: ${error instanceof Error ? error.message : "Unknown error"}`);
7047
+ }
7048
+ }
7049
+ if (!options.keepReadme) {
7050
+ const readmePath = join15(cwd, "README.md");
7051
+ if (existsSync15(readmePath)) {
7052
+ try {
7053
+ const content = await readFile11(readmePath, "utf-8");
7054
+ const archonPatterns = [
7055
+ /## ArchonDev[^#]*(?=##|$)/gi,
7056
+ /\*This project was scaffolded by ArchonDev\.\*/gi,
7057
+ /<!-- ArchonDev:.*?-->/gi,
7058
+ /\[!\[ArchonDev\].*?\]\(.*?\)/gi
7059
+ ];
7060
+ let newContent = content;
7061
+ let modified = false;
7062
+ for (const pattern of archonPatterns) {
7063
+ if (pattern.test(newContent)) {
7064
+ newContent = newContent.replace(pattern, "");
7065
+ modified = true;
7066
+ }
7067
+ }
7068
+ newContent = newContent.replace(/\n{3,}/g, "\n\n").trim() + "\n";
7069
+ if (modified) {
7070
+ await writeFile9(readmePath, newContent);
7071
+ result.filesModified.push("README.md");
7072
+ }
7073
+ } catch (error) {
7074
+ result.warnings.push(`Failed to clean README.md: ${error instanceof Error ? error.message : "Unknown error"}`);
7075
+ }
7076
+ }
7077
+ }
7078
+ return result;
7079
+ }
7080
+ async function ejectDryRun() {
7081
+ const cwd = process.cwd();
7082
+ console.log(chalk15.blue("\n\u{1F50D} Eject Dry Run\n"));
7083
+ const archonDir = join15(cwd, ".archon");
7084
+ if (!existsSync15(archonDir)) {
7085
+ console.log(chalk15.yellow("This does not appear to be an ArchonDev project."));
7086
+ return;
7087
+ }
7088
+ console.log("The following would be removed:\n");
7089
+ for (const file of ARCHON_FILES) {
7090
+ const filePath = join15(cwd, file);
7091
+ if (existsSync15(filePath)) {
7092
+ console.log(chalk15.red(` \u2717 ${file}`));
7093
+ }
7094
+ }
7095
+ console.log();
7096
+ console.log("The following would be modified:\n");
7097
+ for (const file of METADATA_FILES) {
7098
+ const filePath = join15(cwd, file);
7099
+ if (existsSync15(filePath)) {
7100
+ console.log(chalk15.yellow(` \u25CF ${file}`));
7101
+ }
7102
+ }
7103
+ console.log();
7104
+ console.log(chalk15.dim('Run "archon eject" to proceed.'));
7105
+ }
7106
+ function promptYesNo3(question, defaultValue) {
7107
+ return new Promise((resolve) => {
7108
+ const rl = readline3.createInterface({
7109
+ input: process.stdin,
7110
+ output: process.stdout
7111
+ });
7112
+ const hint = defaultValue ? "(Y/n)" : "(y/N)";
7113
+ rl.question(`${chalk15.cyan("?")} ${question} ${hint}: `, (answer) => {
7114
+ rl.close();
7115
+ if (answer.trim() === "") {
7116
+ resolve(defaultValue);
7117
+ } else {
7118
+ resolve(answer.toLowerCase().startsWith("y"));
7119
+ }
7120
+ });
7121
+ });
7122
+ }
7123
+
7124
+ // src/cli/revert.ts
7125
+ import chalk16 from "chalk";
7126
+ import { execSync as execSync3 } from "child_process";
7127
+ import { existsSync as existsSync16 } from "fs";
7128
+ import { readFile as readFile12, writeFile as writeFile10 } from "fs/promises";
7129
+ import { join as join16 } from "path";
7130
+ import readline4 from "readline";
7131
+ async function findAtomCommits(limit = 50) {
7132
+ const cwd = process.cwd();
7133
+ try {
7134
+ const logOutput = execSync3(
7135
+ `git log --oneline --no-merges -n ${limit} --format="%H|%s|%ai|%an"`,
7136
+ { cwd, encoding: "utf-8" }
7137
+ );
7138
+ const commits = [];
7139
+ const lines = logOutput.trim().split("\n").filter(Boolean);
7140
+ for (const line of lines) {
7141
+ const parts = line.split("|");
7142
+ if (parts.length < 4) continue;
7143
+ const [hash, message, date, author] = parts;
7144
+ if (!hash || !message) continue;
7145
+ const atomMatch = message.match(/\[([A-Z]+-\d+|US-\d+)\]|Atom #([A-Za-z0-9-]+)/i);
7146
+ if (atomMatch) {
7147
+ const atomId = atomMatch[1] ?? atomMatch[2] ?? "unknown";
7148
+ let filesChanged = 0;
7149
+ try {
7150
+ const statOutput = execSync3(
7151
+ `git diff --shortstat ${hash}^..${hash}`,
7152
+ { cwd, encoding: "utf-8" }
7153
+ );
7154
+ const filesMatch = statOutput.match(/(\d+) files? changed/);
7155
+ filesChanged = filesMatch ? parseInt(filesMatch[1] ?? "0", 10) : 0;
7156
+ } catch {
7157
+ }
7158
+ commits.push({
7159
+ atomId,
7160
+ commitHash: hash,
7161
+ message: message ?? "",
7162
+ date: date ?? "",
7163
+ author: author ?? "",
7164
+ filesChanged
7165
+ });
7166
+ }
7167
+ }
7168
+ return commits;
7169
+ } catch (error) {
7170
+ console.error(chalk16.red("Failed to read git history:"), error instanceof Error ? error.message : "Unknown error");
7171
+ return [];
7172
+ }
7173
+ }
7174
+ async function historyCommand(options) {
7175
+ const limit = options.limit ?? 20;
7176
+ console.log(chalk16.blue("\n\u{1F4DC} Atom Execution History\n"));
7177
+ const commits = await findAtomCommits(limit);
7178
+ if (commits.length === 0) {
7179
+ console.log(chalk16.dim("No atom commits found in git history."));
7180
+ console.log(chalk16.dim('Atom commits are created when you run "archon execute <atom-id>".'));
7181
+ return;
7182
+ }
7183
+ console.log(chalk16.dim(`Showing ${commits.length} atom commit(s):
7184
+ `));
7185
+ for (const commit of commits) {
7186
+ const shortHash = commit.commitHash.substring(0, 7);
7187
+ const filesLabel = commit.filesChanged === 1 ? "file" : "files";
7188
+ console.log(`${chalk16.yellow(shortHash)} ${chalk16.cyan(commit.atomId)}`);
7189
+ console.log(chalk16.dim(` ${commit.message}`));
7190
+ console.log(chalk16.dim(` ${commit.date} | ${commit.filesChanged} ${filesLabel} changed`));
7191
+ console.log();
7192
+ }
7193
+ console.log(chalk16.dim("To revert an atom: archon revert <atom-id>"));
7194
+ console.log(chalk16.dim("Or by commit hash: archon revert --commit <hash>"));
7195
+ }
7196
+ async function revertCommand(atomIdOrHash, options = {}) {
7197
+ const cwd = process.cwd();
7198
+ console.log(chalk16.blue("\n\u23EA Atom Revert\n"));
7199
+ let commit;
7200
+ if (atomIdOrHash.match(/^[a-f0-9]{7,40}$/i)) {
7201
+ const commits = await findAtomCommits(100);
7202
+ commit = commits.find((c) => c.commitHash.startsWith(atomIdOrHash));
7203
+ } else {
7204
+ const commits = await findAtomCommits(100);
7205
+ commit = commits.find((c) => c.atomId.toLowerCase() === atomIdOrHash.toLowerCase());
7206
+ }
7207
+ if (!commit) {
7208
+ console.log(chalk16.red(`No atom commit found for: ${atomIdOrHash}`));
7209
+ console.log(chalk16.dim('Run "archon history" to see available atom commits.'));
7210
+ return;
7211
+ }
7212
+ console.log(`Atom: ${chalk16.cyan(commit.atomId)}`);
7213
+ console.log(`Commit: ${chalk16.yellow(commit.commitHash.substring(0, 7))}`);
7214
+ console.log(`Message: ${commit.message}`);
7215
+ console.log(`Date: ${commit.date}`);
7216
+ console.log(`Files changed: ${commit.filesChanged}`);
7217
+ console.log();
7218
+ try {
7219
+ console.log(chalk16.dim("Changes to be reverted:"));
7220
+ const diffStat = execSync3(
7221
+ `git diff --stat ${commit.commitHash}^..${commit.commitHash}`,
7222
+ { cwd, encoding: "utf-8" }
7223
+ );
7224
+ console.log(chalk16.dim(diffStat));
7225
+ } catch {
7226
+ }
7227
+ if (!options.force) {
7228
+ const confirmed = await promptYesNo4("Revert this atom commit?", false);
7229
+ if (!confirmed) {
7230
+ console.log(chalk16.dim("Revert cancelled."));
7231
+ return;
7232
+ }
7233
+ }
7234
+ try {
7235
+ const revertArgs = options.noCommit ? "--no-commit" : "";
7236
+ execSync3(`git revert ${revertArgs} ${commit.commitHash}`, { cwd, stdio: "pipe" });
7237
+ console.log(chalk16.green(`
7238
+ \u2705 Successfully reverted ${commit.atomId}`));
7239
+ if (options.noCommit) {
7240
+ console.log(chalk16.dim("Changes are staged but not committed."));
7241
+ console.log(chalk16.dim('Run "git commit" to finalize the revert.'));
7242
+ } else {
7243
+ console.log(chalk16.dim("A new commit has been created to undo the changes."));
7244
+ }
7245
+ await updateAtomStatus(commit.atomId, "REVERTED");
7246
+ } catch (error) {
7247
+ const errorMsg = error instanceof Error ? error.message : "Unknown error";
7248
+ if (errorMsg.includes("conflict")) {
7249
+ console.log(chalk16.yellow("\n\u26A0\uFE0F Merge conflict detected during revert."));
7250
+ console.log(chalk16.dim("Resolve conflicts manually, then:"));
7251
+ console.log(chalk16.dim(" git add ."));
7252
+ console.log(chalk16.dim(" git revert --continue"));
7253
+ } else {
7254
+ console.log(chalk16.red("\n\u274C Revert failed:"), errorMsg);
7255
+ console.log(chalk16.dim("You may need to resolve this manually."));
7256
+ }
7257
+ }
7258
+ }
7259
+ async function updateAtomStatus(atomId, status2) {
7260
+ const atomPath = join16(process.cwd(), ".archon", "atoms", `${atomId}.json`);
7261
+ if (!existsSync16(atomPath)) {
7262
+ return;
7263
+ }
7264
+ try {
7265
+ const content = await readFile12(atomPath, "utf-8");
7266
+ const atom = JSON.parse(content);
7267
+ atom["status"] = status2;
7268
+ atom["revertedAt"] = (/* @__PURE__ */ new Date()).toISOString();
7269
+ await writeFile10(atomPath, JSON.stringify(atom, null, 2));
7270
+ } catch {
7271
+ }
7272
+ }
7273
+ async function revertableAtoms() {
7274
+ console.log(chalk16.blue("\n\u{1F504} Revertable Atoms\n"));
7275
+ const commits = await findAtomCommits(30);
7276
+ if (commits.length === 0) {
7277
+ console.log(chalk16.dim("No atom commits found."));
7278
+ return;
7279
+ }
7280
+ const atomMap = /* @__PURE__ */ new Map();
7281
+ for (const commit of commits) {
7282
+ if (!atomMap.has(commit.atomId)) {
7283
+ atomMap.set(commit.atomId, commit);
7284
+ }
7285
+ }
7286
+ console.log(chalk16.dim(`Found ${atomMap.size} unique atom(s) in history:
7287
+ `));
7288
+ for (const [atomId, commit] of atomMap) {
7289
+ const shortHash = commit.commitHash.substring(0, 7);
7290
+ console.log(` ${chalk16.cyan(atomId)} ${chalk16.dim(`(${shortHash})`)} - ${commit.message.substring(0, 50)}`);
7291
+ }
7292
+ console.log();
7293
+ console.log(chalk16.dim("To revert: archon revert <atom-id>"));
7294
+ }
7295
+ function promptYesNo4(question, defaultValue) {
7296
+ return new Promise((resolve) => {
7297
+ const rl = readline4.createInterface({
7298
+ input: process.stdin,
7299
+ output: process.stdout
7300
+ });
7301
+ const hint = defaultValue ? "(Y/n)" : "(y/N)";
7302
+ rl.question(`${chalk16.cyan("?")} ${question} ${hint}: `, (answer) => {
7303
+ rl.close();
7304
+ if (answer.trim() === "") {
7305
+ resolve(defaultValue);
7306
+ } else {
7307
+ resolve(answer.toLowerCase().startsWith("y"));
7308
+ }
7309
+ });
7310
+ });
7311
+ }
7312
+
6892
7313
  // src/cli/index.ts
6893
7314
  var program = new Command4();
6894
7315
  program.name("archon").description("Local-first AI-powered development governance").version("1.1.0").action(async () => {
6895
7316
  const cwd = process.cwd();
6896
7317
  const wasInitialized = isInitialized(cwd);
6897
7318
  if (!wasInitialized) {
6898
- console.log(chalk15.blue("\nArchonDev is not initialized in this folder.\n"));
7319
+ console.log(chalk17.blue("\nArchonDev is not initialized in this folder.\n"));
6899
7320
  await init({ analyze: true, git: true });
6900
7321
  }
6901
7322
  await start({ skipGovernanceBanner: !wasInitialized });
@@ -6903,7 +7324,7 @@ program.name("archon").description("Local-first AI-powered development governanc
6903
7324
  program.command("login").description("Authenticate with ArchonDev").option("-p, --provider <provider>", "OAuth provider (github or google)", "github").action(async (options) => {
6904
7325
  const provider = options.provider;
6905
7326
  if (provider !== "github" && provider !== "google") {
6906
- console.error(chalk15.red('Invalid provider. Use "github" or "google"'));
7327
+ console.error(chalk17.red('Invalid provider. Use "github" or "google"'));
6907
7328
  process.exit(1);
6908
7329
  }
6909
7330
  await login(provider);
@@ -7077,6 +7498,8 @@ var parallelCmd = program.command("parallel").description("Parallel agent execut
7077
7498
  parallelCmd.command("status").description("Show status of all parallel executions").action(parallelStatus);
7078
7499
  parallelCmd.command("merge [atomId]").description("Merge completed worktrees back to main").action(parallelMerge);
7079
7500
  parallelCmd.command("clean").description("Clean up all parallel execution state and worktrees").action(parallelClean);
7501
+ parallelCmd.command("schedule").description("Analyze atom dependencies and show execution schedule").option("--mermaid", "Output dependency graph as mermaid diagram").option("--max-parallelism <n>", "Maximum atoms per wave", parseInt).option("--only-ready", "Only include READY atoms").action(parallelSchedule);
7502
+ parallelCmd.command("run-waves").description("Execute all READY atoms in dependency-ordered waves").option("--max-parallelism <n>", "Maximum atoms per wave", parseInt).option("--dry-run", "Show execution plan without running").action(parallelRunWaves);
7080
7503
  parallelCmd.action(parallelStatus);
7081
7504
  var githubCmd = program.command("github").description("GitHub integration for cloud execution");
7082
7505
  githubCmd.command("connect").description("Connect your GitHub account for cloud execution").action(githubConnect);
@@ -7088,7 +7511,7 @@ cleanupCmd.command("check").description("Analyze workspace for bloat and mainten
7088
7511
  cleanupCmd.command("run").description("Execute cleanup (archive old entries, remove stale files)").action(cleanupRun);
7089
7512
  cleanupCmd.command("auto").description("Enable/disable automatic cleanup checks").argument("[action]", "enable, disable, or status", "status").action(async (action) => {
7090
7513
  if (action !== "enable" && action !== "disable" && action !== "status") {
7091
- console.error(chalk15.red("Invalid action. Use: enable, disable, or status"));
7514
+ console.error(chalk17.red("Invalid action. Use: enable, disable, or status"));
7092
7515
  process.exit(1);
7093
7516
  }
7094
7517
  await cleanupAuto(action);
@@ -7113,4 +7536,14 @@ interviewCmd.action(async () => {
7113
7536
  program.command("generate").description("Generate atoms from Constitution (alias for interview generate)").option("--include-post-mvp", "Include POST_MVP features").option("--dry-run", "Show what would be generated without writing files").option("-o, --output <path>", "Output path for prd.json").action(async (options) => {
7114
7537
  await generateAtoms(options);
7115
7538
  });
7539
+ program.command("eject").description("Remove all ArchonDev metadata, leaving a clean standalone codebase").option("--force", "Skip confirmation prompt").option("--keep-architecture", "Keep ARCHITECTURE.md file").option("--keep-readme", "Do not modify README.md").option("--dry-run", "Show what would be ejected without doing it").action(async (options) => {
7540
+ if (options.dryRun) {
7541
+ await ejectDryRun();
7542
+ } else {
7543
+ await eject(options);
7544
+ }
7545
+ });
7546
+ program.command("history").description("Show atom execution history from git commits").option("-n, --limit <n>", "Number of commits to show", parseInt).action(historyCommand);
7547
+ program.command("revert <atomIdOrHash>").description("Revert a specific atom execution by atom ID or commit hash").option("--force", "Skip confirmation prompt").option("--no-commit", "Stage changes but do not create revert commit").action(revertCommand);
7548
+ program.command("revertable").description("List atoms that can be reverted").action(revertableAtoms);
7116
7549
  program.parse();
@@ -2,8 +2,10 @@ import {
2
2
  parallelClean,
3
3
  parallelExecute,
4
4
  parallelMerge,
5
+ parallelRunWaves,
6
+ parallelSchedule,
5
7
  parallelStatus
6
- } from "./chunk-OI4K3RYO.js";
8
+ } from "./chunk-Y5LQX7LK.js";
7
9
  import "./chunk-5HVYNCLT.js";
8
10
  import "./chunk-5IQKC2TD.js";
9
11
  import "./chunk-SMR7JQK6.js";
@@ -15,5 +17,7 @@ export {
15
17
  parallelClean,
16
18
  parallelExecute,
17
19
  parallelMerge,
20
+ parallelRunWaves,
21
+ parallelSchedule,
18
22
  parallelStatus
19
23
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "archondev",
3
- "version": "2.3.0",
3
+ "version": "2.4.0",
4
4
  "description": "Local-first AI-powered development governance system",
5
5
  "main": "dist/index.js",
6
6
  "bin": {