waitsec 0.3.0 → 0.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/.cursor-plugin/plugin.json +1 -1
- package/README.md +7 -1
- package/bin/cli.mjs +266 -0
- package/package.json +8 -4
- package/plugin.json +1 -1
- package/skills/waitsec-code/SKILL.md +1 -1
- package/skills/waitsec-core/SKILL.md +1 -1
- package/skills/waitsec-quality/SKILL.md +1 -1
- package/skills/waitsec-ui/SKILL.md +1 -1
- package/bin/cli.js +0 -66
package/README.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# waitsec
|
|
2
2
|
|
|
3
|
+
<p align="center">
|
|
4
|
+
<a href="https://skills.sh/fastroware/waitsec"><img src="https://skills.sh/b/fastroware/waitsec" alt="skills.sh"></a>
|
|
5
|
+
<a href="https://www.npmjs.com/package/waitsec"><img src="https://img.shields.io/npm/v/waitsec?color=crimson" alt="npm version"></a>
|
|
6
|
+
<a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-2ea44f" alt="License: MIT"></a>
|
|
7
|
+
</p>
|
|
8
|
+
|
|
3
9
|
> **Hold on. Think first. Code less.**
|
|
4
10
|
|
|
5
11
|
`waitsec` gives your AI coding agent practical guardrails. It prevents AI from writing hundreds of unneeded lines, inventing imaginary requirements, or over-complicating simple tasks.
|
|
@@ -119,7 +125,7 @@ waitsec/
|
|
|
119
125
|
│ ├── AGENTS.md # Universal rule pointer (Antigravity / Claude Code)
|
|
120
126
|
│ └── waitsec.md # All-in-one bundled rules (Kilo Code / Cline / Cursor)
|
|
121
127
|
├── bin/
|
|
122
|
-
│ └── cli.
|
|
128
|
+
│ └── cli.mjs # Interactive terminal installer (Clack prompts)
|
|
123
129
|
├── plugin.json # Antigravity plugin manifest
|
|
124
130
|
├── package.json # npm / npx manifest
|
|
125
131
|
└── composer.json # Composer / Laravel manifest
|
package/bin/cli.mjs
ADDED
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import fs from 'node:fs';
|
|
5
|
+
import os from 'node:os';
|
|
6
|
+
import { fileURLToPath } from 'node:url';
|
|
7
|
+
import pc from 'picocolors';
|
|
8
|
+
import { intro, outro, select, multiselect, confirm, isCancel, cancel, log, spinner } from '@clack/prompts';
|
|
9
|
+
|
|
10
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
11
|
+
const __dirname = path.dirname(__filename);
|
|
12
|
+
const REPO_ROOT = path.resolve(__dirname, '..');
|
|
13
|
+
const SKILLS_SOURCE_DIR = path.join(REPO_ROOT, 'skills');
|
|
14
|
+
const RULES_SOURCE_FILE = path.join(REPO_ROOT, 'rules', 'waitsec.md');
|
|
15
|
+
|
|
16
|
+
const CORE_SKILL = 'waitsec-core';
|
|
17
|
+
|
|
18
|
+
const AVAILABLE_SKILLS = [
|
|
19
|
+
{
|
|
20
|
+
value: 'waitsec-core',
|
|
21
|
+
label: 'waitsec-core',
|
|
22
|
+
hint: '5 core guardrails: ask-first, anti-overengineering, small-diff, debug-first, verify-first',
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
value: 'waitsec-quality',
|
|
26
|
+
label: 'waitsec-quality (preview)',
|
|
27
|
+
hint: 'Security audits, test discipline, data integrity',
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
value: 'waitsec-code',
|
|
31
|
+
label: 'waitsec-code (preview)',
|
|
32
|
+
hint: 'Clean code rules, anti-comment noise, dependency control',
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
value: 'waitsec-ui',
|
|
36
|
+
label: 'waitsec-ui (preview)',
|
|
37
|
+
hint: 'Anti-slop UI copy & CSS, responsive guardrails',
|
|
38
|
+
},
|
|
39
|
+
];
|
|
40
|
+
|
|
41
|
+
const AGENTS = [
|
|
42
|
+
{ id: 'antigravity', label: 'Antigravity / Universal', skillDir: '.agents/skills', ruleFile: 'AGENTS.md' },
|
|
43
|
+
{ id: 'claude', label: 'Claude Code', skillDir: '.claude/skills', ruleFile: 'CLAUDE.md' },
|
|
44
|
+
{ id: 'cursor', label: 'Cursor', skillDir: '.cursor/skills', ruleFile: '.cursorrules' },
|
|
45
|
+
{ id: 'kilo', label: 'Kilo Code (VS Code)', skillDir: '.kilo/skills', ruleFile: '.kilorules' },
|
|
46
|
+
{ id: 'cline', label: 'Cline / Roo Code', skillDir: '.cline/skills', ruleFile: '.clinerules' },
|
|
47
|
+
{ id: 'codex', label: 'Codex', skillDir: '.codex/skills', ruleFile: 'AGENTS.md' },
|
|
48
|
+
{ id: 'gemini', label: 'Gemini CLI', skillDir: '.gemini/skills', ruleFile: 'GEMINI.md' },
|
|
49
|
+
];
|
|
50
|
+
|
|
51
|
+
function stop(message) {
|
|
52
|
+
cancel(message);
|
|
53
|
+
process.exit(0);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function copyDirSync(src, dest) {
|
|
57
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
58
|
+
for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
|
|
59
|
+
const srcPath = path.join(src, entry.name);
|
|
60
|
+
const destPath = path.join(dest, entry.name);
|
|
61
|
+
if (entry.isDirectory()) {
|
|
62
|
+
copyDirSync(srcPath, destPath);
|
|
63
|
+
} else {
|
|
64
|
+
fs.copyFileSync(srcPath, destPath);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const POINTER_START = '<!-- waitsec:start -->';
|
|
70
|
+
const POINTER_END = '<!-- waitsec:end -->';
|
|
71
|
+
|
|
72
|
+
function getPointerBlock(skills) {
|
|
73
|
+
return [
|
|
74
|
+
POINTER_START,
|
|
75
|
+
'# waitsec: AI Coding Guardrails',
|
|
76
|
+
'> Hold on. Think first. Code less.',
|
|
77
|
+
'',
|
|
78
|
+
'Follow the waitsec engineering discipline for all tasks in this workspace:',
|
|
79
|
+
'- **Core Guardrails Active**: ' + skills.map(s => '`' + s + '`').join(', '),
|
|
80
|
+
'- When requirements are ambiguous: pause and ask 1 to 3 direct questions with concrete options.',
|
|
81
|
+
'- Keep solutions lean: reject enterprise boilerplate; never compromise security or input validation.',
|
|
82
|
+
'- Keep diffs surgical: touch only the files strictly required to solve the prompt.',
|
|
83
|
+
'- Debug from evidence: inspect stack traces and root causes before guessing.',
|
|
84
|
+
'- Verify before declaring done: run builds, tests, and verify edge cases.',
|
|
85
|
+
POINTER_END,
|
|
86
|
+
].join('\n');
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function updateRuleFile(filePath, content, isPointer = false) {
|
|
90
|
+
if (!fs.existsSync(filePath)) {
|
|
91
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
92
|
+
fs.writeFileSync(filePath, content, 'utf8');
|
|
93
|
+
return 'created';
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const existing = fs.readFileSync(filePath, 'utf8');
|
|
97
|
+
if (isPointer) {
|
|
98
|
+
if (existing.includes(POINTER_START) && existing.includes(POINTER_END)) {
|
|
99
|
+
const regex = new RegExp(`${POINTER_START}[\\s\\S]*?${POINTER_END}`, 'g');
|
|
100
|
+
const updated = existing.replace(regex, content);
|
|
101
|
+
fs.writeFileSync(filePath, updated, 'utf8');
|
|
102
|
+
return 'updated';
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (existing.includes('waitsec: AI Coding Guardrails') || existing.includes(POINTER_START)) {
|
|
107
|
+
return 'already-configured';
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
fs.appendFileSync(filePath, `\n\n${content}`, 'utf8');
|
|
111
|
+
return 'appended';
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function detectActiveAgents(baseDir) {
|
|
115
|
+
return AGENTS.filter((agent) => {
|
|
116
|
+
const rootFolder = agent.skillDir.split('/')[0];
|
|
117
|
+
const folderExists = fs.existsSync(path.join(baseDir, rootFolder));
|
|
118
|
+
const ruleExists = agent.ruleFile && fs.existsSync(path.join(baseDir, agent.ruleFile));
|
|
119
|
+
return folderExists || ruleExists;
|
|
120
|
+
}).map((a) => a.id);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
async function main() {
|
|
124
|
+
if (process.argv.includes('--version') || process.argv.includes('-v')) {
|
|
125
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(REPO_ROOT, 'package.json'), 'utf8'));
|
|
126
|
+
console.log(`waitsec v${pkg.version}`);
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
console.log(`
|
|
131
|
+
${pc.bold(pc.cyan('██╗ ██╗ █████╗ ██╗████████╗███████╗███████╗ ██████╗'))}
|
|
132
|
+
${pc.bold(pc.cyan('██║ ██║██╔══██╗██║╚══██╔══╝██╔════╝██╔════╝██╔════╝'))}
|
|
133
|
+
${pc.bold(pc.cyan('██║ █╗ ██║███████║██║ ██║ ███████╗█████╗ ██║ '))}
|
|
134
|
+
${pc.bold(pc.cyan('██║███╗██║██╔══██║██║ ██║ ╚════██║██╔══╝ ██║ '))}
|
|
135
|
+
${pc.bold(pc.cyan('╚███╔███╔╝██║ ██║██║ ██║ ███████║███████╗╚██████╗'))}
|
|
136
|
+
${pc.bold(pc.cyan(' ╚══╝╚══╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚══════╝╚══════╝ ╚═════╝'))}
|
|
137
|
+
${pc.dim(' "Hold on. Think first. Code less."')}
|
|
138
|
+
`);
|
|
139
|
+
|
|
140
|
+
intro(pc.bold('Install waitsec guardrails into your AI coding setup'));
|
|
141
|
+
|
|
142
|
+
log.step(pc.bold('1. Select Skills to Install'));
|
|
143
|
+
const selectedSkills = await multiselect({
|
|
144
|
+
message: 'Select the skills you want (Press Space to select, Enter to confirm):',
|
|
145
|
+
options: AVAILABLE_SKILLS,
|
|
146
|
+
initialValues: ['waitsec-core'],
|
|
147
|
+
required: 'You must select at least one skill.',
|
|
148
|
+
});
|
|
149
|
+
if (isCancel(selectedSkills)) stop('Installation cancelled.');
|
|
150
|
+
|
|
151
|
+
log.step(pc.bold('2. Choose Installation Scope'));
|
|
152
|
+
const scope = await select({
|
|
153
|
+
message: 'Where do you want waitsec to be installed?',
|
|
154
|
+
options: [
|
|
155
|
+
{
|
|
156
|
+
value: 'project',
|
|
157
|
+
label: 'This project only',
|
|
158
|
+
hint: 'Creates rules and skill folders in current workspace',
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
value: 'global',
|
|
162
|
+
label: 'Everywhere (Global)',
|
|
163
|
+
hint: 'Installs directly to your machine home directory across all projects',
|
|
164
|
+
},
|
|
165
|
+
],
|
|
166
|
+
});
|
|
167
|
+
if (isCancel(scope)) stop('Installation cancelled.');
|
|
168
|
+
|
|
169
|
+
const baseDir = scope === 'global' ? os.homedir() : process.cwd();
|
|
170
|
+
const detectedAgentIds = detectActiveAgents(baseDir);
|
|
171
|
+
|
|
172
|
+
log.step(pc.bold('3. Choose Your AI Agents / Editors'));
|
|
173
|
+
const chosenAgentIds = await multiselect({
|
|
174
|
+
message: 'Which coding assistants or editors do you use? (Press Space to select):',
|
|
175
|
+
options: AGENTS.map((a) => ({
|
|
176
|
+
value: a.id,
|
|
177
|
+
label: a.label,
|
|
178
|
+
hint: detectedAgentIds.includes(a.id)
|
|
179
|
+
? pc.green('found in environment')
|
|
180
|
+
: pc.dim(a.ruleFile ? `configures ${a.ruleFile}` : 'creates skill folder'),
|
|
181
|
+
})),
|
|
182
|
+
initialValues: detectedAgentIds.length > 0 ? detectedAgentIds : ['antigravity', 'cursor', 'claude', 'kilo'],
|
|
183
|
+
required: 'Please pick at least one assistant or editor.',
|
|
184
|
+
});
|
|
185
|
+
if (isCancel(chosenAgentIds)) stop('Installation cancelled.');
|
|
186
|
+
|
|
187
|
+
const chosenAgents = AGENTS.filter((a) => chosenAgentIds.includes(a.id));
|
|
188
|
+
|
|
189
|
+
let overwrite = false;
|
|
190
|
+
const existingDestinations = [];
|
|
191
|
+
for (const agent of chosenAgents) {
|
|
192
|
+
for (const skill of selectedSkills) {
|
|
193
|
+
const checkPath = path.join(baseDir, agent.skillDir, skill);
|
|
194
|
+
if (fs.existsSync(checkPath)) {
|
|
195
|
+
existingDestinations.push(checkPath);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
if (existingDestinations.length > 0) {
|
|
201
|
+
const conflictAction = await select({
|
|
202
|
+
message: `${existingDestinations.length} skill folder(s) already exist. What would you like to do?`,
|
|
203
|
+
options: [
|
|
204
|
+
{ value: 'overwrite', label: 'Overwrite with latest version', hint: 'recommended' },
|
|
205
|
+
{ value: 'skip', label: 'Keep existing folders', hint: 'skip copying over existing skills' },
|
|
206
|
+
],
|
|
207
|
+
});
|
|
208
|
+
if (isCancel(conflictAction)) stop('Installation cancelled.');
|
|
209
|
+
overwrite = conflictAction === 'overwrite';
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const s = spinner();
|
|
213
|
+
s.start('Installing waitsec guardrails...');
|
|
214
|
+
|
|
215
|
+
let copiedSkillsCount = 0;
|
|
216
|
+
for (const agent of chosenAgents) {
|
|
217
|
+
for (const skill of selectedSkills) {
|
|
218
|
+
const srcDir = path.join(SKILLS_SOURCE_DIR, skill);
|
|
219
|
+
const destDir = path.join(baseDir, agent.skillDir, skill);
|
|
220
|
+
|
|
221
|
+
if (!fs.existsSync(srcDir)) continue;
|
|
222
|
+
if (fs.existsSync(destDir) && !overwrite) continue;
|
|
223
|
+
|
|
224
|
+
if (fs.existsSync(destDir) && overwrite) {
|
|
225
|
+
fs.rmSync(destDir, { recursive: true, force: true });
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
copyDirSync(srcDir, destDir);
|
|
229
|
+
copiedSkillsCount++;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
const configuredRules = [];
|
|
234
|
+
const rulesContent = fs.existsSync(RULES_SOURCE_FILE)
|
|
235
|
+
? fs.readFileSync(RULES_SOURCE_FILE, 'utf8')
|
|
236
|
+
: getPointerBlock(selectedSkills);
|
|
237
|
+
|
|
238
|
+
for (const agent of chosenAgents) {
|
|
239
|
+
if (!agent.ruleFile) continue;
|
|
240
|
+
const rulePath = path.join(baseDir, agent.ruleFile);
|
|
241
|
+
const isSpecialRule = agent.id === 'kilo' || agent.id === 'cline' || agent.id === 'cursor';
|
|
242
|
+
const contentToWrite = isSpecialRule ? rulesContent : getPointerBlock(selectedSkills);
|
|
243
|
+
const action = updateRuleFile(rulePath, contentToWrite, !isSpecialRule);
|
|
244
|
+
configuredRules.push({ file: agent.ruleFile, action });
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
s.stop(pc.green('Installation complete!'));
|
|
248
|
+
|
|
249
|
+
console.log('');
|
|
250
|
+
log.message(
|
|
251
|
+
pc.bold('Installed Skills & Configuration Details:') + '\n' +
|
|
252
|
+
chosenAgents.map(a => ` ${pc.cyan('●')} ${pc.bold(a.label)}: ${pc.dim(path.join(baseDir, a.skillDir))}`).join('\n') +
|
|
253
|
+
'\n' +
|
|
254
|
+
configuredRules.map(r => ` ${pc.green('✔')} Configured rule: ${pc.bold(r.file)} (${r.action})`).join('\n')
|
|
255
|
+
);
|
|
256
|
+
|
|
257
|
+
outro(
|
|
258
|
+
pc.bold(pc.green('waitsec is active.')) + ' ' +
|
|
259
|
+
pc.dim('Your AI will now think first, keep diffs small, and prevent overengineering.')
|
|
260
|
+
);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
main().catch((err) => {
|
|
264
|
+
console.error(pc.red('Unexpected error:'), err);
|
|
265
|
+
process.exit(1);
|
|
266
|
+
});
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "waitsec",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Practical guardrails for AI coding agents. Hold on, think first, code less.",
|
|
5
5
|
"main": "rules/waitsec.md",
|
|
6
6
|
"bin": {
|
|
7
|
-
"waitsec": "bin/cli.
|
|
7
|
+
"waitsec": "bin/cli.mjs"
|
|
8
8
|
},
|
|
9
9
|
"scripts": {
|
|
10
|
-
"start": "node ./bin/cli.
|
|
10
|
+
"start": "node ./bin/cli.mjs",
|
|
11
11
|
"ship": "node ./scripts/ship.js"
|
|
12
12
|
},
|
|
13
13
|
"keywords": [
|
|
@@ -40,5 +40,9 @@
|
|
|
40
40
|
"plugin.json",
|
|
41
41
|
"README.md",
|
|
42
42
|
"LICENSE"
|
|
43
|
-
]
|
|
43
|
+
],
|
|
44
|
+
"dependencies": {
|
|
45
|
+
"@clack/prompts": "^1.8.0",
|
|
46
|
+
"picocolors": "^1.1.1"
|
|
47
|
+
}
|
|
44
48
|
}
|
package/plugin.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: waitsec-core
|
|
3
|
-
description: Core guardrails for AI coding agents. Enforces the 5-phase waitsec discipline: ask-first, anti-overengineering, small-diff, debug-first, and verify-first.
|
|
3
|
+
description: "Core guardrails for AI coding agents. Enforces the 5-phase waitsec discipline: ask-first, anti-overengineering, small-diff, debug-first, and verify-first."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# waitsec-core: The 5 Foundational Guardrails
|
package/bin/cli.js
DELETED
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
const fs = require('fs');
|
|
4
|
-
const path = require('path');
|
|
5
|
-
const readline = require('readline');
|
|
6
|
-
|
|
7
|
-
const rl = readline.createInterface({
|
|
8
|
-
input: process.stdin,
|
|
9
|
-
output: process.stdout
|
|
10
|
-
});
|
|
11
|
-
|
|
12
|
-
const sourceRulePath = path.join(__dirname, '..', 'rules', 'waitsec.md');
|
|
13
|
-
|
|
14
|
-
console.log(`
|
|
15
|
-
=========================================
|
|
16
|
-
waitsec: AI Coding Guardrails Installer
|
|
17
|
-
"Hold on. Think first. Code less."
|
|
18
|
-
=========================================
|
|
19
|
-
`);
|
|
20
|
-
|
|
21
|
-
console.log('Select your editor / coding agent:\n');
|
|
22
|
-
console.log(' 1) Kilo Code (.kilorules)');
|
|
23
|
-
console.log(' 2) Cline / Roo Code (.clinerules)');
|
|
24
|
-
console.log(' 3) Cursor (.cursorrules)');
|
|
25
|
-
console.log(' 4) Antigravity / Universal (AGENTS.md)');
|
|
26
|
-
console.log(' 5) All of the above\n');
|
|
27
|
-
|
|
28
|
-
rl.question('Enter number [1-5] (default: 1): ', (answer) => {
|
|
29
|
-
const choice = (answer || '1').trim();
|
|
30
|
-
const cwd = process.cwd();
|
|
31
|
-
|
|
32
|
-
if (!fs.existsSync(sourceRulePath)) {
|
|
33
|
-
console.error(`Error: Rule template not found at ${sourceRulePath}`);
|
|
34
|
-
rl.close();
|
|
35
|
-
process.exit(1);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
const ruleContent = fs.readFileSync(sourceRulePath, 'utf8');
|
|
39
|
-
|
|
40
|
-
const targets = [];
|
|
41
|
-
if (choice === '1') targets.push('.kilorules');
|
|
42
|
-
else if (choice === '2') targets.push('.clinerules');
|
|
43
|
-
else if (choice === '3') targets.push('.cursorrules');
|
|
44
|
-
else if (choice === '4') targets.push('AGENTS.md');
|
|
45
|
-
else if (choice === '5') targets.push('.kilorules', '.clinerules', '.cursorrules', 'AGENTS.md');
|
|
46
|
-
else {
|
|
47
|
-
console.log('Unknown choice, defaulting to .kilorules');
|
|
48
|
-
targets.push('.kilorules');
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
targets.forEach((filename) => {
|
|
52
|
-
const destPath = path.join(cwd, filename);
|
|
53
|
-
if (fs.existsSync(destPath)) {
|
|
54
|
-
console.log(`[!] ${filename} already exists. Appending waitsec rules...`);
|
|
55
|
-
fs.appendFileSync(destPath, `\n\n${ruleContent}`);
|
|
56
|
-
} else {
|
|
57
|
-
fs.writeFileSync(destPath, ruleContent, 'utf8');
|
|
58
|
-
console.log(`[+] Created ${filename}`);
|
|
59
|
-
}
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
console.log('\nSuccess! waitsec rules are now active in this project.');
|
|
63
|
-
console.log('Your AI assistant will now pause, check requirements, and avoid bloated code.\n');
|
|
64
|
-
|
|
65
|
-
rl.close();
|
|
66
|
-
});
|