aiblueprint-cli 1.4.24 → 1.4.25

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.
Files changed (20) hide show
  1. package/claude-code-config/skills/workflow-apex-free/SKILL.md +261 -0
  2. package/claude-code-config/skills/workflow-apex-free/scripts/setup-templates.sh +100 -0
  3. package/claude-code-config/skills/workflow-apex-free/scripts/update-progress.sh +80 -0
  4. package/claude-code-config/skills/workflow-apex-free/steps/step-00-init.md +267 -0
  5. package/claude-code-config/skills/workflow-apex-free/steps/step-00b-branch.md +126 -0
  6. package/claude-code-config/skills/workflow-apex-free/steps/step-00b-economy.md +244 -0
  7. package/claude-code-config/skills/workflow-apex-free/steps/step-00b-interactive.md +153 -0
  8. package/claude-code-config/skills/workflow-apex-free/steps/step-01-analyze.md +361 -0
  9. package/claude-code-config/skills/workflow-apex-free/steps/step-02-plan.md +264 -0
  10. package/claude-code-config/skills/workflow-apex-free/steps/step-03-execute.md +239 -0
  11. package/claude-code-config/skills/workflow-apex-free/steps/step-04-validate.md +251 -0
  12. package/claude-code-config/skills/workflow-apex-free/templates/00-context.md +43 -0
  13. package/claude-code-config/skills/workflow-apex-free/templates/01-analyze.md +10 -0
  14. package/claude-code-config/skills/workflow-apex-free/templates/02-plan.md +10 -0
  15. package/claude-code-config/skills/workflow-apex-free/templates/03-execute.md +10 -0
  16. package/claude-code-config/skills/workflow-apex-free/templates/04-validate.md +10 -0
  17. package/claude-code-config/skills/workflow-apex-free/templates/README.md +176 -0
  18. package/claude-code-config/skills/workflow-apex-free/templates/step-complete.md +7 -0
  19. package/dist/cli.js +146 -9
  20. package/package.json +1 -1
