@codebehind/agent-workflow 1.0.0 → 1.1.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/bin/agent-workflow.mjs +88 -14
- package/package.json +1 -1
package/bin/agent-workflow.mjs
CHANGED
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
existsSync, mkdirSync, copyFileSync, readdirSync, statSync,
|
|
4
|
+
readFileSync,
|
|
5
|
+
} from 'fs';
|
|
3
6
|
import { join, dirname, relative } from 'path';
|
|
4
7
|
import { fileURLToPath } from 'url';
|
|
8
|
+
import { execSync } from 'child_process';
|
|
9
|
+
import readline from 'readline';
|
|
5
10
|
|
|
6
11
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
7
12
|
const TEMPLATES_DIR = join(__dirname, '..', 'templates');
|
|
8
|
-
const VERSION = '1.
|
|
13
|
+
const VERSION = '1.1.0';
|
|
9
14
|
|
|
10
15
|
const args = process.argv.slice(2);
|
|
11
16
|
const command = args[0];
|
|
@@ -16,44 +21,59 @@ function printUsage() {
|
|
|
16
21
|
@codebehind/agent-workflow v${VERSION}
|
|
17
22
|
|
|
18
23
|
Usage:
|
|
19
|
-
npx @codebehind/agent-workflow
|
|
24
|
+
npx @codebehind/agent-workflow <command> [options]
|
|
20
25
|
|
|
21
26
|
Commands:
|
|
22
27
|
init Copy the agent-workflow framework files into the current directory.
|
|
23
|
-
Skips files that already exist (use --force to overwrite).
|
|
28
|
+
Skips files that already exist (use --force to overwrite all).
|
|
29
|
+
upgrade Update all framework files to the latest version.
|
|
30
|
+
Prompts before overwriting any file that differs locally.
|
|
24
31
|
|
|
25
32
|
Options:
|
|
26
|
-
--force Overwrite existing files.
|
|
33
|
+
--force (init only) Overwrite existing files without prompting.
|
|
27
34
|
--version Print version and exit.
|
|
28
35
|
`);
|
|
29
36
|
}
|
|
30
37
|
|
|
31
|
-
|
|
38
|
+
const SKIP_FILES = new Set(['.DS_Store']);
|
|
39
|
+
|
|
40
|
+
// Async walk — processes files sequentially so prompts work correctly
|
|
41
|
+
async function walkDir(dir, baseDir, callback) {
|
|
32
42
|
for (const entry of readdirSync(dir)) {
|
|
43
|
+
if (SKIP_FILES.has(entry)) continue;
|
|
33
44
|
const fullPath = join(dir, entry);
|
|
34
45
|
const relPath = relative(baseDir, fullPath);
|
|
35
46
|
if (statSync(fullPath).isDirectory()) {
|
|
36
|
-
walkDir(fullPath, baseDir, callback);
|
|
47
|
+
await walkDir(fullPath, baseDir, callback);
|
|
37
48
|
} else {
|
|
38
|
-
callback(fullPath, relPath);
|
|
49
|
+
await callback(fullPath, relPath);
|
|
39
50
|
}
|
|
40
51
|
}
|
|
41
52
|
}
|
|
42
53
|
|
|
43
|
-
function
|
|
54
|
+
function getDiff(localPath, templatePath) {
|
|
55
|
+
try {
|
|
56
|
+
// diff exits with code 1 when files differ — that's expected, not an error
|
|
57
|
+
return execSync(`diff -u "${localPath}" "${templatePath}"`, { stdio: ['pipe', 'pipe', 'pipe'] }).toString();
|
|
58
|
+
} catch (e) {
|
|
59
|
+
return e.stdout ? e.stdout.toString() : '';
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async function init(targetDir) {
|
|
44
64
|
const copied = [];
|
|
45
65
|
const skipped = [];
|
|
46
66
|
|
|
47
|
-
walkDir(TEMPLATES_DIR, TEMPLATES_DIR, (srcPath, relPath) => {
|
|
67
|
+
await walkDir(TEMPLATES_DIR, TEMPLATES_DIR, async (srcPath, relPath) => {
|
|
48
68
|
const destPath = join(targetDir, relPath);
|
|
49
|
-
const
|
|
69
|
+
const destDirPath = dirname(destPath);
|
|
50
70
|
|
|
51
71
|
if (!force && existsSync(destPath)) {
|
|
52
72
|
skipped.push(relPath);
|
|
53
73
|
return;
|
|
54
74
|
}
|
|
55
75
|
|
|
56
|
-
mkdirSync(
|
|
76
|
+
mkdirSync(destDirPath, { recursive: true });
|
|
57
77
|
copyFileSync(srcPath, destPath);
|
|
58
78
|
copied.push(relPath);
|
|
59
79
|
});
|
|
@@ -83,12 +103,66 @@ Next steps:
|
|
|
83
103
|
`);
|
|
84
104
|
}
|
|
85
105
|
|
|
106
|
+
async function upgrade(targetDir) {
|
|
107
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
108
|
+
const ask = (q) => new Promise(resolve => rl.question(q, resolve));
|
|
109
|
+
|
|
110
|
+
let overridden = 0;
|
|
111
|
+
let skipped = 0;
|
|
112
|
+
let added = 0;
|
|
113
|
+
|
|
114
|
+
console.log(`\nUpgrading to @codebehind/agent-workflow v${VERSION}...\n`);
|
|
115
|
+
|
|
116
|
+
await walkDir(TEMPLATES_DIR, TEMPLATES_DIR, async (srcPath, relPath) => {
|
|
117
|
+
const destPath = join(targetDir, relPath);
|
|
118
|
+
|
|
119
|
+
if (!existsSync(destPath)) {
|
|
120
|
+
mkdirSync(dirname(destPath), { recursive: true });
|
|
121
|
+
copyFileSync(srcPath, destPath);
|
|
122
|
+
console.log(` + ${relPath} (new)`);
|
|
123
|
+
added++;
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const localContent = readFileSync(destPath);
|
|
128
|
+
const templateContent = readFileSync(srcPath);
|
|
129
|
+
|
|
130
|
+
if (localContent.equals(templateContent)) {
|
|
131
|
+
console.log(` ~ ${relPath} (up to date)`);
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Files differ — show diff and prompt
|
|
136
|
+
const diff = getDiff(destPath, srcPath);
|
|
137
|
+
console.log(`\n--- Conflict: ${relPath} ---`);
|
|
138
|
+
console.log(diff);
|
|
139
|
+
|
|
140
|
+
const answer = await ask(`Override local file? [o=override, s=skip] (default: s): `);
|
|
141
|
+
|
|
142
|
+
if (answer.trim().toLowerCase() === 'o') {
|
|
143
|
+
copyFileSync(srcPath, destPath);
|
|
144
|
+
console.log(` ✓ ${relPath} (overridden)\n`);
|
|
145
|
+
overridden++;
|
|
146
|
+
} else {
|
|
147
|
+
console.log(` - ${relPath} (skipped)\n`);
|
|
148
|
+
skipped++;
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
rl.close();
|
|
153
|
+
console.log(`Done. ${added} new, ${overridden} overridden, ${skipped} skipped.`);
|
|
154
|
+
}
|
|
155
|
+
|
|
86
156
|
// Entry point
|
|
87
157
|
if (command === '--version' || command === '-v') {
|
|
88
158
|
console.log(VERSION);
|
|
89
159
|
process.exit(0);
|
|
90
|
-
} else if (
|
|
91
|
-
init(process.cwd());
|
|
160
|
+
} else if (command === 'init') {
|
|
161
|
+
await init(process.cwd());
|
|
162
|
+
} else if (command === 'upgrade') {
|
|
163
|
+
await upgrade(process.cwd());
|
|
164
|
+
} else if (!command) {
|
|
165
|
+
printUsage();
|
|
92
166
|
} else {
|
|
93
167
|
console.error(`Unknown command: ${command}`);
|
|
94
168
|
printUsage();
|