aios-core 4.0.1 → 4.0.2
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.
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
# - SHA256 hashes for change detection
|
|
8
8
|
# - File types for categorization
|
|
9
9
|
#
|
|
10
|
-
version: 4.0.
|
|
11
|
-
generated_at: "2026-02-13T01:
|
|
10
|
+
version: 4.0.2
|
|
11
|
+
generated_at: "2026-02-13T01:40:56.998Z"
|
|
12
12
|
generator: scripts/generate-install-manifest.js
|
|
13
13
|
file_count: 971
|
|
14
14
|
files:
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
# Claude Code Hooks
|
|
2
|
+
|
|
3
|
+
Sistema de governança automática para regras do CLAUDE.md.
|
|
4
|
+
|
|
5
|
+
## Arquitetura
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
PreToolUse Hooks
|
|
9
|
+
├── Read → read-protection.py
|
|
10
|
+
├── Write|Edit → enforce-architecture-first.py
|
|
11
|
+
│ → write-path-validation.py
|
|
12
|
+
│ → mind-clone-governance.py
|
|
13
|
+
└── Bash → sql-governance.py
|
|
14
|
+
→ slug-validation.py
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Hooks Disponíveis
|
|
18
|
+
|
|
19
|
+
### 1. read-protection.py
|
|
20
|
+
**Trigger:** `Read`
|
|
21
|
+
**Comportamento:** BLOQUEIA (exit 2)
|
|
22
|
+
|
|
23
|
+
Impede leitura parcial (`limit`/`offset`) em arquivos protegidos:
|
|
24
|
+
- `.claude/CLAUDE.md`
|
|
25
|
+
- `.claude/rules/*.md`
|
|
26
|
+
- `.aios-core/development/agents/*.md`
|
|
27
|
+
- `supabase/docs/SCHEMA.md`
|
|
28
|
+
- `package.json`, `tsconfig.json`
|
|
29
|
+
- `app/components/ui/icons/icon-map.ts`
|
|
30
|
+
|
|
31
|
+
### 2. enforce-architecture-first.py
|
|
32
|
+
**Trigger:** `Write|Edit`
|
|
33
|
+
**Comportamento:** BLOQUEIA (exit 2)
|
|
34
|
+
|
|
35
|
+
Exige documentação aprovada antes de criar código em paths protegidos:
|
|
36
|
+
- `supabase/functions/` → requer doc em `docs/architecture/` ou `docs/approved-plans/`
|
|
37
|
+
- `supabase/migrations/` → requer doc ou permite edição de arquivo existente
|
|
38
|
+
|
|
39
|
+
### 3. write-path-validation.py
|
|
40
|
+
**Trigger:** `Write|Edit`
|
|
41
|
+
**Comportamento:** AVISA (exit 0 + stderr)
|
|
42
|
+
|
|
43
|
+
Avisa quando documentos parecem estar no path errado:
|
|
44
|
+
- Sessions/handoffs → `docs/sessions/YYYY-MM/`
|
|
45
|
+
- Architecture → `docs/architecture/`
|
|
46
|
+
- Guides → `docs/guides/`
|
|
47
|
+
|
|
48
|
+
### 4. sql-governance.py
|
|
49
|
+
**Trigger:** `Bash`
|
|
50
|
+
**Comportamento:** BLOQUEIA (exit 2)
|
|
51
|
+
|
|
52
|
+
Intercepta comandos SQL perigosos:
|
|
53
|
+
- `CREATE TABLE/VIEW/FUNCTION/TRIGGER`
|
|
54
|
+
- `ALTER TABLE`
|
|
55
|
+
- `DROP TABLE/VIEW/FUNCTION`
|
|
56
|
+
- `CREATE TABLE AS SELECT` (backup proibido)
|
|
57
|
+
|
|
58
|
+
**Exceções permitidas:**
|
|
59
|
+
- `supabase migration` (CLI oficial)
|
|
60
|
+
- `pg_dump` (backup/export)
|
|
61
|
+
|
|
62
|
+
### 5. slug-validation.py
|
|
63
|
+
**Trigger:** `Bash`
|
|
64
|
+
**Comportamento:** BLOQUEIA (exit 2)
|
|
65
|
+
|
|
66
|
+
Valida formato snake_case em slugs:
|
|
67
|
+
- Pattern: `^[a-z0-9]+(_[a-z0-9]+)*$`
|
|
68
|
+
- ✅ `jose_carlos_amorim`
|
|
69
|
+
- ❌ `jose-carlos-amorim` (hyphen)
|
|
70
|
+
- ❌ `JoseAmorim` (camelCase)
|
|
71
|
+
|
|
72
|
+
### 6. mind-clone-governance.py
|
|
73
|
+
**Trigger:** `Write|Edit`
|
|
74
|
+
**Comportamento:** BLOQUEIA (exit 2)
|
|
75
|
+
|
|
76
|
+
Impede criação de mind clones sem DNA extraído previamente.
|
|
77
|
+
|
|
78
|
+
**O que é bloqueado:**
|
|
79
|
+
- Criar novo arquivo `squads/*/agents/*.md` que pareça ser um mind clone
|
|
80
|
+
- Mind clones = agents baseados em pessoas reais (não funcionais)
|
|
81
|
+
|
|
82
|
+
**O que NÃO é bloqueado:**
|
|
83
|
+
- Editar arquivos existentes (permite updates)
|
|
84
|
+
- Agents funcionais (identificados por sufixo):
|
|
85
|
+
- `-chief`, `-orchestrator`, `-chair`
|
|
86
|
+
- `-validator`, `-calculator`, `-generator`, `-extractor`, `-analyzer`
|
|
87
|
+
- `-architect`, `-mapper`, `-designer`, `-engineer`
|
|
88
|
+
- `tools-*`, `process-*`, `workflow-*`
|
|
89
|
+
|
|
90
|
+
**Locais de DNA verificados:**
|
|
91
|
+
- `squads/{pack}/data/minds/{agent_id}_dna.yaml`
|
|
92
|
+
- `squads/{pack}/data/minds/{agent_id}_dna.md`
|
|
93
|
+
- `squads/{pack}/data/{agent_id}-dna.yaml`
|
|
94
|
+
- `outputs/minds/{agent_id}/`
|
|
95
|
+
|
|
96
|
+
**Solução quando bloqueado:**
|
|
97
|
+
1. Execute o pipeline de extração de DNA: `/squad-creator` → `*collect-sources` → `*extract-voice-dna` → `*extract-thinking-dna`
|
|
98
|
+
2. OU se é agent funcional, renomeie com sufixo apropriado
|
|
99
|
+
|
|
100
|
+
## Exit Codes
|
|
101
|
+
|
|
102
|
+
| Code | Significado |
|
|
103
|
+
|------|-------------|
|
|
104
|
+
| 0 | Permitido (operação continua) |
|
|
105
|
+
| 2 | Bloqueado (operação cancelada, mostra stderr) |
|
|
106
|
+
| Outro | Erro não-bloqueante |
|
|
107
|
+
|
|
108
|
+
## Input Format
|
|
109
|
+
|
|
110
|
+
Hooks recebem JSON via stdin:
|
|
111
|
+
|
|
112
|
+
```json
|
|
113
|
+
{
|
|
114
|
+
"session_id": "abc123",
|
|
115
|
+
"hook_event_name": "PreToolUse",
|
|
116
|
+
"tool_name": "Read",
|
|
117
|
+
"tool_input": {
|
|
118
|
+
"file_path": "/path/to/file",
|
|
119
|
+
"limit": 100
|
|
120
|
+
},
|
|
121
|
+
"cwd": "/Users/alan/Code/mmos"
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## Debugging
|
|
126
|
+
|
|
127
|
+
Para testar um hook manualmente:
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
echo '{"tool_name": "Read", "tool_input": {"file_path": ".claude/CLAUDE.md", "limit": 100}}' | python3 .claude/hooks/read-protection.py
|
|
131
|
+
echo $? # Deve retornar 2 (bloqueado)
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## Configuração
|
|
135
|
+
|
|
136
|
+
Hooks são configurados em `.claude/settings.local.json`:
|
|
137
|
+
|
|
138
|
+
```json
|
|
139
|
+
{
|
|
140
|
+
"hooks": {
|
|
141
|
+
"PreToolUse": [
|
|
142
|
+
{
|
|
143
|
+
"matcher": "Read",
|
|
144
|
+
"hooks": [
|
|
145
|
+
{
|
|
146
|
+
"type": "command",
|
|
147
|
+
"command": "python3 \"$CLAUDE_PROJECT_DIR/.claude/hooks/read-protection.py\"",
|
|
148
|
+
"timeout": 5
|
|
149
|
+
}
|
|
150
|
+
]
|
|
151
|
+
}
|
|
152
|
+
]
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## Manutenção
|
|
158
|
+
|
|
159
|
+
Para adicionar novo hook:
|
|
160
|
+
|
|
161
|
+
1. Criar arquivo `.claude/hooks/novo-hook.py`
|
|
162
|
+
2. Adicionar entrada em `.claude/settings.local.json`
|
|
163
|
+
3. Documentar neste README
|
|
164
|
+
4. Testar com casos reais
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
*Criado: 2026-01-24*
|
|
169
|
+
*Arquitetura: docs/architecture/claude-md-governance-system.md*
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Claude Code Hook: PreCompact Session Digest
|
|
4
|
+
*
|
|
5
|
+
* This hook is registered with Claude Code to trigger before context compact.
|
|
6
|
+
* It delegates to the unified hook runner in aios-core.
|
|
7
|
+
*
|
|
8
|
+
* Installation:
|
|
9
|
+
* - Claude Code automatically discovers hooks in .claude/hooks/
|
|
10
|
+
* - Hook naming: {event}-{name}.js (e.g., precompact-session-digest.js)
|
|
11
|
+
*
|
|
12
|
+
* @see .aios-core/hooks/unified/runners/precompact-runner.js
|
|
13
|
+
* @see Story MIS-3 - Session Digest (PreCompact Hook)
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
'use strict';
|
|
17
|
+
|
|
18
|
+
const path = require('path');
|
|
19
|
+
|
|
20
|
+
// Resolve path to the unified hook runner
|
|
21
|
+
const PROJECT_ROOT = path.resolve(__dirname, '..', '..');
|
|
22
|
+
const runnerPath = path.join(
|
|
23
|
+
PROJECT_ROOT,
|
|
24
|
+
'.aios-core',
|
|
25
|
+
'hooks',
|
|
26
|
+
'unified',
|
|
27
|
+
'runners',
|
|
28
|
+
'precompact-runner.js',
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
// Load and execute the hook runner
|
|
32
|
+
try {
|
|
33
|
+
const { onPreCompact } = require(runnerPath);
|
|
34
|
+
|
|
35
|
+
// Export the hook handler for Claude Code
|
|
36
|
+
module.exports = async (context) => {
|
|
37
|
+
return await onPreCompact(context);
|
|
38
|
+
};
|
|
39
|
+
} catch (error) {
|
|
40
|
+
console.error('[PreCompact Hook] Failed to load hook runner:', error.message);
|
|
41
|
+
|
|
42
|
+
// Graceful degradation - export no-op function
|
|
43
|
+
module.exports = async () => {
|
|
44
|
+
console.log('[PreCompact Hook] Hook runner not available, skipping');
|
|
45
|
+
};
|
|
46
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* SYNAPSE Hook Entry Point — UserPromptSubmit
|
|
6
|
+
*
|
|
7
|
+
* Thin wrapper that reads JSON from stdin, delegates to SynapseEngine,
|
|
8
|
+
* and writes <synapse-rules> context to stdout.
|
|
9
|
+
*
|
|
10
|
+
* - Silent exit on missing .synapse/ directory
|
|
11
|
+
* - Silent exit on any error (never blocks the user prompt)
|
|
12
|
+
* - All errors logged to stderr with [synapse-hook] prefix
|
|
13
|
+
* - 5s safety timeout as defense-in-depth
|
|
14
|
+
*
|
|
15
|
+
* @module synapse-engine-hook
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
const path = require('path');
|
|
19
|
+
const fs = require('fs');
|
|
20
|
+
|
|
21
|
+
/** Safety timeout (ms) — defense-in-depth; Claude Code also manages hook timeout. */
|
|
22
|
+
const HOOK_TIMEOUT_MS = 5000;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Read all data from stdin as a JSON object.
|
|
26
|
+
* @returns {Promise<object>} Parsed JSON input
|
|
27
|
+
*/
|
|
28
|
+
function readStdin() {
|
|
29
|
+
return new Promise((resolve, reject) => {
|
|
30
|
+
let data = '';
|
|
31
|
+
process.stdin.setEncoding('utf8');
|
|
32
|
+
process.stdin.on('error', (e) => reject(e));
|
|
33
|
+
process.stdin.on('data', (chunk) => { data += chunk; });
|
|
34
|
+
process.stdin.on('end', () => {
|
|
35
|
+
try { resolve(JSON.parse(data)); }
|
|
36
|
+
catch (e) { reject(e); }
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** Main hook execution pipeline. */
|
|
42
|
+
async function main() {
|
|
43
|
+
const input = await readStdin();
|
|
44
|
+
const { sessionId, cwd, prompt } = input;
|
|
45
|
+
if (!cwd) return;
|
|
46
|
+
const synapsePath = path.join(cwd, '.synapse');
|
|
47
|
+
if (!fs.existsSync(synapsePath)) return;
|
|
48
|
+
|
|
49
|
+
const { loadSession } = require(
|
|
50
|
+
path.join(cwd, '.aios-core', 'core', 'synapse', 'session', 'session-manager.js')
|
|
51
|
+
);
|
|
52
|
+
const { SynapseEngine } = require(
|
|
53
|
+
path.join(cwd, '.aios-core', 'core', 'synapse', 'engine.js')
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
const sessionsDir = path.join(synapsePath, 'sessions');
|
|
57
|
+
const session = loadSession(sessionId, sessionsDir) || { prompt_count: 0 };
|
|
58
|
+
const engine = new SynapseEngine(synapsePath);
|
|
59
|
+
const result = await engine.process(prompt, session);
|
|
60
|
+
|
|
61
|
+
process.stdout.write(JSON.stringify({
|
|
62
|
+
hookSpecificOutput: { additionalContext: result.xml || '' },
|
|
63
|
+
}));
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Safely exit the process — no-op inside Jest workers to prevent worker crashes.
|
|
68
|
+
* @param {number} code - Exit code
|
|
69
|
+
*/
|
|
70
|
+
function safeExit(code) {
|
|
71
|
+
if (process.env.JEST_WORKER_ID) return;
|
|
72
|
+
process.exit(code);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** Entry point runner — sets safety timeout and executes main(). */
|
|
76
|
+
function run() {
|
|
77
|
+
const timer = setTimeout(() => safeExit(0), HOOK_TIMEOUT_MS);
|
|
78
|
+
timer.unref();
|
|
79
|
+
main().catch((err) => {
|
|
80
|
+
console.error(`[synapse-hook] ${err.message}`);
|
|
81
|
+
safeExit(0);
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (require.main === module) run();
|
|
86
|
+
|
|
87
|
+
module.exports = { readStdin, main, run, HOOK_TIMEOUT_MS };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "aios-core",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.2",
|
|
4
4
|
"description": "Synkra AIOS: AI-Orchestrated System for Full Stack Development - Core Framework",
|
|
5
5
|
"bin": {
|
|
6
6
|
"aios": "bin/aios.js",
|
|
@@ -18,6 +18,9 @@
|
|
|
18
18
|
".aios-core/",
|
|
19
19
|
".claude/CLAUDE.md",
|
|
20
20
|
".claude/rules/",
|
|
21
|
+
".claude/hooks/synapse-engine.js",
|
|
22
|
+
".claude/hooks/precompact-session-digest.js",
|
|
23
|
+
".claude/hooks/README.md",
|
|
21
24
|
"README.md",
|
|
22
25
|
"LICENSE"
|
|
23
26
|
],
|
|
@@ -324,8 +324,9 @@ async function installAiosCore(options = {}) {
|
|
|
324
324
|
// BUG-2 fix (INS-1): Install .aios-core dependencies after copy
|
|
325
325
|
// The copied .aios-core/package.json has dependencies (js-yaml, execa, etc.)
|
|
326
326
|
// that must be installed for the activation pipeline to work
|
|
327
|
-
|
|
328
|
-
|
|
327
|
+
const aiosCorePackageJson = path.join(targetAiosCore, 'package.json');
|
|
328
|
+
if (await fs.pathExists(aiosCorePackageJson)) {
|
|
329
|
+
spinner.text = 'Installing .aios-core dependencies (js-yaml, etc.)...';
|
|
329
330
|
try {
|
|
330
331
|
const { exec } = require('child_process');
|
|
331
332
|
const { promisify } = require('util');
|
|
@@ -334,8 +335,11 @@ async function installAiosCore(options = {}) {
|
|
|
334
335
|
cwd: targetAiosCore,
|
|
335
336
|
timeout: 60000,
|
|
336
337
|
});
|
|
338
|
+
spinner.succeed('Installed .aios-core dependencies');
|
|
339
|
+
spinner.start('Finishing installation...');
|
|
337
340
|
} catch (depError) {
|
|
338
|
-
|
|
341
|
+
spinner.warn(`Could not install .aios-core dependencies: ${depError.message}`);
|
|
342
|
+
spinner.start('Continuing installation...');
|
|
339
343
|
result.errors.push(`Dependencies warning: ${depError.message}`);
|
|
340
344
|
}
|
|
341
345
|
}
|