@@ -0,0 +1,176 @@
1
+ # APEX Template System
2
+
3
+ ## Overview
4
+
5
+ This directory contains template files used to initialize APEX workflow outputs when save mode (`-s`) is enabled. This template system significantly reduces token usage by moving repetitive content out of step files.
6
+
7
+ ## Template Files
8
+
9
+ | Template | Purpose | Created When |
10
+ |----------|---------|--------------|
11
+ | `00-context.md` | Workflow configuration and progress tracking | Always (if save_mode) |
12
+ | `01-analyze.md` | Analysis findings | Always (if save_mode) |
13
+ | `02-plan.md` | Implementation plan | Always (if save_mode) |
14
+ | `03-execute.md` | Implementation log | Always (if save_mode) |
15
+ | `04-validate.md` | Validation results and workflow completion | Always (if save_mode) |
16
+ | `step-complete.md` | Completion marker template | Referenced in steps |
17
+
18
+ ## Template Variables
19
+
20
+ Templates use `{{variable}}` syntax for placeholders:
21
+
22
+ | Variable | Description | Example |
23
+ |----------|-------------|---------|
24
+ | `{{task_id}}` | Kebab-case task identifier | `01-add-auth-middleware` |
25
+ | `{{task_description}}` | Plain text task description | `add authentication middleware` |
26
+ | `{{timestamp}}` | ISO 8601 timestamp | `2026-01-12T10:30:00Z` |
27
+ | `{{auto_mode}}` | Auto mode flag | `true` or `false` |
28
+ | `{{save_mode}}` | Save mode flag | `true` or `false` |
29
+ | `{{economy_mode}}` | Economy mode flag | `true` or `false` |
30
+ | `{{branch_mode}}` | Branch mode flag | `true` or `false` |
31
+ | `{{interactive_mode}}` | Interactive mode flag | `true` or `false` |
32
+ | `{{branch_name}}` | Git branch name | `feature/add-auth` |
33
+ | `{{original_input}}` | Raw user input | `/apex -a -s add auth` |
34
+
35
+ ## Setup Script
36
+
37
+ ### `setup-templates.sh`
38
+
39
+ Initializes all template files in the output directory with variables replaced.
40
+
41
+ **Usage:**
42
+ ```bash
43
+ bash scripts/setup-templates.sh \
44
+ "feature_name" \
45
+ "task_description" \
46
+ "auto_mode" \
47
+ "save_mode" \
48
+ "economy_mode" \
49
+ "branch_mode" \
50
+ "interactive_mode" \
51
+ "branch_name" \
52
+ "original_input"
53
+ ```
54
+
55
+ **Output:**
56
+ ```
57
+ .claude/output/apex/01-add-auth-middleware/
58
+ ├── 00-context.md # Always created
59
+ ├── 01-analyze.md # Always created
60
+ ├── 02-plan.md # Always created
61
+ ├── 03-execute.md # Always created
62
+ └── 04-validate.md # Always created
63
+ ```
64
+
65
+ ## Progress Update Script
66
+
67
+ ### `update-progress.sh`
68
+
69
+ Updates the progress table in `00-context.md` without manual markdown editing.
70
+
71
+ **Usage:**
72
+ ```bash
73
+ bash scripts/update-progress.sh <task_id> <step_number> <step_name> <status>
74
+ ```
75
+
76
+ **Examples:**
77
+ ```bash
78
+ # Mark step 01 as in progress
79
+ bash scripts/update-progress.sh "01-add-auth" "01" "analyze" "in_progress"
80
+
81
+ # Mark step 01 as complete
82
+ bash scripts/update-progress.sh "01-add-auth" "01" "analyze" "complete"
83
+
84
+ # Mark step 02 as in progress
85
+ bash scripts/update-progress.sh "01-add-auth" "02" "plan" "in_progress"
86
+ ```
87
+
88
+ **Status Values:**
89
+ - `in_progress` → `⏳ In Progress`
90
+ - `complete` → `✓ Complete`
91
+
92
+ ## Token Savings
93
+
94
+ ### Before Optimization
95
+
96
+ Each step file contained full template content inline:
97
+
98
+ ```markdown
99
+ ### 1. Initialize Save Output (if save_mode)
100
+
101
+ **If `{save_mode}` = true:**
102
+
103
+ Create `{output_dir}/01-analyze.md`:
104
+ ```markdown
105
+ # Step 01: Analyze
106
+
107
+ **Task:** {task_description}
108
+ **Started:** {ISO timestamp}
109
+
110
+ ---
111
+
112
+ ## Context Discovery
113
+ ```
114
+
115
+ Update `00-context.md` progress:
116
+ ```markdown
117
+ | 01-analyze | ⏳ In Progress | {timestamp} |
118
+ ```
119
+ ```
120
+
121
+ **Token cost per step:** ~200 tokens × 5 steps = ~1,000 tokens
122
+
123
+ ### After Optimization
124
+
125
+ Step files now reference templates and scripts:
126
+
127
+ ```markdown
128
+ ### 1. Initialize Save Output (if save_mode)
129
+
130
+ **If `{save_mode}` = true:**
131
+
132
+ The file `{output_dir}/01-analyze.md` has already been created by the setup script.
133
+
134
+ Update progress:
135
+ ```bash
136
+ bash {skill_dir}/scripts/update-progress.sh "{task_id}" "01" "analyze" "in_progress"
137
+ ```
138
+
139
+ Append your findings to `01-analyze.md` as you work.
140
+ ```
141
+
142
+ **Token cost per step:** ~50 tokens × 5 steps = ~250 tokens
143
+
144
+ **Total savings:** ~750 tokens per workflow execution (75% reduction)
145
+
146
+ ## How It Works
147
+
148
+ 1. **Initialization (step-00-init.md):**
149
+ - Runs `setup-templates.sh` once at workflow start
150
+ - Creates all template files with variables replaced
151
+ - Output directory is ready with pre-initialized files
152
+
153
+ 2. **Each Step:**
154
+ - Runs `update-progress.sh` to mark step as "in_progress"
155
+ - Appends findings/logs to the pre-created step file
156
+ - Runs `update-progress.sh` again to mark step as "complete"
157
+
158
+ 3. **Benefits:**
159
+ - AI doesn't need to hold template content in context
160
+ - Consistent formatting across all workflows
161
+ - Easy to update templates without editing step files
162
+ - Scripts handle the tedious markdown updates
163
+
164
+ ## Updating Templates
165
+
166
+ To modify template content:
167
+
168
+ 1. Edit the template file in `templates/`
169
+ 2. Changes apply to all future workflows automatically
170
+ 3. No need to update step files
171
+
172
+ ## Maintenance
173
+
174
+ - Templates are stateless (no workflow-specific logic)
175
+ - Scripts are idempotent (safe to run multiple times)
176
+ - Variables use `{{var}}` syntax to avoid conflicts with markdown
@@ -0,0 +1,7 @@
1
+ ---
2
+
3
+ ## Step Complete
4
+
5
+ **Status:** ✓ Complete
6
+ **Next:** {{next_step}}
7
+ **Timestamp:** {{timestamp}}
package/dist/cli.js CHANGED
@@ -33301,6 +33301,44 @@ function formatDate(date) {
33301
33301
  const pad = (n) => n.toString().padStart(2, "0");
33302
33302
  return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}-${pad(date.getHours())}-${pad(date.getMinutes())}-${pad(date.getSeconds())}`;
33303
33303
  }
33304
+ async function listBackups() {
33305
+ const exists = await import_fs_extra5.default.pathExists(BACKUP_BASE_DIR);
33306
+ if (!exists) {
33307
+ return [];
33308
+ }
33309
+ const entries = await import_fs_extra5.default.readdir(BACKUP_BASE_DIR, { withFileTypes: true });
33310
+ const backups = [];
33311
+ for (const entry of entries) {
33312
+ if (!entry.isDirectory())
33313
+ continue;
33314
+ const match = entry.name.match(/^(\d{4})-(\d{2})-(\d{2})-(\d{2})-(\d{2})-(\d{2})$/);
33315
+ if (!match)
33316
+ continue;
33317
+ const [, year, month, day, hour, minute, second] = match;
33318
+ const date = new Date(parseInt(year), parseInt(month) - 1, parseInt(day), parseInt(hour), parseInt(minute), parseInt(second));
33319
+ backups.push({
33320
+ name: entry.name,
33321
+ path: path7.join(BACKUP_BASE_DIR, entry.name),
33322
+ date
33323
+ });
33324
+ }
33325
+ return backups.sort((a, b) => b.date.getTime() - a.date.getTime());
33326
+ }
33327
+ async function loadBackup(backupPath, claudeDir) {
33328
+ const exists = await import_fs_extra5.default.pathExists(backupPath);
33329
+ if (!exists) {
33330
+ throw new Error(`Backup not found: ${backupPath}`);
33331
+ }
33332
+ await import_fs_extra5.default.ensureDir(claudeDir);
33333
+ const itemsToCopy = ["commands", "agents", "skills", "scripts", "song", "settings.json"];
33334
+ for (const item of itemsToCopy) {
33335
+ const sourcePath = path7.join(backupPath, item);
33336
+ const destPath = path7.join(claudeDir, item);
33337
+ if (await import_fs_extra5.default.pathExists(sourcePath)) {
33338
+ await import_fs_extra5.default.copy(sourcePath, destPath, { overwrite: true });
33339
+ }
33340
+ }
33341
+ }
33304
33342
  async function createBackup(claudeDir) {
33305
33343
  const exists = await import_fs_extra5.default.pathExists(claudeDir);
33306
33344
  if (!exists) {
@@ -35732,6 +35770,22 @@ async function proSyncCommand(options = {}) {
35732
35770
  if (syncMode === "updates") {
35733
35771
  selectedItems = [...newItems, ...modifiedItems];
35734
35772
  } else if (syncMode === "updates_and_delete") {
35773
+ M2.message("");
35774
+ M2.message(source_default.red.bold("⚠️ WARNING: DESTRUCTIVE ACTION"));
35775
+ M2.message(source_default.red("━".repeat(50)));
35776
+ M2.message(source_default.red("All your custom skills, commands, agents, and configuration files"));
35777
+ M2.message(source_default.red("that are not in the premium version will be PERMANENTLY DELETED"));
35778
+ M2.message(source_default.red("and replaced by the new version."));
35779
+ M2.message(source_default.red("━".repeat(50)));
35780
+ M2.message("");
35781
+ const deleteConfirm = await ye({
35782
+ message: source_default.red.bold("Are you sure you want to delete and replace all files?"),
35783
+ initialValue: false
35784
+ });
35785
+ if (pD(deleteConfirm) || !deleteConfirm) {
35786
+ xe("Sync cancelled");
35787
+ process.exit(0);
35788
+ }
35735
35789
  selectedItems = [...newItems, ...modifiedItems, ...deletedItems];
35736
35790
  } else {
35737
35791
  const fileChoices = choices.filter((c) => c.value.type !== "hook");
@@ -35879,13 +35933,90 @@ async function proSyncCommand(options = {}) {
35879
35933
  }
35880
35934
  }
35881
35935
 
35936
+ // src/commands/backup.ts
35937
+ import os15 from "os";
35938
+ import path15 from "path";
35939
+ function formatBackupDate(date) {
35940
+ const now = new Date;
35941
+ const diffMs = now.getTime() - date.getTime();
35942
+ const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24));
35943
+ const diffHours = Math.floor(diffMs / (1000 * 60 * 60));
35944
+ const diffMinutes = Math.floor(diffMs / (1000 * 60));
35945
+ let relative;
35946
+ if (diffMinutes < 60) {
35947
+ relative = `${diffMinutes} minute${diffMinutes !== 1 ? "s" : ""} ago`;
35948
+ } else if (diffHours < 24) {
35949
+ relative = `${diffHours} hour${diffHours !== 1 ? "s" : ""} ago`;
35950
+ } else if (diffDays < 7) {
35951
+ relative = `${diffDays} day${diffDays !== 1 ? "s" : ""} ago`;
35952
+ } else {
35953
+ relative = date.toLocaleDateString();
35954
+ }
35955
+ return `${date.toLocaleString()} (${relative})`;
35956
+ }
35957
+ async function backupLoadCommand(options = {}) {
35958
+ const claudeDir = options.folder || path15.join(os15.homedir(), ".claude");
35959
+ Ie(source_default.blue("\uD83D\uDCE6 Load Backup"));
35960
+ const spinner = Y2();
35961
+ spinner.start("Scanning for backups...");
35962
+ const backups = await listBackups();
35963
+ spinner.stop(`Found ${backups.length} backup${backups.length !== 1 ? "s" : ""}`);
35964
+ if (backups.length === 0) {
35965
+ M2.warn("No backups found in ~/.config/aiblueprint/backup/");
35966
+ M2.info("Backups are created automatically when you run setup or sync commands.");
35967
+ Se(source_default.gray("Nothing to restore"));
35968
+ return;
35969
+ }
35970
+ const backupOptions = backups.map((backup) => ({
35971
+ value: backup,
35972
+ label: backup.name,
35973
+ hint: formatBackupDate(backup.date)
35974
+ }));
35975
+ const selected = await ve({
35976
+ message: "Select a backup to restore:",
35977
+ options: backupOptions
35978
+ });
35979
+ if (pD(selected)) {
35980
+ xe("Operation cancelled");
35981
+ process.exit(0);
35982
+ }
35983
+ M2.info(`Selected: ${source_default.cyan(selected.name)}`);
35984
+ M2.info(`Date: ${source_default.gray(formatBackupDate(selected.date))}`);
35985
+ const confirm = await ye({
35986
+ message: `This will overwrite your current configuration in ${source_default.cyan(claudeDir)}. Continue?`,
35987
+ initialValue: false
35988
+ });
35989
+ if (pD(confirm) || !confirm) {
35990
+ xe("Operation cancelled");
35991
+ process.exit(0);
35992
+ }
35993
+ spinner.start("Creating backup of current configuration...");
35994
+ const currentBackup = await createBackup(claudeDir);
35995
+ if (currentBackup) {
35996
+ spinner.stop(`Current config backed up to: ${source_default.gray(currentBackup)}`);
35997
+ } else {
35998
+ spinner.stop("No current config to backup");
35999
+ }
36000
+ spinner.start("Restoring backup...");
36001
+ try {
36002
+ await loadBackup(selected.path, claudeDir);
36003
+ spinner.stop("Backup restored successfully");
36004
+ M2.success(`Restored configuration from ${source_default.cyan(selected.name)}`);
36005
+ Se(source_default.green("✅ Backup loaded successfully"));
36006
+ } catch (error) {
36007
+ spinner.stop("Restore failed");
36008
+ M2.error(`Failed to restore backup: ${error}`);
36009
+ process.exit(1);
36010
+ }
36011
+ }
36012
+
35882
36013
  // src/commands/dynamic-scripts.ts
35883
- import path17 from "path";
36014
+ import path18 from "path";
35884
36015
  import { homedir } from "os";
35885
36016
 
35886
36017
  // src/lib/script-parser.ts
35887
36018
  var import_fs_extra12 = __toESM(require_lib4(), 1);
35888
- import path15 from "path";
36019
+ import path16 from "path";
35889
36020
  var EXCLUDED_SCRIPTS = ["test", "lint", "format", "start"];
35890
36021
  var EXCLUDED_SUFFIXES = [":test", ":lint", ":test-fixtures", ":start"];
35891
36022
  function shouldIncludeScript(scriptName) {
@@ -35896,7 +36027,7 @@ function shouldIncludeScript(scriptName) {
35896
36027
  return true;
35897
36028
  }
35898
36029
  async function readScriptsPackageJson(claudeDir) {
35899
- const packageJsonPath = path15.join(claudeDir, "scripts", "package.json");
36030
+ const packageJsonPath = path16.join(claudeDir, "scripts", "package.json");
35900
36031
  try {
35901
36032
  if (!await import_fs_extra12.default.pathExists(packageJsonPath)) {
35902
36033
  return null;
@@ -35948,11 +36079,11 @@ function groupScriptsByPrefix(commands) {
35948
36079
  var import_fs_extra13 = __toESM(require_lib4(), 1);
35949
36080
  import { spawn as spawn2 } from "child_process";
35950
36081
  import { execSync as execSync4 } from "child_process";
35951
- import path16 from "path";
35952
- import os15 from "os";
36082
+ import path17 from "path";
36083
+ import os16 from "os";
35953
36084
  function checkCommand(cmd) {
35954
36085
  try {
35955
- const isWindows = os15.platform() === "win32";
36086
+ const isWindows = os16.platform() === "win32";
35956
36087
  const whichCmd = isWindows ? `where ${cmd}` : `which ${cmd}`;
35957
36088
  execSync4(whichCmd, { stdio: "ignore" });
35958
36089
  return true;
@@ -35978,13 +36109,13 @@ async function executeScript(scriptName, claudeDir) {
35978
36109
  console.error(source_default.red("Bun is not installed. Install with: npm install -g bun"));
35979
36110
  return 1;
35980
36111
  }
35981
- const scriptsDir = path16.join(claudeDir, "scripts");
36112
+ const scriptsDir = path17.join(claudeDir, "scripts");
35982
36113
  if (!await import_fs_extra13.default.pathExists(scriptsDir)) {
35983
36114
  console.error(source_default.red(`Scripts directory not found at ${scriptsDir}`));
35984
36115
  console.log(source_default.gray("Run: aiblueprint claude-code setup"));
35985
36116
  return 1;
35986
36117
  }
35987
- const packageJsonPath = path16.join(scriptsDir, "package.json");
36118
+ const packageJsonPath = path17.join(scriptsDir, "package.json");
35988
36119
  if (!await import_fs_extra13.default.pathExists(packageJsonPath)) {
35989
36120
  console.error(source_default.red(`package.json not found in ${scriptsDir}`));
35990
36121
  return 1;
@@ -36012,7 +36143,7 @@ async function executeScript(scriptName, claudeDir) {
36012
36143
 
36013
36144
  // src/commands/dynamic-scripts.ts
36014
36145
  function getClaudeDir(parentOptions) {
36015
- return parentOptions.claudeCodeFolder || parentOptions.folder ? path17.resolve(parentOptions.claudeCodeFolder || parentOptions.folder) : path17.join(homedir(), ".claude");
36146
+ return parentOptions.claudeCodeFolder || parentOptions.folder ? path18.resolve(parentOptions.claudeCodeFolder || parentOptions.folder) : path18.join(homedir(), ".claude");
36016
36147
  }
36017
36148
  async function registerDynamicScriptCommands(claudeCodeCmd, claudeDir) {
36018
36149
  const scripts = await readScriptsPackageJson(claudeDir);
@@ -36095,6 +36226,12 @@ proCmd.command("sync").description("Sync premium configurations with selective u
36095
36226
  const claudeCodeFolder = parentOptions.claudeCodeFolder || parentOptions.folder;
36096
36227
  proSyncCommand({ folder: claudeCodeFolder });
36097
36228
  });
36229
+ var backupCmd = claudeCodeCmd.command("backup").description("Manage Claude Code configuration backups");
36230
+ backupCmd.command("load").description("Load a previous backup interactively").action((options, command) => {
36231
+ const parentOptions = command.parent.parent.opts();
36232
+ const claudeCodeFolder = parentOptions.claudeCodeFolder || parentOptions.folder;
36233
+ backupLoadCommand({ folder: claudeCodeFolder });
36234
+ });
36098
36235
  try {
36099
36236
  const claudeDir = join2(homedir2(), ".claude");
36100
36237
  await registerDynamicScriptCommands(claudeCodeCmd, claudeDir);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aiblueprint-cli",
3
- "version": "1.4.24",
3
+ "version": "1.4.25",
4
4
  "description": "AIBlueprint CLI for setting up Claude Code configurations",
5
5
  "author": "AIBlueprint",
6
6
  "license": "MIT",