ac-framework 1.0.0 → 1.0.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ac-framework",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "Agentic Coding Framework - Multi-assistant configuration system with OpenSpec workflows",
5
5
  "main": "src/index.js",
6
6
  "bin": {
package/src/cli.js CHANGED
@@ -1,15 +1,21 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  import { Command } from 'commander';
4
+ import { readFile } from 'node:fs/promises';
5
+ import { dirname, resolve } from 'node:path';
6
+ import { fileURLToPath } from 'node:url';
4
7
  import { initCommand } from './commands/init.js';
5
8
  import { showBanner } from './ui/banner.js';
6
9
 
10
+ const __dirname = dirname(fileURLToPath(import.meta.url));
11
+ const pkg = JSON.parse(await readFile(resolve(__dirname, '../package.json'), 'utf-8'));
12
+
7
13
  const program = new Command();
8
14
 
9
15
  program
10
16
  .name('acfm')
11
17
  .description('AC Framework - Agentic Coding Framework CLI')
12
- .version('1.0.0');
18
+ .version(pkg.version);
13
19
 
14
20
  program
15
21
  .command('init')
@@ -14,55 +14,31 @@ const __dirname = dirname(__filename);
14
14
  const acGradient = gradient(['#6C5CE7', '#00CEC9', '#0984E3']);
15
15
  const successGradient = gradient(['#00CEC9', '#00B894', '#55EFC4']);
16
16
 
17
+ const ALWAYS_INSTALL = ['openspec'];
18
+
17
19
  async function getFrameworkFolders() {
18
20
  const frameworkPath = resolve(__dirname, '../../framework');
19
21
  const entries = await readdir(frameworkPath, { withFileTypes: true });
20
22
 
21
23
  return entries
22
- .filter((entry) => entry.isDirectory())
24
+ .filter((entry) => entry.isDirectory() && !ALWAYS_INSTALL.includes(entry.name))
23
25
  .map((entry) => entry.name)
24
- .sort((a, b) => {
25
- // Hidden folders first, then normal
26
- const aHidden = a.startsWith('.');
27
- const bHidden = b.startsWith('.');
28
- if (aHidden && !bHidden) return -1;
29
- if (!aHidden && bHidden) return 1;
30
- return a.localeCompare(b);
31
- });
26
+ .sort((a, b) => a.localeCompare(b));
32
27
  }
33
28
 
34
29
  function buildChoices(folders) {
35
30
  const choices = [];
36
31
 
37
- const hidden = folders.filter((f) => f.startsWith('.'));
38
- const visible = folders.filter((f) => !f.startsWith('.'));
39
-
40
- if (hidden.length > 0) {
41
- choices.push(new inquirer.Separator(chalk.hex('#636E72')(' ── AI Assistants ──────────────────────────')));
42
- for (const folder of hidden) {
43
- const desc = DESCRIPTIONS[folder] || '';
44
- const displayName = formatFolderName(folder);
45
- const label = `${chalk.hex('#DFE6E9').bold(displayName)}${desc ? chalk.hex('#636E72')(` — ${desc}`) : ''}`;
46
- choices.push({
47
- name: label,
48
- value: folder,
49
- short: displayName,
50
- });
51
- }
52
- }
53
-
54
- if (visible.length > 0) {
55
- choices.push(new inquirer.Separator(chalk.hex('#636E72')(' ── Configuration ─────────────────────────')));
56
- for (const folder of visible) {
57
- const desc = DESCRIPTIONS[folder] || '';
58
- const displayName = formatFolderName(folder);
59
- const label = `${chalk.hex('#DFE6E9').bold(displayName)}${desc ? chalk.hex('#636E72')(` — ${desc}`) : ''}`;
60
- choices.push({
61
- name: label,
62
- value: folder,
63
- short: displayName,
64
- });
65
- }
32
+ choices.push(new inquirer.Separator(chalk.hex('#636E72')(' ── AI Assistants ──────────────────────────')));
33
+ for (const folder of folders) {
34
+ const desc = DESCRIPTIONS[folder] || '';
35
+ const displayName = formatFolderName(folder);
36
+ const label = `${chalk.hex('#DFE6E9').bold(displayName)}${desc ? chalk.hex('#636E72')(` ${desc}`) : ''}`;
37
+ choices.push({
38
+ name: label,
39
+ value: folder,
40
+ short: displayName,
41
+ });
66
42
  }
67
43
 
68
44
  return choices;
@@ -103,7 +79,10 @@ export async function initCommand() {
103
79
  }
104
80
 
105
81
  console.log(
106
- chalk.hex('#B2BEC3')(` Found ${chalk.hex('#00CEC9').bold(folders.length)} modules available\n`)
82
+ chalk.hex('#B2BEC3')(` Found ${chalk.hex('#00CEC9').bold(folders.length)} assistant modules available`)
83
+ );
84
+ console.log(
85
+ chalk.hex('#636E72')(` + ${chalk.hex('#6C5CE7').bold('openspec')} will be included automatically\n`)
107
86
  );
108
87
 
109
88
  console.log(
@@ -137,9 +116,10 @@ export async function initCommand() {
137
116
 
138
117
  console.log();
139
118
 
140
- // Check for existing folders
119
+ // Check for existing folders (includes openspec)
120
+ const allForCheck = [...selected, ...ALWAYS_INSTALL];
141
121
  const existing = [];
142
- for (const folder of selected) {
122
+ for (const folder of allForCheck) {
143
123
  if (await checkExisting(targetDir, folder)) {
144
124
  existing.push(folder);
145
125
  }
@@ -165,19 +145,20 @@ export async function initCommand() {
165
145
 
166
146
  if (!overwrite) {
167
147
  const filtered = selected.filter((f) => !existing.includes(f));
168
- if (filtered.length === 0) {
148
+ const autoFiltered = ALWAYS_INSTALL.filter((f) => !existing.includes(f));
149
+ if (filtered.length === 0 && autoFiltered.length === 0) {
169
150
  console.log(chalk.hex('#636E72')('\n No new modules to install. Exiting.\n'));
170
151
  process.exit(0);
171
152
  }
172
153
  selected.length = 0;
173
154
  selected.push(...filtered);
174
155
  console.log(
175
- chalk.hex('#B2BEC3')(`\n Proceeding with ${chalk.hex('#00CEC9').bold(selected.length)} new module(s)...\n`)
156
+ chalk.hex('#B2BEC3')(`\n Proceeding with ${chalk.hex('#00CEC9').bold(filtered.length + autoFiltered.length)} new module(s)...\n`)
176
157
  );
177
158
  }
178
159
  }
179
160
 
180
- // Confirm selection
161
+ // Confirm selection — show selected + openspec
181
162
  console.log(chalk.hex('#B2BEC3')(' Modules to install:\n'));
182
163
  for (const folder of selected) {
183
164
  const desc = DESCRIPTIONS[folder] || '';
@@ -187,6 +168,12 @@ export async function initCommand() {
187
168
  (desc ? chalk.hex('#636E72')(` — ${desc}`) : '')
188
169
  );
189
170
  }
171
+ console.log(
172
+ chalk.hex('#6C5CE7')(' ◆ ') +
173
+ chalk.hex('#DFE6E9').bold('Openspec') +
174
+ chalk.hex('#636E72')(` — ${DESCRIPTIONS['openspec']}`) +
175
+ chalk.hex('#636E72').italic(' (auto)')
176
+ );
190
177
  console.log();
191
178
 
192
179
  const { confirm } = await inquirer.prompt([
@@ -205,12 +192,13 @@ export async function initCommand() {
205
192
 
206
193
  console.log();
207
194
 
208
- // Install modules with progress
195
+ // Install modules with progress — always include openspec
209
196
  const frameworkPath = resolve(__dirname, '../../framework');
197
+ const allToInstall = [...selected, ...ALWAYS_INSTALL];
210
198
  let installed = 0;
211
199
  const errors = [];
212
200
 
213
- for (const folder of selected) {
201
+ for (const folder of allToInstall) {
214
202
  const spinner = createSpinner(
215
203
  chalk.hex('#B2BEC3')(`Installing ${chalk.hex('#DFE6E9').bold(formatFolderName(folder))}...`)
216
204
  ).start();
@@ -23,7 +23,7 @@ export async function matrixRain(durationMs = 1500) {
23
23
 
24
24
  for (let c = 0; c < cols; c++) {
25
25
  const drop = drops[c];
26
- if (drop.y < rows) {
26
+ if (drop.y >= 0 && drop.y < rows) {
27
27
  const ch = chars[Math.floor(Math.random() * chars.length)];
28
28
  grid[drop.y][c] = chalk.hex(colors[Math.floor(Math.random() * colors.length)])(ch);
29
29
  if (drop.y > 0) {