@ryuenn3123/agentic-senior-core 6.16.2 → 6.16.5
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/.agents/plugins/agentic-senior-core/.codex-plugin/plugin.json +1 -1
- package/.agents/plugins/agentic-senior-core/commands/asc-pentest.md +2 -0
- package/.agents/plugins/agentic-senior-core/commands/asc-pentest.toml +3 -0
- package/.agents/plugins/agentic-senior-core/hooks/dedup-gate.js +137 -128
- package/.agents/plugins/agentic-senior-core/hooks/hooks.json +97 -0
- package/.agents/plugins/agentic-senior-core/hooks/ladder-pulse.js +53 -36
- package/.agents/plugins/agentic-senior-core/hooks/lib/known-ui-slop-patterns.json +20 -0
- package/.agents/plugins/agentic-senior-core/hooks/path-util.cjs +118 -4
- package/.agents/plugins/agentic-senior-core/hooks/post-edit-enforce.js +98 -81
- package/.agents/plugins/agentic-senior-core/hooks/pre-tool-dependency-gate.js +168 -191
- package/.agents/plugins/agentic-senior-core/hooks/session-pulse.js +48 -35
- package/.agents/plugins/agentic-senior-core/hooks/session-start.js +62 -11
- package/.agents/plugins/agentic-senior-core/hooks.json +4 -94
- package/.agents/plugins/agentic-senior-core/plugin.json +5 -13
- package/.agents/plugins/agentic-senior-core/rules/agentic-senior-core.md +6 -1
- package/.agents/plugins/agentic-senior-core/skills/asc/SKILL.md +5 -2
- package/.agents/plugins/agentic-senior-core/skills/asc-develop/SKILL.md +3 -3
- package/.agents/plugins/agentic-senior-core/skills/asc-pentest/SKILL.md +97 -0
- package/.agents/plugins/agentic-senior-core/skills/asc-pentest/references/api-security-idor.md +105 -0
- package/.agents/plugins/agentic-senior-core/skills/asc-pentest/references/dast-baseline.md +78 -0
- package/.agents/plugins/agentic-senior-core/skills/asc-pentest/references/fuzzing-dsl.md +66 -0
- package/.agents/plugins/agentic-senior-core/skills/asc-pentest/references/pentest-task-tree.md +70 -0
- package/.agents/plugins/agentic-senior-core/skills/asc-review/SKILL.md +2 -2
- package/.agents/plugins/agentic-senior-core/skills/asc-test/SKILL.md +8 -1
- package/.agents/plugins/agentic-senior-core/skills/asc-test/references/mutation-testing.md +55 -0
- package/.agents/plugins/agentic-senior-core/skills/asc-test/references/performance-budgets.md +67 -0
- package/.agents/plugins/agentic-senior-core/skills/asc-test/references/property-testing.md +72 -0
- package/.agents/plugins/agentic-senior-core/skills/asc-ui/SKILL.md +17 -14
- package/.agents/plugins/agentic-senior-core/skills/asc-ui/references/copy-i18n.md +56 -8
- package/.agents/plugins/agentic-senior-core/skills/asc-ui/references/craft/color-surfaces.md +25 -0
- package/.agents/plugins/agentic-senior-core/skills/asc-ui/references/craft/themes-catalog.md +198 -0
- package/.agents/plugins/agentic-senior-core/skills/asc-ui/references/divergence.md +34 -2
- package/.agents/plugins/agentic-senior-core/skills/asc-ui/references/modes/genre-calibration.md +89 -0
- package/.agents/plugins/agentic-senior-core/skills/asc-ui/references/modes/operate.md +26 -0
- package/.agents/plugins/agentic-senior-core/skills/asc-ui/references/modes/persuade.md +10 -9
- package/.agents/plugins/agentic-senior-core/skills/asc-ui/references/redesign-audit.md +4 -9
- package/bin/agentic-senior-core.js +19 -4
- package/gemini-extension.json +2 -2
- package/lib/cli/ascx/runtime.mjs +5 -27
- package/lib/cli/ascx/windows-spawn.mjs +348 -0
- package/lib/cli/commands/bootstrap.mjs +56 -0
- package/lib/cli/commands/dedup.mjs +500 -0
- package/lib/cli/commands/git-hook-generator.mjs +3 -2
- package/lib/cli/commands/global.mjs +109 -53
- package/lib/cli/commands/preview.mjs +18 -9
- package/package.json +1 -1
- package/plugin.yaml +3 -1
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
|
|
5
|
+
const CURRENT_DIR = path.dirname(fileURLToPath(import.meta.url));
|
|
6
|
+
const REPOSITORY_ROOT = path.resolve(CURRENT_DIR, '..', '..', '..');
|
|
7
|
+
const ASC_BIN_PATH = path.join(REPOSITORY_ROOT, 'bin', 'agentic-senior-core.js');
|
|
8
|
+
const ASCX_BIN_PATH = path.join(REPOSITORY_ROOT, 'bin', 'ascx.js');
|
|
9
|
+
|
|
10
|
+
const CMD_BUILTINS = new Set([
|
|
11
|
+
'assoc', 'call', 'cd', 'chdir', 'cls', 'color', 'copy', 'date', 'del', 'dir',
|
|
12
|
+
'echo', 'endlocal', 'erase', 'exit', 'for', 'ftype', 'goto', 'if', 'md',
|
|
13
|
+
'mkdir', 'mklink', 'move', 'path', 'pause', 'popd', 'prompt', 'pushd', 'rd',
|
|
14
|
+
'rem', 'ren', 'rename', 'rmdir', 'set', 'setlocal', 'shift', 'start', 'time',
|
|
15
|
+
'title', 'type', 'ver', 'verify', 'vol',
|
|
16
|
+
]);
|
|
17
|
+
|
|
18
|
+
const POWERSHELL_CMDLET_PATTERN = /^[A-Za-z]+-[A-Za-z0-9]+$/;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Finds the canonical PATH key in an environment object (handles Windows `Path` vs `PATH`).
|
|
22
|
+
*/
|
|
23
|
+
export function getPathEnvKey(env = process.env) {
|
|
24
|
+
for (const key of Object.keys(env)) {
|
|
25
|
+
if (key.toUpperCase() === 'PATH') {
|
|
26
|
+
return key;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return process.platform === 'win32' ? 'Path' : 'PATH';
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Collects local `node_modules/.bin` directories walking up from `cwd`.
|
|
34
|
+
*/
|
|
35
|
+
export function collectLocalNodeBinDirs(cwd) {
|
|
36
|
+
const dirs = [];
|
|
37
|
+
let current = path.resolve(cwd);
|
|
38
|
+
|
|
39
|
+
while (true) {
|
|
40
|
+
const candidate = path.join(current, 'node_modules', '.bin');
|
|
41
|
+
if (fs.existsSync(candidate)) {
|
|
42
|
+
dirs.push(candidate);
|
|
43
|
+
}
|
|
44
|
+
const parent = path.dirname(current);
|
|
45
|
+
if (parent === current) {
|
|
46
|
+
break;
|
|
47
|
+
}
|
|
48
|
+
current = parent;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return dirs;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Returns a copy of `env` with local `node_modules/.bin` prepended to PATH without duplicating Path/PATH keys.
|
|
56
|
+
*/
|
|
57
|
+
export function buildAugmentedEnvironment(baseEnv, assignments = [], cwd = process.cwd()) {
|
|
58
|
+
const env = { ...baseEnv };
|
|
59
|
+
const pathKey = getPathEnvKey(env);
|
|
60
|
+
const localBins = collectLocalNodeBinDirs(cwd);
|
|
61
|
+
|
|
62
|
+
if (localBins.length > 0) {
|
|
63
|
+
const currentPath = env[pathKey] || '';
|
|
64
|
+
const existingSet = new Set(
|
|
65
|
+
currentPath.split(path.delimiter).map(p => (process.platform === 'win32' ? p.toLowerCase() : p))
|
|
66
|
+
);
|
|
67
|
+
const toPrepend = localBins.filter(
|
|
68
|
+
dir => !existingSet.has(process.platform === 'win32' ? dir.toLowerCase() : dir)
|
|
69
|
+
);
|
|
70
|
+
if (toPrepend.length > 0) {
|
|
71
|
+
env[pathKey] = [...toPrepend, currentPath].filter(Boolean).join(path.delimiter);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (Array.isArray(assignments)) {
|
|
76
|
+
for (const assignment of assignments) {
|
|
77
|
+
const separatorIndex = assignment.indexOf('=');
|
|
78
|
+
if (separatorIndex === -1) continue;
|
|
79
|
+
const variableName = assignment.slice(0, separatorIndex);
|
|
80
|
+
const variableValue = assignment.slice(separatorIndex + 1);
|
|
81
|
+
if (variableName.toUpperCase() === 'PATH') {
|
|
82
|
+
env[pathKey] = variableValue;
|
|
83
|
+
} else {
|
|
84
|
+
env[variableName] = variableValue;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
} else if (assignments && typeof assignments === 'object') {
|
|
88
|
+
for (const [variableName, variableValue] of Object.entries(assignments)) {
|
|
89
|
+
if (variableName.toUpperCase() === 'PATH') {
|
|
90
|
+
env[pathKey] = String(variableValue);
|
|
91
|
+
} else {
|
|
92
|
+
env[variableName] = String(variableValue);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return env;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Resolves an executable on Windows across PATH and PATHEXT, prioritizing native `.exe`/`.com` before `.cmd`/`.bat`/`.ps1`.
|
|
102
|
+
*/
|
|
103
|
+
export function resolveWindowsExecutable(executable, env = process.env, cwd = process.cwd()) {
|
|
104
|
+
if (!executable) return null;
|
|
105
|
+
|
|
106
|
+
const hasPathSep = executable.includes('/') || executable.includes('\\');
|
|
107
|
+
const rawPathExt = env.PATHEXT || '.COM;.EXE;.BAT;.CMD;.PS1';
|
|
108
|
+
const parsedExts = rawPathExt
|
|
109
|
+
.split(';')
|
|
110
|
+
.map(ext => ext.trim().toLowerCase())
|
|
111
|
+
.filter(Boolean);
|
|
112
|
+
const priorityExts = ['.exe', '.com', '.cmd', '.bat', '.ps1', ...parsedExts.filter(
|
|
113
|
+
e => !['.exe', '.com', '.cmd', '.bat', '.ps1'].includes(e)
|
|
114
|
+
)];
|
|
115
|
+
|
|
116
|
+
const checkCandidateBase = (basePath) => {
|
|
117
|
+
const lowerExt = path.extname(basePath).toLowerCase();
|
|
118
|
+
if (lowerExt && fs.existsSync(basePath) && fs.statSync(basePath).isFile()) {
|
|
119
|
+
return basePath;
|
|
120
|
+
}
|
|
121
|
+
for (const ext of priorityExts) {
|
|
122
|
+
const withExt = `${basePath}${ext}`;
|
|
123
|
+
try {
|
|
124
|
+
if (fs.existsSync(withExt) && fs.statSync(withExt).isFile()) {
|
|
125
|
+
return withExt;
|
|
126
|
+
}
|
|
127
|
+
} catch {
|
|
128
|
+
// Ignore inaccessible paths
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return null;
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
if (hasPathSep || path.isAbsolute(executable)) {
|
|
135
|
+
const fullBase = path.isAbsolute(executable) ? executable : path.resolve(cwd, executable);
|
|
136
|
+
return checkCandidateBase(fullBase);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const pathKey = getPathEnvKey(env);
|
|
140
|
+
const searchDirs = (env[pathKey] || '')
|
|
141
|
+
.split(path.delimiter)
|
|
142
|
+
.map(dir => dir.replace(/^"+|"+$/g, '').trim())
|
|
143
|
+
.filter(Boolean);
|
|
144
|
+
|
|
145
|
+
for (const dir of searchDirs) {
|
|
146
|
+
const resolved = checkCandidateBase(path.join(dir, executable));
|
|
147
|
+
if (resolved) {
|
|
148
|
+
return resolved;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
return null;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Safely quotes a single argument for `cmd.exe /d /s /c "..."` execution on Windows,
|
|
157
|
+
* preventing CVE-2024-27980 batch argument injection and `%VAR%` expansion.
|
|
158
|
+
*/
|
|
159
|
+
export function escapeCmdArg(value, isExecutable = false) {
|
|
160
|
+
const str = String(value);
|
|
161
|
+
if (str.length === 0) {
|
|
162
|
+
return '""';
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Escape % so cmd.exe does not expand %TEMP% or strip %tokens
|
|
166
|
+
let escaped = str.replace(/%/g, '%%');
|
|
167
|
+
|
|
168
|
+
if (isExecutable) {
|
|
169
|
+
return /[\s&|<>()^"!;,]/.test(escaped) ? `"${escaped.replace(/"/g, '')}"` : escaped;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
const needsQuotes = /[\s&|<>()^"!;,]/.test(escaped);
|
|
173
|
+
if (!needsQuotes) {
|
|
174
|
+
return escaped;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Escape trailing backslashes before closing quote and internal double quotes
|
|
178
|
+
escaped = escaped.replace(/(\\*)"/g, '$1$1\\"');
|
|
179
|
+
escaped = escaped.replace(/(\\*)$/, '$1$1');
|
|
180
|
+
return `"${escaped}"`;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Safely quotes an argument for PowerShell `-Command` invocation.
|
|
185
|
+
*/
|
|
186
|
+
function escapePowerShellArg(value) {
|
|
187
|
+
const str = String(value);
|
|
188
|
+
if (/^[A-Za-z0-9_./:\\-]+$/.test(str)) {
|
|
189
|
+
return str;
|
|
190
|
+
}
|
|
191
|
+
return `'${str.replace(/'/g, "''")}'`;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Quotes tokens for POSIX / Windows `shell: true` command strings when shell operators are present.
|
|
196
|
+
*/
|
|
197
|
+
const SHELL_OPERATORS = new Set(['|', '||', '&', '&&', ';', '>', '>>', '<', '2>', '2>>']);
|
|
198
|
+
|
|
199
|
+
export function buildShellCommandString(executable, args) {
|
|
200
|
+
const quoteToken = (token) => {
|
|
201
|
+
if (SHELL_OPERATORS.has(token) || /^(?:[12]?>|[12]?>>|<)/.test(token)) {
|
|
202
|
+
return token;
|
|
203
|
+
}
|
|
204
|
+
if (!/[\s"'`$\\]/.test(token)) {
|
|
205
|
+
return token;
|
|
206
|
+
}
|
|
207
|
+
if (process.platform === 'win32') {
|
|
208
|
+
return `"${token.replace(/"/g, '\\"')}"`;
|
|
209
|
+
}
|
|
210
|
+
return `'${token.replace(/'/g, "'\\''")}'`;
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
return [quoteToken(executable), ...args.map(quoteToken)].join(' ');
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Builds spawn parameters `{ command, args, options }` that work seamlessly across Windows and POSIX
|
|
218
|
+
* without triggering Node DEP0190 warnings or CVE-2024-27980 `.cmd` EINVAL/ENOENT failures.
|
|
219
|
+
*/
|
|
220
|
+
export function prepareSpawnInvocation(parsedCommand, { cwd = process.cwd(), env = process.env, shell = false } = {}) {
|
|
221
|
+
const augmentedEnv = buildAugmentedEnvironment(env, parsedCommand.environment, cwd);
|
|
222
|
+
const rawExe = parsedCommand.executable;
|
|
223
|
+
const rawArgs = parsedCommand.args;
|
|
224
|
+
|
|
225
|
+
// Direct fast-path for ASC's own binaries on all platforms (zero shim overhead)
|
|
226
|
+
if (!shell) {
|
|
227
|
+
const normalizedBase = rawExe.toLowerCase();
|
|
228
|
+
if (normalizedBase === 'asc' || normalizedBase === 'agentic-senior-core') {
|
|
229
|
+
return {
|
|
230
|
+
command: process.execPath,
|
|
231
|
+
args: [ASC_BIN_PATH, ...rawArgs],
|
|
232
|
+
options: { cwd, env: augmentedEnv, shell: false, windowsHide: true },
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
if (normalizedBase === 'ascx') {
|
|
236
|
+
return {
|
|
237
|
+
command: process.execPath,
|
|
238
|
+
args: [ASCX_BIN_PATH, ...rawArgs],
|
|
239
|
+
options: { cwd, env: augmentedEnv, shell: false, windowsHide: true },
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// Explicit shell pipeline / redirect mode: omit args array to avoid Node DEP0190
|
|
245
|
+
if (shell) {
|
|
246
|
+
const commandLine = buildShellCommandString(rawExe, rawArgs);
|
|
247
|
+
return {
|
|
248
|
+
command: commandLine,
|
|
249
|
+
args: undefined,
|
|
250
|
+
options: { cwd, env: augmentedEnv, shell: true, windowsHide: true },
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
if (process.platform !== 'win32') {
|
|
255
|
+
return {
|
|
256
|
+
command: rawExe,
|
|
257
|
+
args: rawArgs,
|
|
258
|
+
options: { cwd, env: augmentedEnv, shell: false, windowsHide: true },
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// Windows resolution: native .exe/.com, .cmd/.bat shims, .ps1 scripts, CMD builtins, and PowerShell cmdlets
|
|
263
|
+
const resolved = resolveWindowsExecutable(rawExe, augmentedEnv, cwd);
|
|
264
|
+
const comspec = augmentedEnv.ComSpec || augmentedEnv.COMSPEC || 'cmd.exe';
|
|
265
|
+
|
|
266
|
+
if (resolved) {
|
|
267
|
+
const ext = path.extname(resolved).toLowerCase();
|
|
268
|
+
|
|
269
|
+
if (ext === '.exe' || ext === '.com') {
|
|
270
|
+
return {
|
|
271
|
+
command: resolved,
|
|
272
|
+
args: rawArgs,
|
|
273
|
+
options: { cwd, env: augmentedEnv, shell: false, windowsHide: true },
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
if (ext === '.js' || ext === '.mjs' || ext === '.cjs') {
|
|
278
|
+
return {
|
|
279
|
+
command: process.execPath,
|
|
280
|
+
args: [resolved, ...rawArgs],
|
|
281
|
+
options: { cwd, env: augmentedEnv, shell: false, windowsHide: true },
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
if (ext === '.cmd' || ext === '.bat') {
|
|
286
|
+
const innerCmd = [escapeCmdArg(resolved, true), ...rawArgs.map(a => escapeCmdArg(a, false))].join(' ');
|
|
287
|
+
return {
|
|
288
|
+
command: comspec,
|
|
289
|
+
args: ['/d', '/s', '/c', `"${innerCmd}"`],
|
|
290
|
+
options: {
|
|
291
|
+
cwd,
|
|
292
|
+
env: augmentedEnv,
|
|
293
|
+
shell: false,
|
|
294
|
+
windowsVerbatimArguments: true,
|
|
295
|
+
windowsHide: true,
|
|
296
|
+
},
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
if (ext === '.ps1') {
|
|
301
|
+
const psExe = resolveWindowsExecutable('pwsh', augmentedEnv, cwd)
|
|
302
|
+
|| resolveWindowsExecutable('powershell', augmentedEnv, cwd)
|
|
303
|
+
|| 'powershell.exe';
|
|
304
|
+
return {
|
|
305
|
+
command: psExe,
|
|
306
|
+
args: ['-NoProfile', '-NonInteractive', '-ExecutionPolicy', 'Bypass', '-File', resolved, ...rawArgs],
|
|
307
|
+
options: { cwd, env: augmentedEnv, shell: false, windowsHide: true },
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
// Check CMD builtins (dir, echo, type, where, etc.)
|
|
313
|
+
if (CMD_BUILTINS.has(rawExe.toLowerCase())) {
|
|
314
|
+
const innerCmd = [rawExe, ...rawArgs.map(a => escapeCmdArg(a, false))].join(' ');
|
|
315
|
+
return {
|
|
316
|
+
command: comspec,
|
|
317
|
+
args: ['/d', '/s', '/c', `"${innerCmd}"`],
|
|
318
|
+
options: {
|
|
319
|
+
cwd,
|
|
320
|
+
env: augmentedEnv,
|
|
321
|
+
shell: false,
|
|
322
|
+
windowsVerbatimArguments: true,
|
|
323
|
+
windowsHide: true,
|
|
324
|
+
},
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
// Check PowerShell Verb-Noun cmdlets (Get-ChildItem, Select-String, Test-Path, etc.)
|
|
329
|
+
if (POWERSHELL_CMDLET_PATTERN.test(rawExe)) {
|
|
330
|
+
const psExe = resolveWindowsExecutable('pwsh', augmentedEnv, cwd)
|
|
331
|
+
|| resolveWindowsExecutable('powershell', augmentedEnv, cwd)
|
|
332
|
+
|| 'powershell.exe';
|
|
333
|
+
const psCommand = [rawExe, ...rawArgs.map(escapePowerShellArg)].join(' ');
|
|
334
|
+
return {
|
|
335
|
+
command: psExe,
|
|
336
|
+
args: ['-NoProfile', '-NonInteractive', '-ExecutionPolicy', 'Bypass', '-Command', psCommand],
|
|
337
|
+
options: { cwd, env: augmentedEnv, shell: false, windowsHide: true },
|
|
338
|
+
};
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
// Fallback for unknown binaries (preserves clean ENOENT behavior)
|
|
342
|
+
return {
|
|
343
|
+
command: rawExe,
|
|
344
|
+
args: rawArgs,
|
|
345
|
+
options: { cwd, env: augmentedEnv, shell: false, windowsHide: true },
|
|
346
|
+
};
|
|
347
|
+
}
|
|
348
|
+
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { getSlopCatalog, bootstrapPreferences } from '../../core/bootstrap-wizard.mjs';
|
|
2
|
+
import { getPreferencesFilePath } from '../../core/adaptive-preferences.mjs';
|
|
3
|
+
|
|
4
|
+
const RECOMMENDED_PATTERN_IDS = [
|
|
5
|
+
'ui-gradient-purple-blue',
|
|
6
|
+
'ui-generic-card-shadcn',
|
|
7
|
+
'ui-card-in-card-nesting',
|
|
8
|
+
'ui-ghost-card',
|
|
9
|
+
'ui-eyebrow-tracked-caps',
|
|
10
|
+
'ui-gradient-text-cliche',
|
|
11
|
+
'ui-transition-all-layout-cost',
|
|
12
|
+
'ui-stripped-focus-ring',
|
|
13
|
+
'ui-viewport-100vh-mobile',
|
|
14
|
+
'ui-missing-reduced-motion',
|
|
15
|
+
'copy-marketing-buzzwords',
|
|
16
|
+
'copy-ai-buzzwords',
|
|
17
|
+
'copy-cadence-tricolon',
|
|
18
|
+
'copy-cadence-rebuttal',
|
|
19
|
+
'copy-hybrid-neologism',
|
|
20
|
+
'code-decorative-banner',
|
|
21
|
+
'code-step-narration',
|
|
22
|
+
];
|
|
23
|
+
|
|
24
|
+
export async function runBootstrapCommand(args = []) {
|
|
25
|
+
const catalog = getSlopCatalog();
|
|
26
|
+
const isHelp = args.includes('--help') || args.includes('-h');
|
|
27
|
+
const isList = args.includes('--list');
|
|
28
|
+
const isRecommended = args.includes('--recommended') || args.includes('--all');
|
|
29
|
+
const scope = (args.includes('--global') || args.includes('--user')) ? 'user' : 'project';
|
|
30
|
+
const explicitIds = args.filter(a => !a.startsWith('-'));
|
|
31
|
+
|
|
32
|
+
if (isHelp || isList || (!isRecommended && explicitIds.length === 0)) {
|
|
33
|
+
console.log('Agentic Senior Core -- Anti-Slop Preference Bootstrap\n');
|
|
34
|
+
console.log('Usage:');
|
|
35
|
+
console.log(' asc bootstrap --list List all curated anti-slop pattern IDs');
|
|
36
|
+
console.log(' asc bootstrap --recommended [--global] Seed core UI & prose anti-slop rules');
|
|
37
|
+
console.log(' asc bootstrap <id1> <id2> [--global] Seed specific pattern IDs\n');
|
|
38
|
+
console.log(`Available catalog patterns (${catalog.length}):`);
|
|
39
|
+
for (const item of catalog) {
|
|
40
|
+
console.log(` ${item.id.padEnd(32)} ${item.message}`);
|
|
41
|
+
}
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const selectedIds = isRecommended ? RECOMMENDED_PATTERN_IDS : explicitIds;
|
|
46
|
+
const results = bootstrapPreferences({
|
|
47
|
+
cwd: process.cwd(),
|
|
48
|
+
scope,
|
|
49
|
+
selectedIds,
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
const targetFile = getPreferencesFilePath({ cwd: process.cwd(), scope });
|
|
53
|
+
console.log(`Seeded ${results.length} preference rule(s) into ${scope} scope:`);
|
|
54
|
+
console.log(` ${targetFile}`);
|
|
55
|
+
}
|
|
56
|
+
|