clckernel 1.2.6 → 1.2.9
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/README.es.md +103 -110
- package/README.md +100 -108
- package/package.json +14 -2
- package/src/adapters/agent-os.js +206 -0
- package/src/catalog.js +16 -0
- package/src/detector.js +2 -0
- package/src/generator.js +39 -62
- package/src/index.js +11 -0
- package/src/ui.js +79 -35
- package/tools/audit.js +0 -0
- package/tools/audit.py +0 -0
- package/tools/check_custom.js +0 -0
- package/tools/check_custom.py +0 -0
- package/tools/check_db_efficiency.py +0 -0
- package/tools/check_domain_data.js +100 -0
- package/tools/check_hitl.js +93 -0
- package/tools/check_responsive.js +0 -0
- package/tools/check_seo.js +1 -1
- package/tools/check_symlinks.js +76 -0
- package/tools/check_test_calendar_sync.js +111 -0
- package/tools/scan_secrets.js +12 -1
- package/tools/scan_secrets.py +0 -0
- package/AGENTS.md +0 -124
- package/docs/Journal/001-adr-clckernel-governance.md +0 -18
- package/test/adapters/astro.test.js +0 -102
- package/test/adapters/base.test.js +0 -86
- package/test/adapters/django.test.js +0 -95
- package/test/adapters/fastapi.test.js +0 -88
- package/test/adapters/go.test.js +0 -81
- package/test/adapters/laravel.test.js +0 -106
- package/test/adapters/nextjs.test.js +0 -113
- package/test/adapters/rails.test.js +0 -108
- package/test/adapters/rust.test.js +0 -83
- package/test/catalog.test.js +0 -170
- package/test/config.test.js +0 -512
- package/test/detector.test.js +0 -345
- package/test/doctor.test.js +0 -302
- package/test/generator.test.js +0 -419
- package/test/guards_new.test.js +0 -95
- package/test/helpers.js +0 -36
- package/test/integration/cli-flow.test.js +0 -270
- package/test/technologies/celery_guard.test.js +0 -185
- package/test/technologies/detector.test.js +0 -342
- package/test/technologies/docker_guard.test.js +0 -187
- package/test/technologies/integration.test.js +0 -123
- package/test/technologies/postgres_guard.test.js +0 -87
- package/test/technologies/redis_guard.test.js +0 -128
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLC Kernel — Agent-OS & Domain Workflows Stack Adapter
|
|
3
|
+
* Supports AI Agent Operating Systems (Marketing OS, Content Ops, Research OS)
|
|
4
|
+
* featuring Dual-Layer Governance and Domain Integrity Safeguards.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const fs = require('fs');
|
|
8
|
+
const path = require('path');
|
|
9
|
+
const BaseAdapter = require('./base');
|
|
10
|
+
|
|
11
|
+
class AgentOSAdapter extends BaseAdapter {
|
|
12
|
+
constructor() {
|
|
13
|
+
super('Agent-OS (Domain & AI Workflows)', 'agent-os', 'Playbook / Contract Test');
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
detect(targetDir) {
|
|
17
|
+
// 1. package.json check
|
|
18
|
+
const pkgPath = path.join(targetDir, 'package.json');
|
|
19
|
+
if (fs.existsSync(pkgPath)) {
|
|
20
|
+
try {
|
|
21
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
|
|
22
|
+
const name = (pkg.name || '').toLowerCase();
|
|
23
|
+
const desc = (pkg.description || '').toLowerCase();
|
|
24
|
+
const keywords = Array.isArray(pkg.keywords) ? pkg.keywords.map(k => k.toLowerCase()) : [];
|
|
25
|
+
if (
|
|
26
|
+
name.includes('agent-os') || name.includes('marketing-os') || name.includes('laila-mos') ||
|
|
27
|
+
desc.includes('agent-os') || desc.includes('marketing operating system') ||
|
|
28
|
+
keywords.includes('agent-os') || keywords.includes('marketing-os') || keywords.includes('ai-agents')
|
|
29
|
+
) {
|
|
30
|
+
return true;
|
|
31
|
+
}
|
|
32
|
+
} catch {}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// 2. skills/ or .agents/skills/ directory check
|
|
36
|
+
const skillsDir = path.join(targetDir, 'skills');
|
|
37
|
+
const agentSkillsDir = path.join(targetDir, '.agents', 'skills');
|
|
38
|
+
if (fs.existsSync(skillsDir) || fs.existsSync(agentSkillsDir)) {
|
|
39
|
+
const dirToCheck = fs.existsSync(skillsDir) ? skillsDir : agentSkillsDir;
|
|
40
|
+
try {
|
|
41
|
+
const files = fs.readdirSync(dirToCheck);
|
|
42
|
+
if (files.some(f => f.endsWith('.md'))) {
|
|
43
|
+
return true;
|
|
44
|
+
}
|
|
45
|
+
} catch {}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// 3. brand/ or templates/ check alongside README referencing agents/workflows
|
|
49
|
+
const brandPath = path.join(targetDir, 'brand');
|
|
50
|
+
const templatesPath = path.join(targetDir, 'templates');
|
|
51
|
+
const readmePath = path.join(targetDir, 'README.md');
|
|
52
|
+
if ((fs.existsSync(brandPath) || fs.existsSync(templatesPath)) && fs.existsSync(readmePath)) {
|
|
53
|
+
try {
|
|
54
|
+
const readme = fs.readFileSync(readmePath, 'utf-8').toLowerCase();
|
|
55
|
+
if (readme.includes('subagent') || readme.includes('operating system') || readme.includes('agent')) {
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
} catch {}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
getSafeguards() {
|
|
65
|
+
return [
|
|
66
|
+
'Dual-Layer Architecture: Layer 1 (Engineering) & Layer 2 (Domain Runtime)',
|
|
67
|
+
'Mandatory Human-in-the-Loop (HITL) Checkpoints',
|
|
68
|
+
'Symlink Interoperability (.cursorrules, CLAUDE.md, GEMINI.md, .windsurfrules)',
|
|
69
|
+
'Domain Data Integrity & Clean Creation State (No Hallucinated Metrics)',
|
|
70
|
+
'Single Source of Truth (SSOT) Memory Primacy',
|
|
71
|
+
'Local-only Spec Driven Development (sdds/)'
|
|
72
|
+
];
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
getTools() {
|
|
76
|
+
return [
|
|
77
|
+
{
|
|
78
|
+
name: 'check_symlinks',
|
|
79
|
+
language: 'node',
|
|
80
|
+
path: 'tools/check_symlinks.js',
|
|
81
|
+
command: 'node tools/check_symlinks.js',
|
|
82
|
+
description: 'AI IDE symlinks and rule mirror verification'
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
name: 'check_hitl',
|
|
86
|
+
language: 'node',
|
|
87
|
+
path: 'tools/check_hitl.js',
|
|
88
|
+
command: 'node tools/check_hitl.js',
|
|
89
|
+
description: 'Human-in-the-Loop review checkpoint validator'
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
name: 'check_domain_data',
|
|
93
|
+
language: 'node',
|
|
94
|
+
path: 'tools/check_domain_data.js',
|
|
95
|
+
command: 'node tools/check_domain_data.js',
|
|
96
|
+
description: 'Domain deliverables schema and clean state integrity'
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
name: 'check_test_calendar_sync',
|
|
100
|
+
language: 'node',
|
|
101
|
+
path: 'tools/check_test_calendar_sync.js',
|
|
102
|
+
command: 'node tools/check_test_calendar_sync.js',
|
|
103
|
+
description: 'Test calendar harness synchronization and parity check'
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
name: 'scan_secrets',
|
|
107
|
+
language: 'node',
|
|
108
|
+
path: 'tools/scan_secrets.js',
|
|
109
|
+
command: 'node tools/scan_secrets.js',
|
|
110
|
+
description: 'Security & API key leak scanner'
|
|
111
|
+
}
|
|
112
|
+
];
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
provision(targetDir, config) {
|
|
116
|
+
// 1. Create docs/, sdds/, and tools/
|
|
117
|
+
super.provision(targetDir, config);
|
|
118
|
+
|
|
119
|
+
// 2. Write Dual-Layer AGENTS.md
|
|
120
|
+
const dualLayerAgents = `# Standard Operating Procedure (SOP) — AGENTS
|
|
121
|
+
Governed by **CLC Kernel: The Universal AI Agent Governance Engine**.
|
|
122
|
+
Target System: **${this.name}**
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
## 🛠️ Layer 1: Development & Maintenance Governance (Engineering)
|
|
127
|
+
All AI Agents (Antigravity, OpenCode, Claude Code, Cursor, Windsurf, Copilot) developing or maintaining this codebase MUST adhere to strict engineering standards:
|
|
128
|
+
|
|
129
|
+
> 🚨 **RULE #0: MANDATORY EXECUTION OVERRIDE RULE (UNBYPASSABLE)**
|
|
130
|
+
> Even when the user issues a direct or urgent fix request ("fix this bug", "fix this error", "quick fix"):
|
|
131
|
+
> YOU ARE STRICTLY FORBIDDEN from modifying source code or workflows directly without completing the full quality harness:
|
|
132
|
+
> 1. **Research & Root Cause Analysis:** Investigate tracebacks and affected files before editing.
|
|
133
|
+
> 2. **SDD Specification:** Document non-trivial changes in \`sdds/{change-name}/01-spec.md\` (gitignored).
|
|
134
|
+
> 3. **Verification (Red Phase):** Write a failing test or contract validation first.
|
|
135
|
+
> 4. **Clean Implementation (Green Phase):** Make tests pass maintaining strict layer isolation.
|
|
136
|
+
> 5. **Mandatory Audit Gate:** Execute \`node tools/audit.js\` and output summary to stdout.
|
|
137
|
+
|
|
138
|
+
### Engineering Rules
|
|
139
|
+
1. **Conventional Commits Only**: Commits must use Conventional Commits (e.g. \`feat(...): ...\`, \`fix(...): ...\`). NEVER add \`Co-Authored-By\` or AI attribution.
|
|
140
|
+
2. **Mirror Links Interoperability**: \`CLAUDE.md\`, \`GEMINI.md\`, \`.cursorrules\`, and \`.windsurfrules\` must remain valid symlinks to \`AGENTS.md\`.
|
|
141
|
+
3. **No Superficial Symptom Patches**: Always address root causes.
|
|
142
|
+
|
|
143
|
+
---
|
|
144
|
+
|
|
145
|
+
## 🚀 Layer 2: Domain Runtime Directives (Agent Workflows & Operations)
|
|
146
|
+
When operating as domain agents for end-users and non-technical operators:
|
|
147
|
+
|
|
148
|
+
1. **Non-Technical Operator Friendly**: Interact naturally with the operator. Guide step-by-step through conversational prompts without technical jargon.
|
|
149
|
+
2. **Mandatory Human-in-the-Loop (HITL) Checkpoints**: Always pause phase-by-phase during multi-step pipelines. Present draft output and WAIT for explicit user confirmation before executing irreversible steps.
|
|
150
|
+
3. **SSOT Memory Primacy**: Always read from and persist to designated single-source-of-truth memory files (e.g. \`brand/client-profile.md\` or \`docs/\`).
|
|
151
|
+
4. **Clean Creation State (No Hallucinated Data)**: When new records, calendars, or deliverables are drafted, metric fields must initialize as \`null\` / empty. Never invent fictional stats.
|
|
152
|
+
5. **Deterministic Output Standard**: Outputs must strictly follow valid Markdown, JSON schema, or domain templates.
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
## 🎮 Universal Command Interface (All LLMs & Agents)
|
|
157
|
+
When given a command matching \`clckernel <action>\` or \`/clckernel <action>\`, execute the deterministic state machine below:
|
|
158
|
+
|
|
159
|
+
| Command | Lifecycle Phase | Mandatory Execution Protocol |
|
|
160
|
+
|---|---|---|
|
|
161
|
+
| \`clckernel feature <name>\` | New Feature | 1. Research affected layers.<br>2. Author local spec in \`sdds/{name}/spec.md\`.<br>3. Present HIT review to user and wait for approval.<br>4. Write failing test (Red Phase).<br>5. Implement clean code (Green Phase).<br>6. Run \`node tools/audit.js\` (or \`audit.py\`). |
|
|
162
|
+
| \`clckernel fix <issue>\` | Bug Fix | 1. Investigate root cause (no code edits).<br>2. Reproduce with failing test (Red Phase).<br>3. Minimal surgical fix respecting Clean Arch (Green Phase).<br>4. Run audit gate without skipping. |
|
|
163
|
+
| \`clckernel test\` | Verification | Run test suite and verify clean pass (exit code 0). |
|
|
164
|
+
| \`clckernel audit\` | Verification | Run \`node tools/audit.js\` or \`python tools/audit.py\` and output the Educational Summary. |
|
|
165
|
+
| \`clckernel doctor\` | Diagnostics | Check git pre-commit hooks, IDE symlinks, and AST engine integrity. |
|
|
166
|
+
| \`clckernel commit <message>\` | Version Control | Run full audit, verify tests pass, ensure no changes outside SDD scope, and commit with conventional commits (never add AI attribution). |
|
|
167
|
+
| \`clckernel guard create <name>\` | Safeguards | Scaffold a new AST guard in the stack's native language in \`tools/guards/\`. |
|
|
168
|
+
| \`clckernel start\` | Setup | Scan codebase, propose governance plan, and materialize \`.clckernel.yaml\`. |
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
## 🛡️ Core AI Safeguards
|
|
173
|
+
${this.getSafeguards().map(s => `- ${s}`).join('\n')}
|
|
174
|
+
`;
|
|
175
|
+
|
|
176
|
+
fs.writeFileSync(path.join(targetDir, 'AGENTS.md'), dualLayerAgents, 'utf-8');
|
|
177
|
+
|
|
178
|
+
// 3. Create AI IDE mirror symlinks
|
|
179
|
+
const mirrors = ['CLAUDE.md', 'GEMINI.md', '.cursorrules', '.windsurfrules'];
|
|
180
|
+
for (const mirror of mirrors) {
|
|
181
|
+
const mirrorPath = path.join(targetDir, mirror);
|
|
182
|
+
try {
|
|
183
|
+
if (!fs.existsSync(mirrorPath)) {
|
|
184
|
+
fs.symlinkSync('AGENTS.md', mirrorPath);
|
|
185
|
+
}
|
|
186
|
+
} catch {}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// 4. Copy domain guard tools into tools/
|
|
190
|
+
const srcToolsDir = path.join(__dirname, '..', '..', 'tools');
|
|
191
|
+
const targetToolsDir = path.join(targetDir, 'tools');
|
|
192
|
+
const toolsToCopy = ['check_symlinks.js', 'check_hitl.js', 'check_domain_data.js', 'scan_secrets.js', 'audit.js'];
|
|
193
|
+
|
|
194
|
+
for (const toolFile of toolsToCopy) {
|
|
195
|
+
const srcFile = path.join(srcToolsDir, toolFile);
|
|
196
|
+
const destFile = path.join(targetToolsDir, toolFile);
|
|
197
|
+
if (fs.existsSync(srcFile) && !fs.existsSync(destFile)) {
|
|
198
|
+
try {
|
|
199
|
+
fs.copyFileSync(srcFile, destFile);
|
|
200
|
+
} catch {}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
module.exports = AgentOSAdapter;
|
package/src/catalog.js
CHANGED
|
@@ -110,6 +110,21 @@ const SAFEGUARD_CATALOG = [
|
|
|
110
110
|
applies_when: 'docker', severity: 'error', gate_mode: 'hard', config_keys: ['scope', 'exclude_paths'],
|
|
111
111
|
phase: 'audit', file: 'docker_guard.py', manifest: true, planned: false },
|
|
112
112
|
|
|
113
|
+
{ name: 'check_symlinks', labels: ['check_symlinks', 'check_symlinks.js'],
|
|
114
|
+
checks: 'AI IDE symlinks and rule mirror verification', verify: ['verify_symlinks', 'verify_rule_mirrors'],
|
|
115
|
+
applies_when: 'agent-os', severity: 'error', gate_mode: 'hard', config_keys: ['scope'],
|
|
116
|
+
phase: 'audit', file: 'check_symlinks.js', manifest: true, planned: false },
|
|
117
|
+
|
|
118
|
+
{ name: 'check_hitl', labels: ['check_hitl', 'check_hitl.js'],
|
|
119
|
+
checks: 'Human-in-the-Loop review checkpoint validator in subagent skills', verify: ['verify_hitl', 'verify_human_review_checkpoints'],
|
|
120
|
+
applies_when: 'agent-os', severity: 'error', gate_mode: 'hard', config_keys: ['scope'],
|
|
121
|
+
phase: 'audit', file: 'check_hitl.js', manifest: true, planned: false },
|
|
122
|
+
|
|
123
|
+
{ name: 'check_domain_data', labels: ['check_domain_data', 'check_domain_data.js'],
|
|
124
|
+
checks: 'Domain deliverables schema and clean state integrity', verify: ['verify_domain_data', 'verify_clean_state_metrics'],
|
|
125
|
+
applies_when: 'agent-os', severity: 'error', gate_mode: 'hard', config_keys: ['scope'],
|
|
126
|
+
phase: 'audit', file: 'check_domain_data.js', manifest: true, planned: false },
|
|
127
|
+
|
|
113
128
|
{ name: 'ruff', labels: ['ruff'],
|
|
114
129
|
checks: 'Python AST linter (external CLI)', verify: ['verify_python_lint'],
|
|
115
130
|
applies_when: 'backend', severity: 'warning', gate_mode: 'advisory', config_keys: [],
|
|
@@ -172,6 +187,7 @@ const VALID_PHASES = ['audit', 'test', 'review', 'handover'];
|
|
|
172
187
|
const VALID_APPLIES_WHEN = [
|
|
173
188
|
'always', 'frontend', 'backend', 'fastapi', 'django', 'django|sqlalchemy',
|
|
174
189
|
'celery', 'redis', 'postgresql', 'docker', 'frontend,backend', 'backend,fastapi,django',
|
|
190
|
+
'agent-os',
|
|
175
191
|
];
|
|
176
192
|
|
|
177
193
|
/** Normalize an input label for catalog lookup. */
|
package/src/detector.js
CHANGED
|
@@ -15,9 +15,11 @@ const RailsAdapter = require('./adapters/rails');
|
|
|
15
15
|
const GoAdapter = require('./adapters/go');
|
|
16
16
|
const RustAdapter = require('./adapters/rust');
|
|
17
17
|
const LaravelAdapter = require('./adapters/laravel');
|
|
18
|
+
const AgentOSAdapter = require('./adapters/agent-os');
|
|
18
19
|
const { TechnologyDetector } = require('./technologies/detector');
|
|
19
20
|
|
|
20
21
|
const adapters = [
|
|
22
|
+
new AgentOSAdapter(),
|
|
21
23
|
new NextjsAdapter(),
|
|
22
24
|
new FastApiAdapter(),
|
|
23
25
|
new DjangoAdapter(),
|
package/src/generator.js
CHANGED
|
@@ -325,6 +325,20 @@ ${isFront ? `- UI Component Reuse First (components/ui/ & semantic tokens)
|
|
|
325
325
|
- Database Efficiency & N+1 Performance Guard
|
|
326
326
|
- Database Migration Idempotency Guard
|
|
327
327
|
- Memory Guard (Engram / Graphify)`}
|
|
328
|
+
|
|
329
|
+
## 3. Universal Command Interface (All LLMs & Agents)
|
|
330
|
+
When given a command matching \`clckernel <action>\` or \`/clckernel <action>\`, execute the deterministic state machine below:
|
|
331
|
+
|
|
332
|
+
| Command | Lifecycle Phase | Mandatory Execution Protocol |
|
|
333
|
+
|---|---|---|
|
|
334
|
+
| \`clckernel feature <name>\` | New Feature | 1. Research affected layers.<br>2. Author local spec in \`sdds/{name}/spec.md\`.<br>3. Present HIT review to user and wait for approval.<br>4. Write failing test (Red Phase).<br>5. Implement clean code (Green Phase).<br>6. Run \`node tools/audit.js\` (or \`audit.py\`). |
|
|
335
|
+
| \`clckernel fix <issue>\` | Bug Fix | 1. Investigate root cause (no code edits).<br>2. Reproduce with failing test (Red Phase).<br>3. Minimal surgical fix respecting Clean Arch (Green Phase).<br>4. Run audit gate without skipping. |
|
|
336
|
+
| \`clckernel test\` | Verification | Run test suite (\`${config.testRunner || 'npm test'}\`) and verify clean pass (exit code 0). |
|
|
337
|
+
| \`clckernel audit\` | Verification | Run \`node tools/audit.js\` or \`python tools/audit.py\` and output the Educational Summary. |
|
|
338
|
+
| \`clckernel doctor\` | Diagnostics | Check git pre-commit hooks, IDE symlinks, and AST engine integrity. |
|
|
339
|
+
| \`clckernel commit <message>\` | Version Control | Run full audit, verify tests pass, ensure no changes outside SDD scope, and commit with conventional commits (never add AI attribution). |
|
|
340
|
+
| \`clckernel guard create <name>\` | Safeguards | Scaffold a new AST guard in the stack's native language in \`tools/guards/\`. |
|
|
341
|
+
| \`clckernel start\` | Setup | Scan codebase, propose governance plan, and materialize \`.clckernel.yaml\`. |
|
|
328
342
|
`;
|
|
329
343
|
fs.writeFileSync(path.join(targetDir, 'AGENTS.md'), agentsContent, 'utf-8');
|
|
330
344
|
}
|
|
@@ -372,68 +386,31 @@ function installAgenticCLI(targetDir) {
|
|
|
372
386
|
// 1. Crear el Directorio de Skills
|
|
373
387
|
const skillDir = path.join(targetDir, '.agents', 'skills', 'clckernel_cli');
|
|
374
388
|
const legacySkillDir = path.join(targetDir, '.agents', 'skills', 'clc_forge_cli');
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
### Phase 1: Silent Discovery
|
|
401
|
-
Scan the current project using your file-reading capabilities. Identify the primary tech stack by looking for signature files (e.g., \`package.json\`, \`Gemfile\`, \`Cargo.toml\`, \`go.mod\`).
|
|
402
|
-
*Golden Rule: Do not assume the language. Read the files to establish context.*
|
|
403
|
-
|
|
404
|
-
### Phase 2: Interview & Proposal
|
|
405
|
-
Introduce yourself as CLC Kernel and state the detected stack.
|
|
406
|
-
Propose a standard governance plan for that ecosystem (SDD + TDD + stack-specific Safeguards).
|
|
407
|
-
ASK the user directly:
|
|
408
|
-
1. "Should we activate these standard phases, or do you want to define custom ones?"
|
|
409
|
-
2. "Do you have any specific security needs that require a custom Guard?"
|
|
410
|
-
**STOP.** Wait for the user's response.
|
|
411
|
-
|
|
412
|
-
### Phase 3: Materialization
|
|
413
|
-
Based on user approval, generate and write the \`.clckernel.yaml\` file in the project root.
|
|
414
|
-
|
|
415
|
-
---
|
|
416
|
-
|
|
417
|
-
## 🛠️ INTENT: \`clckernel create_guard\`
|
|
418
|
-
1. Ask the user what behavior they want to audit or block. **STOP.** Wait for technical details.
|
|
419
|
-
2. Based on the detected stack, write the linter/guard script in the **NATIVE ECOSYSTEM LANGUAGE** (Ruby for Rails, Go \`ast\` for Golang, Python \`ast\` for FastAPI, JS for Node). Save it in \`tools/guards/\`.
|
|
420
|
-
3. Update the \`.clckernel.yaml\` file to include the new Guard.
|
|
421
|
-
|
|
422
|
-
---
|
|
423
|
-
|
|
424
|
-
## 🗑️ INTENT: \`clckernel remove_guard\`
|
|
425
|
-
1. Ask which guard to remove and if the script should be deleted. **STOP.** Wait for response.
|
|
426
|
-
2. Update \`.clckernel.yaml\` and delete the script from \`tools/guards/\` if requested.
|
|
427
|
-
|
|
428
|
-
---
|
|
429
|
-
|
|
430
|
-
## 🔄 INTENT: \`clckernel add_phase\` / \`clckernel remove_phase\`
|
|
431
|
-
1. Ask for details of the lifecycle phase to add or remove. **STOP.** Wait for response.
|
|
432
|
-
2. Update the \`execution_phases\` block in \`.clckernel.yaml\`, preserving the logical sequence.
|
|
433
|
-
`;
|
|
434
|
-
|
|
435
|
-
fs.writeFileSync(path.join(skillDir, 'SKILL.md'), skillContent, 'utf-8');
|
|
436
|
-
fs.writeFileSync(path.join(legacySkillDir, 'SKILL.md'), skillContent, 'utf-8');
|
|
389
|
+
const skillRefDir = path.join(skillDir, 'reference');
|
|
390
|
+
const legacySkillRefDir = path.join(legacySkillDir, 'reference');
|
|
391
|
+
fs.mkdirSync(skillRefDir, { recursive: true });
|
|
392
|
+
fs.mkdirSync(legacySkillRefDir, { recursive: true });
|
|
393
|
+
|
|
394
|
+
// 2. Inyectar el SKILL.md Maestro y Playbooks de Referencia
|
|
395
|
+
const bundledSkillDir = path.join(__dirname, '..', '.agents', 'skills', 'clckernel_cli');
|
|
396
|
+
const bundledSkillFile = path.join(bundledSkillDir, 'SKILL.md');
|
|
397
|
+
const bundledRefDir = path.join(bundledSkillDir, 'reference');
|
|
398
|
+
|
|
399
|
+
if (fs.existsSync(bundledSkillFile)) {
|
|
400
|
+
fs.copyFileSync(bundledSkillFile, path.join(skillDir, 'SKILL.md'));
|
|
401
|
+
fs.copyFileSync(bundledSkillFile, path.join(legacySkillDir, 'SKILL.md'));
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
if (fs.existsSync(bundledRefDir)) {
|
|
405
|
+
const playbooks = fs.readdirSync(bundledRefDir);
|
|
406
|
+
for (const pb of playbooks) {
|
|
407
|
+
const srcPb = path.join(bundledRefDir, pb);
|
|
408
|
+
if (fs.statSync(srcPb).isFile()) {
|
|
409
|
+
fs.copyFileSync(srcPb, path.join(skillRefDir, pb));
|
|
410
|
+
fs.copyFileSync(srcPb, path.join(legacySkillRefDir, pb));
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
}
|
|
437
414
|
|
|
438
415
|
// 3. Crear Symlinks Dinámicos al AGENTS.md (El Single Source of Truth)
|
|
439
416
|
const sourceFile = 'AGENTS.md';
|
package/src/index.js
CHANGED
|
@@ -43,8 +43,19 @@ async function runCli() {
|
|
|
43
43
|
const finalConfig = await promptOptions(detected);
|
|
44
44
|
|
|
45
45
|
// 5. Generate Harness & Safeguards
|
|
46
|
+
let s;
|
|
47
|
+
if (Boolean(process.stdin.isTTY) && !process.env.CI) {
|
|
48
|
+
const p = require('@clack/prompts');
|
|
49
|
+
s = p.spinner();
|
|
50
|
+
s.start('Configurando salvaguardas y motor de gobernanza...');
|
|
51
|
+
}
|
|
52
|
+
|
|
46
53
|
generateHarness(targetDir, finalConfig);
|
|
47
54
|
|
|
55
|
+
if (s) {
|
|
56
|
+
s.stop('Salvaguardas y motor de gobernanza configurados.');
|
|
57
|
+
}
|
|
58
|
+
|
|
48
59
|
// 6. Render Pro Success Card
|
|
49
60
|
printSuccess(targetDir, finalConfig.projectType === 'frontend', finalConfig);
|
|
50
61
|
}
|
package/src/ui.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Brand Identity: The AI Agent Governance & Quality Engineering Engine
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
const
|
|
6
|
+
const p = require('@clack/prompts');
|
|
7
7
|
|
|
8
8
|
// ANSI Color Palette
|
|
9
9
|
const colors = {
|
|
@@ -33,7 +33,7 @@ function printBanner() {
|
|
|
33
33
|
╚██████╗███████╗╚██████╗ ██║ ╚██╗███████╗██║ ██║██║ ╚████║███████╗███████╗
|
|
34
34
|
╚═════╝╚══════╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝╚═╝ ╚═══╝╚══════╝╚══════╝
|
|
35
35
|
${colors.reset}`);
|
|
36
|
-
console.log(` ${colors.bgCyan} CLC KERNEL ${colors.reset} ${colors.bold}The AI Agent Governance & Quality Engineering Engine${colors.reset} ${colors.gray}v1.2.
|
|
36
|
+
console.log(` ${colors.bgCyan} CLC KERNEL ${colors.reset} ${colors.bold}The AI Agent Governance & Quality Engineering Engine${colors.reset} ${colors.gray}v1.2.6${colors.reset}\n`);
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
function printBox(title, items) {
|
|
@@ -52,44 +52,88 @@ function printBox(title, items) {
|
|
|
52
52
|
console.log(`${colors.dim}└${'─'.repeat(width)}┘${colors.reset}\n`);
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
function promptOptions(detected) {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
detected.projectType
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
55
|
+
async function promptOptions(detected) {
|
|
56
|
+
const isInteractive = Boolean(process.stdin.isTTY) &&
|
|
57
|
+
!process.env.CI &&
|
|
58
|
+
!process.argv.includes('--yes') &&
|
|
59
|
+
!process.argv.includes('-y');
|
|
60
|
+
|
|
61
|
+
if (!isInteractive) {
|
|
62
|
+
return detected;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
p.intro(`${colors.cyan}${colors.bold}CLC Kernel Setup${colors.reset}`);
|
|
66
|
+
|
|
67
|
+
const choice = await p.select({
|
|
68
|
+
message: '¿Cómo deseas inicializar CLC Kernel en este proyecto?',
|
|
69
|
+
initialValue: 'confirm',
|
|
70
|
+
options: [
|
|
71
|
+
{
|
|
72
|
+
value: 'confirm',
|
|
73
|
+
label: 'Confirmar e Instalar CLC Kernel',
|
|
74
|
+
hint: `Recomendado (${detected.projectType.toUpperCase()} - ${detected.framework})`
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
value: 'frontend',
|
|
78
|
+
label: 'Forzar modo FRONTEND',
|
|
79
|
+
hint: 'Salvaguardas A11y, Zod, Next/Image, UI Reuse'
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
value: 'backend',
|
|
83
|
+
label: 'Forzar modo BACKEND',
|
|
84
|
+
hint: 'Salvaguardas TDD, Clean Arch, N+1, Secrets'
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
value: 'agent-os',
|
|
88
|
+
label: 'Forzar modo AGENT-OS',
|
|
89
|
+
hint: 'Salvaguardas HITL, Symlinks, Schemas, Memoria SSOT'
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
value: 'cancel',
|
|
93
|
+
label: 'Cancelar',
|
|
94
|
+
hint: 'Salir sin realizar cambios'
|
|
82
95
|
}
|
|
83
|
-
|
|
96
|
+
]
|
|
84
97
|
});
|
|
98
|
+
|
|
99
|
+
if (p.isCancel(choice) || choice === 'cancel') {
|
|
100
|
+
p.cancel('Instalación de CLC Kernel cancelada.');
|
|
101
|
+
process.exit(0);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (choice === 'frontend') {
|
|
105
|
+
detected.projectType = 'frontend';
|
|
106
|
+
} else if (choice === 'backend') {
|
|
107
|
+
detected.projectType = 'backend';
|
|
108
|
+
} else if (choice === 'agent-os') {
|
|
109
|
+
detected.projectType = 'agent-os';
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return detected;
|
|
85
113
|
}
|
|
86
114
|
|
|
87
115
|
function printSuccess(targetDir, isFront, config) {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
116
|
+
const isAgentOS = config.projectType === 'agent-os';
|
|
117
|
+
const guardsDesc = isAgentOS
|
|
118
|
+
? `${colors.cyan}6 Guardias Agent-OS (HITL, Symlinks, Schemas, Memoria, Secrets)${colors.reset}`
|
|
119
|
+
: isFront
|
|
120
|
+
? `${colors.emerald}10 Guardias Frontend (A11y, Zod, Image, UI Reuse, Storybook)${colors.reset}`
|
|
121
|
+
: `${colors.violet}7 Guardias Backend (TDD, Architecture, Scope, Secret Scan)${colors.reset}`;
|
|
122
|
+
|
|
123
|
+
const summary = [
|
|
124
|
+
`🔨 ${colors.bold}Proyecto Inicializado:${colors.reset} ${colors.cyan}${targetDir}${colors.reset}`,
|
|
125
|
+
`🛡️ ${colors.bold}Salvaguardas:${colors.reset} ${guardsDesc}`,
|
|
126
|
+
`📝 ${colors.bold}Leyes & SDD:${colors.reset} AGENTS.md, sdds/, docs/Journal/ precargados`,
|
|
127
|
+
`🔒 ${colors.bold}Git Hooks:${colors.reset} Configurados en ${colors.amber}${config.gitHooks === 'husky' ? '.husky/pre-commit' : '.githooks/pre-commit'}${colors.reset}`
|
|
128
|
+
].join('\n');
|
|
129
|
+
|
|
130
|
+
if (p.note && p.outro) {
|
|
131
|
+
p.note(summary, '🚀 Resumen de Instalación');
|
|
132
|
+
p.outro(`${colors.emerald}${colors.bold}¡CLC Kernel instalado exitosamente!${colors.reset}`);
|
|
133
|
+
} else {
|
|
134
|
+
console.log(`\n${colors.bgEmerald} SUCCESS ${colors.reset} ${colors.bold}${colors.emerald}¡CLC Kernel instalado exitosamente!${colors.reset}\n`);
|
|
135
|
+
console.log(summary + '\n');
|
|
136
|
+
}
|
|
93
137
|
}
|
|
94
138
|
|
|
95
139
|
module.exports = {
|
package/tools/audit.js
CHANGED
|
File without changes
|
package/tools/audit.py
CHANGED
|
File without changes
|
package/tools/check_custom.js
CHANGED
|
File without changes
|
package/tools/check_custom.py
CHANGED
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Domain Data Integrity & Clean State Guard
|
|
4
|
+
* Validates domain deliverables (content.json, calendar.json, voc.json)
|
|
5
|
+
* to ensure valid JSON structure and clean creation state (no fake hallucinated metrics on pending posts).
|
|
6
|
+
* Self-contained: uses only Node.js built-ins.
|
|
7
|
+
*
|
|
8
|
+
* @param {string} targetDir - Directory to scan (defaults to cwd)
|
|
9
|
+
* @returns {{ exitCode: number, skipped: boolean, name: string, data: object }}
|
|
10
|
+
*/
|
|
11
|
+
const check = async function checkDomainData(targetDir) {
|
|
12
|
+
const fs = require('fs');
|
|
13
|
+
const path = require('path');
|
|
14
|
+
|
|
15
|
+
const dir = targetDir || process.cwd();
|
|
16
|
+
const searchDirs = [
|
|
17
|
+
dir,
|
|
18
|
+
path.join(dir, 'output'),
|
|
19
|
+
path.join(dir, 'content-calendar'),
|
|
20
|
+
path.join(dir, 'data')
|
|
21
|
+
];
|
|
22
|
+
|
|
23
|
+
const jsonFiles = [];
|
|
24
|
+
for (const sDir of searchDirs) {
|
|
25
|
+
if (fs.existsSync(sDir)) {
|
|
26
|
+
try {
|
|
27
|
+
const files = fs.readdirSync(sDir);
|
|
28
|
+
for (const file of files) {
|
|
29
|
+
if (file.endsWith('.json') && !file.includes('package') && !file.includes('tsconfig')) {
|
|
30
|
+
jsonFiles.push(path.join(sDir, file));
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
} catch {}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (jsonFiles.length === 0) {
|
|
38
|
+
return {
|
|
39
|
+
exitCode: 0,
|
|
40
|
+
skipped: true,
|
|
41
|
+
name: 'check_domain_data',
|
|
42
|
+
data: { violations: [], message: 'No domain data JSON files to validate' }
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const violations = [];
|
|
47
|
+
for (const file of jsonFiles) {
|
|
48
|
+
try {
|
|
49
|
+
const raw = fs.readFileSync(file, 'utf-8');
|
|
50
|
+
const data = JSON.parse(raw);
|
|
51
|
+
|
|
52
|
+
// Clean Creation State Check: If array of posts/calendar entries
|
|
53
|
+
const entries = Array.isArray(data) ? data : (data.posts || data.items || data.calendar || []);
|
|
54
|
+
if (Array.isArray(entries)) {
|
|
55
|
+
for (let i = 0; i < entries.length; i++) {
|
|
56
|
+
const item = entries[i];
|
|
57
|
+
if (item && (item.status === 'pending' || item.status === 'draft')) {
|
|
58
|
+
// Check if metrics are falsely pre-filled with non-null numbers
|
|
59
|
+
if (item.metrics && typeof item.metrics === 'object') {
|
|
60
|
+
const fakeMetrics = Object.entries(item.metrics).filter(([_, val]) => typeof val === 'number' && val > 0);
|
|
61
|
+
if (fakeMetrics.length > 0) {
|
|
62
|
+
violations.push({
|
|
63
|
+
file: path.relative(dir, file),
|
|
64
|
+
message: `Entry #${i + 1} (${item.title || item.id || 'draft'}) has pre-filled fake metrics on pending/draft post`
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
} catch (err) {
|
|
72
|
+
violations.push({
|
|
73
|
+
file: path.relative(dir, file),
|
|
74
|
+
message: `JSON syntax or structural error: ${err.message}`
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const exitCode = violations.length > 0 ? 1 : 0;
|
|
80
|
+
return {
|
|
81
|
+
exitCode,
|
|
82
|
+
skipped: false,
|
|
83
|
+
name: 'check_domain_data',
|
|
84
|
+
data: {
|
|
85
|
+
violations,
|
|
86
|
+
message: violations.length > 0
|
|
87
|
+
? `${violations.length} domain data integrity violation(s) found`
|
|
88
|
+
: 'All domain deliverables & state data verified'
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
module.exports = check;
|
|
94
|
+
|
|
95
|
+
if (require.main === module) {
|
|
96
|
+
check(process.argv[2]).then(result => {
|
|
97
|
+
console.log(JSON.stringify(result, null, 2));
|
|
98
|
+
process.exit(result.exitCode);
|
|
99
|
+
});
|
|
100
|
+
}
|