aios-core 4.0.0 → 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.
- package/.aios-core/cli/commands/pro/index.js +82 -148
- package/.aios-core/core/synapse/domain/domain-loader.js +2 -2
- package/.aios-core/core/synapse/engine.js +17 -4
- package/.aios-core/core/synapse/memory/memory-bridge.js +246 -0
- package/.aios-core/core/synapse/output/formatter.js +34 -12
- package/.aios-core/core/synapse/scripts/generate-constitution.js +204 -0
- package/.aios-core/core/synapse/utils/tokens.js +25 -0
- package/.aios-core/data/aios-kb.md +2 -4
- package/.aios-core/data/entity-registry.yaml +61 -8
- package/.aios-core/development/scripts/unified-activation-pipeline.js +9 -1
- package/.aios-core/framework-config.yaml +1 -1
- package/.aios-core/install-manifest.yaml +33 -21
- package/.aios-core/lib/build.json +1 -0
- package/.aios-core/package.json +2 -1
- package/.aios-core/user-guide.md +1 -1
- package/.claude/CLAUDE.md +8 -9
- package/.claude/hooks/README.md +169 -0
- package/.claude/hooks/precompact-session-digest.js +46 -0
- package/.claude/hooks/synapse-engine.js +87 -0
- package/bin/aios-init.js +4 -4
- package/bin/aios-minimal.js +1 -4
- package/bin/aios.js +1 -1
- package/bin/modules/env-config.js +0 -1
- package/package.json +4 -1
- package/packages/aios-pro-cli/bin/aios-pro.js +158 -0
- package/packages/aios-pro-cli/package.json +32 -0
- package/packages/installer/package.json +1 -1
- package/packages/installer/src/installer/aios-core-installer.js +23 -0
- package/packages/installer/src/wizard/ide-config-generator.js +146 -1
- package/packages/installer/src/wizard/index.js +49 -32
|
@@ -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/bin/aios-init.js
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
* Based on the original beautiful visual design with ASCII art
|
|
6
6
|
* Version: 2.1.0
|
|
7
7
|
*
|
|
8
|
-
* ⚠️
|
|
9
|
-
* This file is the LEGACY installer
|
|
8
|
+
* ⚠️ DEPRECATED (since v3.11.3, scheduled for removal in v5.0.0):
|
|
9
|
+
* This file is the LEGACY installer.
|
|
10
10
|
* The new modular wizard is located at: packages/installer/src/wizard/index.js
|
|
11
11
|
*
|
|
12
12
|
* This file is kept as a fallback for edge cases where the new wizard
|
|
@@ -16,8 +16,8 @@
|
|
|
16
16
|
* - Use `npx aios-core` which routes through bin/aios.js to the new wizard
|
|
17
17
|
* - Do NOT call this file directly
|
|
18
18
|
*
|
|
19
|
-
* Supported IDEs (
|
|
20
|
-
* - Claude Code, Cursor, Windsurf,
|
|
19
|
+
* Supported IDEs (7 total):
|
|
20
|
+
* - Claude Code, Cursor, Windsurf, Roo Code, Cline, Gemini CLI, GitHub Copilot
|
|
21
21
|
*/
|
|
22
22
|
|
|
23
23
|
const path = require('path');
|
package/bin/aios-minimal.js
CHANGED
|
@@ -3,13 +3,10 @@
|
|
|
3
3
|
/**
|
|
4
4
|
* AIOS-FullStack Minimal Installation
|
|
5
5
|
*
|
|
6
|
-
*
|
|
6
|
+
* DEPRECATED (since v3.11.1, scheduled for removal in v5.0.0):
|
|
7
7
|
* The --minimal mode was designed for expansion-packs which have been
|
|
8
8
|
* replaced by the Squads system (OSR-8). This command now runs the
|
|
9
9
|
* standard wizard through the main router.
|
|
10
|
-
*
|
|
11
|
-
* This file is kept for backwards compatibility but will be removed
|
|
12
|
-
* in a future major version.
|
|
13
10
|
*/
|
|
14
11
|
|
|
15
12
|
const { spawn } = require('child_process');
|
package/bin/aios.js
CHANGED
|
@@ -354,7 +354,6 @@ function getIDEConfigFile(ideKey) {
|
|
|
354
354
|
const ideConfigMap = {
|
|
355
355
|
cursor: '.cursorrules',
|
|
356
356
|
windsurf: '.windsurfrules',
|
|
357
|
-
trae: '.trae/config.json',
|
|
358
357
|
zed: '.zed/settings.json',
|
|
359
358
|
antigravity: '.antigravity.yaml',
|
|
360
359
|
continue: '.continue/config.json',
|
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
|
],
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* aios-pro CLI
|
|
5
|
+
*
|
|
6
|
+
* Thin CLI wrapper for @aios-fullstack/pro.
|
|
7
|
+
* Provides a clean npx interface: npx aios-pro install
|
|
8
|
+
*
|
|
9
|
+
* Commands:
|
|
10
|
+
* install Install @aios-fullstack/pro in the current project
|
|
11
|
+
* activate --key X Activate a license key
|
|
12
|
+
* deactivate Deactivate the current license
|
|
13
|
+
* status Show license status
|
|
14
|
+
* features List available pro features
|
|
15
|
+
* validate Force online license revalidation
|
|
16
|
+
* help Show help
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
const { execSync, spawnSync } = require('child_process');
|
|
20
|
+
const path = require('path');
|
|
21
|
+
const fs = require('fs');
|
|
22
|
+
|
|
23
|
+
const PRO_PACKAGE = '@aios-fullstack/pro';
|
|
24
|
+
const VERSION = require('../package.json').version;
|
|
25
|
+
|
|
26
|
+
const args = process.argv.slice(2);
|
|
27
|
+
const command = args[0];
|
|
28
|
+
|
|
29
|
+
// ─── Helpers ────────────────────────────────────────────────────────────────
|
|
30
|
+
|
|
31
|
+
function run(cmd, options = {}) {
|
|
32
|
+
const result = spawnSync(cmd, {
|
|
33
|
+
shell: true,
|
|
34
|
+
stdio: 'inherit',
|
|
35
|
+
cwd: process.cwd(),
|
|
36
|
+
...options,
|
|
37
|
+
});
|
|
38
|
+
return result.status;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function isProInstalled() {
|
|
42
|
+
try {
|
|
43
|
+
const pkgPath = path.join(process.cwd(), 'node_modules', '@aios-fullstack', 'pro', 'package.json');
|
|
44
|
+
return fs.existsSync(pkgPath);
|
|
45
|
+
} catch {
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function findAiosCli() {
|
|
51
|
+
// Check local node_modules first
|
|
52
|
+
const localBin = path.join(process.cwd(), 'node_modules', '.bin', 'aios');
|
|
53
|
+
if (fs.existsSync(localBin) || fs.existsSync(localBin + '.cmd')) {
|
|
54
|
+
return 'npx aios';
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Check global
|
|
58
|
+
try {
|
|
59
|
+
execSync('aios --version', { stdio: 'pipe' });
|
|
60
|
+
return 'aios';
|
|
61
|
+
} catch {
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function delegateToAios(subcommand) {
|
|
67
|
+
const aios = findAiosCli();
|
|
68
|
+
if (!aios) {
|
|
69
|
+
console.error('aios-core CLI not found.');
|
|
70
|
+
console.error('Install it first: npm install aios-core');
|
|
71
|
+
process.exit(1);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const spawnArgs = ['pro', subcommand, ...args.slice(1)];
|
|
75
|
+
const result = spawnSync(aios, spawnArgs, { stdio: 'inherit' });
|
|
76
|
+
process.exit(result.status ?? 0);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// ─── Commands ───────────────────────────────────────────────────────────────
|
|
80
|
+
|
|
81
|
+
function showHelp() {
|
|
82
|
+
console.log(`
|
|
83
|
+
aios-pro v${VERSION} — AIOS Pro CLI
|
|
84
|
+
|
|
85
|
+
Usage:
|
|
86
|
+
npx aios-pro <command> [options]
|
|
87
|
+
|
|
88
|
+
Commands:
|
|
89
|
+
install Install ${PRO_PACKAGE} in the current project
|
|
90
|
+
activate --key KEY Activate a license key
|
|
91
|
+
deactivate Deactivate the current license
|
|
92
|
+
status Show license status
|
|
93
|
+
features List available pro features
|
|
94
|
+
validate Force online license revalidation
|
|
95
|
+
help Show this help message
|
|
96
|
+
|
|
97
|
+
Examples:
|
|
98
|
+
npx aios-pro install
|
|
99
|
+
npx aios-pro activate --key PRO-XXXX-XXXX-XXXX-XXXX
|
|
100
|
+
npx aios-pro status
|
|
101
|
+
|
|
102
|
+
Documentation: https://synkra.ai/pro/docs
|
|
103
|
+
`);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function installPro() {
|
|
107
|
+
console.log(`\nInstalling ${PRO_PACKAGE}...\n`);
|
|
108
|
+
|
|
109
|
+
const exitCode = run(`npm install ${PRO_PACKAGE}`);
|
|
110
|
+
|
|
111
|
+
if (exitCode !== 0) {
|
|
112
|
+
console.error(`\nFailed to install ${PRO_PACKAGE}`);
|
|
113
|
+
process.exit(1);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
console.log(`\n✅ ${PRO_PACKAGE} installed successfully!\n`);
|
|
117
|
+
console.log('Next steps:');
|
|
118
|
+
console.log(' npx aios-pro activate --key PRO-XXXX-XXXX-XXXX-XXXX');
|
|
119
|
+
console.log(' npx aios-pro status');
|
|
120
|
+
console.log('');
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// ─── Main ───────────────────────────────────────────────────────────────────
|
|
124
|
+
|
|
125
|
+
if (!command || command === 'help' || command === '--help' || command === '-h') {
|
|
126
|
+
showHelp();
|
|
127
|
+
process.exit(0);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (command === '--version' || command === '-v') {
|
|
131
|
+
console.log(`aios-pro v${VERSION}`);
|
|
132
|
+
process.exit(0);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
switch (command) {
|
|
136
|
+
case 'install':
|
|
137
|
+
case 'setup':
|
|
138
|
+
installPro();
|
|
139
|
+
break;
|
|
140
|
+
|
|
141
|
+
case 'activate':
|
|
142
|
+
case 'deactivate':
|
|
143
|
+
case 'status':
|
|
144
|
+
case 'features':
|
|
145
|
+
case 'validate':
|
|
146
|
+
if (!isProInstalled()) {
|
|
147
|
+
console.error(`${PRO_PACKAGE} is not installed.`);
|
|
148
|
+
console.error('Run first: npx aios-pro install\n');
|
|
149
|
+
process.exit(1);
|
|
150
|
+
}
|
|
151
|
+
delegateToAios(command);
|
|
152
|
+
break;
|
|
153
|
+
|
|
154
|
+
default:
|
|
155
|
+
console.error(`Unknown command: ${command}\n`);
|
|
156
|
+
showHelp();
|
|
157
|
+
process.exit(1);
|
|
158
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "aios-pro",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "CLI for AIOS Pro — install, activate and manage your license",
|
|
5
|
+
"bin": {
|
|
6
|
+
"aios-pro": "bin/aios-pro.js"
|
|
7
|
+
},
|
|
8
|
+
"files": [
|
|
9
|
+
"bin/"
|
|
10
|
+
],
|
|
11
|
+
"keywords": [
|
|
12
|
+
"aios",
|
|
13
|
+
"pro",
|
|
14
|
+
"license",
|
|
15
|
+
"cli",
|
|
16
|
+
"synkra"
|
|
17
|
+
],
|
|
18
|
+
"author": "SynkraAI",
|
|
19
|
+
"license": "MIT",
|
|
20
|
+
"repository": {
|
|
21
|
+
"type": "git",
|
|
22
|
+
"url": "git+https://github.com/SynkraAI/aios-core.git",
|
|
23
|
+
"directory": "packages/aios-pro-cli"
|
|
24
|
+
},
|
|
25
|
+
"engines": {
|
|
26
|
+
"node": ">=18"
|
|
27
|
+
},
|
|
28
|
+
"publishConfig": {
|
|
29
|
+
"access": "public",
|
|
30
|
+
"registry": "https://registry.npmjs.org"
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -321,6 +321,29 @@ async function installAiosCore(options = {}) {
|
|
|
321
321
|
});
|
|
322
322
|
result.versionInfo = versionInfo;
|
|
323
323
|
|
|
324
|
+
// BUG-2 fix (INS-1): Install .aios-core dependencies after copy
|
|
325
|
+
// The copied .aios-core/package.json has dependencies (js-yaml, execa, etc.)
|
|
326
|
+
// that must be installed for the activation pipeline to work
|
|
327
|
+
const aiosCorePackageJson = path.join(targetAiosCore, 'package.json');
|
|
328
|
+
if (await fs.pathExists(aiosCorePackageJson)) {
|
|
329
|
+
spinner.text = 'Installing .aios-core dependencies (js-yaml, etc.)...';
|
|
330
|
+
try {
|
|
331
|
+
const { exec } = require('child_process');
|
|
332
|
+
const { promisify } = require('util');
|
|
333
|
+
const execAsync = promisify(exec);
|
|
334
|
+
await execAsync('npm install --production --ignore-scripts', {
|
|
335
|
+
cwd: targetAiosCore,
|
|
336
|
+
timeout: 60000,
|
|
337
|
+
});
|
|
338
|
+
spinner.succeed('Installed .aios-core dependencies');
|
|
339
|
+
spinner.start('Finishing installation...');
|
|
340
|
+
} catch (depError) {
|
|
341
|
+
spinner.warn(`Could not install .aios-core dependencies: ${depError.message}`);
|
|
342
|
+
spinner.start('Continuing installation...');
|
|
343
|
+
result.errors.push(`Dependencies warning: ${depError.message}`);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
324
347
|
result.success = true;
|
|
325
348
|
spinner.succeed(`AIOS core installed (${result.installedFiles.length} files)`);
|
|
326
349
|
|