clckernel 1.2.6 → 1.2.8
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 +51 -118
- package/README.md +48 -116
- package/package.json +14 -2
- package/src/adapters/agent-os.js +183 -0
- package/src/catalog.js +16 -0
- package/src/detector.js +2 -0
- 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/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,183 @@
|
|
|
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: 'scan_secrets',
|
|
100
|
+
language: 'node',
|
|
101
|
+
path: 'tools/scan_secrets.js',
|
|
102
|
+
command: 'node tools/scan_secrets.js',
|
|
103
|
+
description: 'Security & API key leak scanner'
|
|
104
|
+
}
|
|
105
|
+
];
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
provision(targetDir, config) {
|
|
109
|
+
// 1. Create docs/, sdds/, and tools/
|
|
110
|
+
super.provision(targetDir, config);
|
|
111
|
+
|
|
112
|
+
// 2. Write Dual-Layer AGENTS.md
|
|
113
|
+
const dualLayerAgents = `# Standard Operating Procedure (SOP) — AGENTS
|
|
114
|
+
Governed by **CLC Kernel: The Universal AI Agent Governance Engine**.
|
|
115
|
+
Target System: **${this.name}**
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## 🛠️ Layer 1: Development & Maintenance Governance (Engineering)
|
|
120
|
+
All AI Agents (Antigravity, OpenCode, Claude Code, Cursor, Windsurf, Copilot) developing or maintaining this codebase MUST adhere to strict engineering standards:
|
|
121
|
+
|
|
122
|
+
> 🚨 **RULE #0: MANDATORY EXECUTION OVERRIDE RULE (UNBYPASSABLE)**
|
|
123
|
+
> Even when the user issues a direct or urgent fix request ("fix this bug", "fix this error", "quick fix"):
|
|
124
|
+
> YOU ARE STRICTLY FORBIDDEN from modifying source code or workflows directly without completing the full quality harness:
|
|
125
|
+
> 1. **Research & Root Cause Analysis:** Investigate tracebacks and affected files before editing.
|
|
126
|
+
> 2. **SDD Specification:** Document non-trivial changes in \`sdds/{change-name}/01-spec.md\` (gitignored).
|
|
127
|
+
> 3. **Verification (Red Phase):** Write a failing test or contract validation first.
|
|
128
|
+
> 4. **Clean Implementation (Green Phase):** Make tests pass maintaining strict layer isolation.
|
|
129
|
+
> 5. **Mandatory Audit Gate:** Execute \`node tools/audit.js\` and output summary to stdout.
|
|
130
|
+
|
|
131
|
+
### Engineering Rules
|
|
132
|
+
1. **Conventional Commits Only**: Commits must use Conventional Commits (e.g. \`feat(...): ...\`, \`fix(...): ...\`). NEVER add \`Co-Authored-By\` or AI attribution.
|
|
133
|
+
2. **Mirror Links Interoperability**: \`CLAUDE.md\`, \`GEMINI.md\`, \`.cursorrules\`, and \`.windsurfrules\` must remain valid symlinks to \`AGENTS.md\`.
|
|
134
|
+
3. **No Superficial Symptom Patches**: Always address root causes.
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
## 🚀 Layer 2: Domain Runtime Directives (Agent Workflows & Operations)
|
|
139
|
+
When operating as domain agents for end-users and non-technical operators:
|
|
140
|
+
|
|
141
|
+
1. **Non-Technical Operator Friendly**: Interact naturally with the operator. Guide step-by-step through conversational prompts without technical jargon.
|
|
142
|
+
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.
|
|
143
|
+
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/\`).
|
|
144
|
+
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.
|
|
145
|
+
5. **Deterministic Output Standard**: Outputs must strictly follow valid Markdown, JSON schema, or domain templates.
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## 🛡️ Core AI Safeguards
|
|
150
|
+
${this.getSafeguards().map(s => `- ${s}`).join('\n')}
|
|
151
|
+
`;
|
|
152
|
+
|
|
153
|
+
fs.writeFileSync(path.join(targetDir, 'AGENTS.md'), dualLayerAgents, 'utf-8');
|
|
154
|
+
|
|
155
|
+
// 3. Create AI IDE mirror symlinks
|
|
156
|
+
const mirrors = ['CLAUDE.md', 'GEMINI.md', '.cursorrules', '.windsurfrules'];
|
|
157
|
+
for (const mirror of mirrors) {
|
|
158
|
+
const mirrorPath = path.join(targetDir, mirror);
|
|
159
|
+
try {
|
|
160
|
+
if (!fs.existsSync(mirrorPath)) {
|
|
161
|
+
fs.symlinkSync('AGENTS.md', mirrorPath);
|
|
162
|
+
}
|
|
163
|
+
} catch {}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// 4. Copy domain guard tools into tools/
|
|
167
|
+
const srcToolsDir = path.join(__dirname, '..', '..', 'tools');
|
|
168
|
+
const targetToolsDir = path.join(targetDir, 'tools');
|
|
169
|
+
const toolsToCopy = ['check_symlinks.js', 'check_hitl.js', 'check_domain_data.js', 'scan_secrets.js', 'audit.js'];
|
|
170
|
+
|
|
171
|
+
for (const toolFile of toolsToCopy) {
|
|
172
|
+
const srcFile = path.join(srcToolsDir, toolFile);
|
|
173
|
+
const destFile = path.join(targetToolsDir, toolFile);
|
|
174
|
+
if (fs.existsSync(srcFile) && !fs.existsSync(destFile)) {
|
|
175
|
+
try {
|
|
176
|
+
fs.copyFileSync(srcFile, destFile);
|
|
177
|
+
} catch {}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
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/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
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Human-in-the-Loop (HITL) Checkpoint Guard
|
|
4
|
+
* Ensures subagent playbooks and workflows in skills/ or .agents/skills/
|
|
5
|
+
* define mandatory user review or approval checkpoints before final output.
|
|
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 checkHitl(targetDir) {
|
|
12
|
+
const fs = require('fs');
|
|
13
|
+
const path = require('path');
|
|
14
|
+
|
|
15
|
+
const dir = targetDir || process.cwd();
|
|
16
|
+
const searchDirs = [
|
|
17
|
+
path.join(dir, 'skills'),
|
|
18
|
+
path.join(dir, '.agents', 'skills')
|
|
19
|
+
];
|
|
20
|
+
|
|
21
|
+
const skillFiles = [];
|
|
22
|
+
for (const sDir of searchDirs) {
|
|
23
|
+
if (fs.existsSync(sDir)) {
|
|
24
|
+
try {
|
|
25
|
+
const files = fs.readdirSync(sDir);
|
|
26
|
+
for (const file of files) {
|
|
27
|
+
if (file.endsWith('.md')) {
|
|
28
|
+
skillFiles.push(path.join(sDir, file));
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
} catch {}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (skillFiles.length === 0) {
|
|
36
|
+
return {
|
|
37
|
+
exitCode: 0,
|
|
38
|
+
skipped: true,
|
|
39
|
+
name: 'check_hitl',
|
|
40
|
+
data: { violations: [], message: 'No skills/ or subagent playbook files found' }
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const hitlKeywords = [
|
|
45
|
+
/human[- ]in[- ]the[- ]loop/i,
|
|
46
|
+
/hitl/i,
|
|
47
|
+
/checkpoint/i,
|
|
48
|
+
/approval/i,
|
|
49
|
+
/confirm/i,
|
|
50
|
+
/review/i,
|
|
51
|
+
/pausa/i,
|
|
52
|
+
/aprobaci[oó]n/i,
|
|
53
|
+
/esperar/i,
|
|
54
|
+
/validaci[oó]n/i
|
|
55
|
+
];
|
|
56
|
+
|
|
57
|
+
const violations = [];
|
|
58
|
+
for (const file of skillFiles) {
|
|
59
|
+
try {
|
|
60
|
+
const content = fs.readFileSync(file, 'utf-8');
|
|
61
|
+
const hasHitl = hitlKeywords.some(kw => kw.test(content));
|
|
62
|
+
|
|
63
|
+
if (!hasHitl) {
|
|
64
|
+
violations.push({
|
|
65
|
+
file: path.relative(dir, file),
|
|
66
|
+
message: 'Skill/Playbook missing mandatory Human-in-the-Loop (HITL) review checkpoint'
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
} catch {}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const exitCode = violations.length > 0 ? 1 : 0;
|
|
73
|
+
return {
|
|
74
|
+
exitCode,
|
|
75
|
+
skipped: false,
|
|
76
|
+
name: 'check_hitl',
|
|
77
|
+
data: {
|
|
78
|
+
violations,
|
|
79
|
+
message: violations.length > 0
|
|
80
|
+
? `${violations.length} skill(s) missing mandatory Human-in-the-Loop checkpoints`
|
|
81
|
+
: 'All subagent skills include mandatory Human-in-the-Loop (HITL) checkpoints'
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
module.exports = check;
|
|
87
|
+
|
|
88
|
+
if (require.main === module) {
|
|
89
|
+
check(process.argv[2]).then(result => {
|
|
90
|
+
console.log(JSON.stringify(result, null, 2));
|
|
91
|
+
process.exit(result.exitCode);
|
|
92
|
+
});
|
|
93
|
+
}
|
|
File without changes
|
package/tools/check_seo.js
CHANGED
|
@@ -90,7 +90,7 @@ const check = async function checkSeo(targetDir) {
|
|
|
90
90
|
}
|
|
91
91
|
|
|
92
92
|
// Check for Hero / Banner images without priority (Core Web Vitals / LCP)
|
|
93
|
-
if (
|
|
93
|
+
if (/\b(?:hero|banner|hero-image|heroImage|heroBanner)\b/i.test(line) && /<(?:img|Image)\b/i.test(line)) {
|
|
94
94
|
if (!/priority|fetchpriority|loading\s*=\s*['"]eager['"]/i.test(line)) {
|
|
95
95
|
fileViolations.push({
|
|
96
96
|
lineNo: i + 1,
|