@josfox/jos 4.0.7 → 4.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -21
- package/README.md +138 -186
- package/bin/jos +160 -98
- package/bin/jos.cmd +5 -0
- package/package.json +40 -35
- package/src/adapters/index.js +16 -0
- package/src/adapters/native.js +41 -0
- package/src/adapters/ollama.js +140 -0
- package/src/commands/add.js +145 -145
- package/src/commands/get.js +245 -245
- package/src/commands/init.js +162 -162
- package/src/commands/llm.js +159 -0
- package/src/commands/prompts.js +229 -0
- package/src/commands/repo.js +139 -139
- package/src/commands/run.js +244 -244
- package/src/commands/secrets.js +137 -137
- package/src/commands/validate.js +194 -190
- package/src/commands/verify.js +98 -0
- package/src/serve.js +781 -780
- package/src/utils/crypto.js +41 -0
- package/src/utils/request.js +41 -0
- package/src/index.js +0 -0
package/src/commands/validate.js
CHANGED
|
@@ -1,190 +1,194 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* JOS VALIDATE Command - Validate .jos artifacts
|
|
3
|
-
* Checks schema, required keys, and integrity
|
|
4
|
-
* Format version v0.0.7 — Specification maturity v0.1.0 (Alpha)
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
const fs = require('fs');
|
|
8
|
-
const path = require('path');
|
|
9
|
-
const crypto = require('crypto');
|
|
10
|
-
|
|
11
|
-
const C = {
|
|
12
|
-
reset: '\x1b[0m', bold: '\x1b[1m', dim: '\x1b[2m',
|
|
13
|
-
purple: '\x1b[38;5;135m', cyan: '\x1b[38;5;51m',
|
|
14
|
-
green: '\x1b[38;5;78m', red: '\x1b[38;5;196m',
|
|
15
|
-
yellow: '\x1b[38;5;220m', gray: '\x1b[38;5;245m'
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
// Witness Logging
|
|
19
|
-
function logWitness(home, eventType, data) {
|
|
20
|
-
const runId = global.JOS_VALIDATE_ID || new Date().toISOString().replace(/[:.]/g, '-');
|
|
21
|
-
global.JOS_VALIDATE_ID = runId;
|
|
22
|
-
|
|
23
|
-
const runDir = path.join(home, 'runs', runId);
|
|
24
|
-
if (!fs.existsSync(runDir)) fs.mkdirSync(runDir, { recursive: true });
|
|
25
|
-
|
|
26
|
-
const event = {
|
|
27
|
-
timestamp: new Date().toISOString(),
|
|
28
|
-
type: `validate:${eventType}`,
|
|
29
|
-
...data
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
fs.appendFileSync(path.join(runDir, 'events.jsonl'), JSON.stringify(event) + '\n');
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
// Required keys for JOSFOXAI + MAGIC compliance
|
|
36
|
-
const JOSFOXAI_KEYS = ['jos', 'orchestration_contract', 'security', 'files', 'orchestration', 'x_run_params', 'adaptive_ai', 'id_jos'];
|
|
37
|
-
const MAGIC_KEYS = ['meta', 'artifacts', 'guardrails', 'intention', 'capabilities'];
|
|
38
|
-
const ALL_REQUIRED_KEYS = [...JOSFOXAI_KEYS, ...MAGIC_KEYS];
|
|
39
|
-
|
|
40
|
-
exports.execute = async (args, home) => {
|
|
41
|
-
const target = args[0];
|
|
42
|
-
const insecure = args.includes('--insecure');
|
|
43
|
-
const verbose = args.includes('--verbose') || args.includes('-v');
|
|
44
|
-
|
|
45
|
-
if (!target || args.includes('--help')) {
|
|
46
|
-
console.log(`
|
|
47
|
-
${C.purple}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${C.reset}
|
|
48
|
-
${C.bold}JOS VALIDATE${C.reset} // Validate .jos artifacts
|
|
49
|
-
${C.purple}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${C.reset}
|
|
50
|
-
|
|
51
|
-
${C.bold}Usage:${C.reset}
|
|
52
|
-
jos validate <file.jos> [options]
|
|
53
|
-
|
|
54
|
-
${C.bold}Options:${C.reset}
|
|
55
|
-
--insecure Skip integrity verification
|
|
56
|
-
--verbose Show detailed validation information
|
|
57
|
-
|
|
58
|
-
${C.bold}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
let
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
console.log(`${C.
|
|
87
|
-
results.push({ check: 'json_syntax', passed:
|
|
88
|
-
logWitness(home, '
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
};
|
|
1
|
+
/**
|
|
2
|
+
* JOS VALIDATE Command - Validate .jos artifacts
|
|
3
|
+
* Checks schema, required keys, and integrity
|
|
4
|
+
* Format version v0.0.7 — Specification maturity v0.1.0 (Alpha)
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const fs = require('fs');
|
|
8
|
+
const path = require('path');
|
|
9
|
+
const crypto = require('crypto');
|
|
10
|
+
|
|
11
|
+
const C = {
|
|
12
|
+
reset: '\x1b[0m', bold: '\x1b[1m', dim: '\x1b[2m',
|
|
13
|
+
purple: '\x1b[38;5;135m', cyan: '\x1b[38;5;51m',
|
|
14
|
+
green: '\x1b[38;5;78m', red: '\x1b[38;5;196m',
|
|
15
|
+
yellow: '\x1b[38;5;220m', gray: '\x1b[38;5;245m'
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
// Witness Logging
|
|
19
|
+
function logWitness(home, eventType, data) {
|
|
20
|
+
const runId = global.JOS_VALIDATE_ID || new Date().toISOString().replace(/[:.]/g, '-');
|
|
21
|
+
global.JOS_VALIDATE_ID = runId;
|
|
22
|
+
|
|
23
|
+
const runDir = path.join(home, 'runs', runId);
|
|
24
|
+
if (!fs.existsSync(runDir)) fs.mkdirSync(runDir, { recursive: true });
|
|
25
|
+
|
|
26
|
+
const event = {
|
|
27
|
+
timestamp: new Date().toISOString(),
|
|
28
|
+
type: `validate:${eventType}`,
|
|
29
|
+
...data
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
fs.appendFileSync(path.join(runDir, 'events.jsonl'), JSON.stringify(event) + '\n');
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Required keys for JOSFOXAI + MAGIC compliance (ALL REQUIRED - NO EXCEPTIONS)
|
|
36
|
+
const JOSFOXAI_KEYS = ['jos', 'orchestration_contract', 'security', 'files', 'orchestration', 'x_run_params', 'adaptive_ai', 'id_jos'];
|
|
37
|
+
const MAGIC_KEYS = ['meta', 'artifacts', 'guardrails', 'intention', 'capabilities'];
|
|
38
|
+
const ALL_REQUIRED_KEYS = [...JOSFOXAI_KEYS, ...MAGIC_KEYS];
|
|
39
|
+
|
|
40
|
+
exports.execute = async (args, home) => {
|
|
41
|
+
const target = args[0];
|
|
42
|
+
const insecure = args.includes('--insecure');
|
|
43
|
+
const verbose = args.includes('--verbose') || args.includes('-v');
|
|
44
|
+
|
|
45
|
+
if (!target || args.includes('--help')) {
|
|
46
|
+
console.log(`
|
|
47
|
+
${C.purple}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${C.reset}
|
|
48
|
+
${C.bold}JOS VALIDATE${C.reset} // Validate .jos artifacts (STRICT)
|
|
49
|
+
${C.purple}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${C.reset}
|
|
50
|
+
|
|
51
|
+
${C.bold}Usage:${C.reset}
|
|
52
|
+
jos validate <file.jos> [options]
|
|
53
|
+
|
|
54
|
+
${C.bold}Options:${C.reset}
|
|
55
|
+
--insecure Skip integrity verification
|
|
56
|
+
--verbose Show detailed validation information
|
|
57
|
+
|
|
58
|
+
${C.bold}ALL REQUIRED Keys:${C.reset}
|
|
59
|
+
JOSFOXAI: ${JOSFOXAI_KEYS.join(', ')}
|
|
60
|
+
MAGIC: ${MAGIC_KEYS.join(', ')}
|
|
61
|
+
|
|
62
|
+
${C.bold}Validates:${C.reset}
|
|
63
|
+
1. JSON syntax
|
|
64
|
+
2. ALL JOSFOXAI keys (8 required)
|
|
65
|
+
3. ALL MAGIC keys (5 required)
|
|
66
|
+
4. Integrity manifest (unless --insecure)
|
|
67
|
+
`);
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
console.log(`\n${C.purple}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${C.reset}`);
|
|
72
|
+
console.log(`${C.bold}JOS VALIDATE${C.reset} // ${C.gray}Format v0.0.7 — STRICT MODE${C.reset}`);
|
|
73
|
+
console.log(`${C.purple}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${C.reset}`);
|
|
74
|
+
console.log(`\n${C.cyan}📋 Artifact:${C.reset} ${target}`);
|
|
75
|
+
|
|
76
|
+
logWitness(home, 'start', { artifact: target });
|
|
77
|
+
|
|
78
|
+
let allPassed = true;
|
|
79
|
+
const results = [];
|
|
80
|
+
|
|
81
|
+
// 1. JSON Syntax Check
|
|
82
|
+
let content, artifact;
|
|
83
|
+
try {
|
|
84
|
+
content = fs.readFileSync(target, 'utf8');
|
|
85
|
+
artifact = JSON.parse(content);
|
|
86
|
+
console.log(`${C.green} ✓ JSON Syntax Valid${C.reset}`);
|
|
87
|
+
results.push({ check: 'json_syntax', passed: true });
|
|
88
|
+
logWitness(home, 'check_passed', { check: 'json_syntax' });
|
|
89
|
+
} catch (e) {
|
|
90
|
+
console.log(`${C.red} ✖ JSON Error: ${e.message}${C.reset}`);
|
|
91
|
+
results.push({ check: 'json_syntax', passed: false, error: e.message });
|
|
92
|
+
logWitness(home, 'check_failed', { check: 'json_syntax', error: e.message });
|
|
93
|
+
process.exit(1);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// 2. JOSFOXAI Keys Check (ALL 8 REQUIRED)
|
|
97
|
+
const missingJosfoxai = JOSFOXAI_KEYS.filter(k => !artifact[k]);
|
|
98
|
+
if (missingJosfoxai.length > 0) {
|
|
99
|
+
console.log(`${C.red} ✖ Missing JOSFOXAI Keys: ${missingJosfoxai.join(', ')}${C.reset}`);
|
|
100
|
+
results.push({ check: 'josfoxai_keys', passed: false, missing: missingJosfoxai });
|
|
101
|
+
logWitness(home, 'check_failed', { check: 'josfoxai_keys', missing: missingJosfoxai });
|
|
102
|
+
allPassed = false;
|
|
103
|
+
} else {
|
|
104
|
+
console.log(`${C.green} ✓ JOSFOXAI Keys Present (${JOSFOXAI_KEYS.length}/${JOSFOXAI_KEYS.length})${C.reset}`);
|
|
105
|
+
results.push({ check: 'josfoxai_keys', passed: true });
|
|
106
|
+
logWitness(home, 'check_passed', { check: 'josfoxai_keys' });
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// 3. MAGIC Keys Check (ALL 5 REQUIRED)
|
|
110
|
+
const missingMagic = MAGIC_KEYS.filter(k => !artifact[k]);
|
|
111
|
+
if (missingMagic.length > 0) {
|
|
112
|
+
console.log(`${C.red} ✖ Missing MAGIC Keys: ${missingMagic.join(', ')}${C.reset}`);
|
|
113
|
+
results.push({ check: 'magic_keys', passed: false, missing: missingMagic });
|
|
114
|
+
logWitness(home, 'check_failed', { check: 'magic_keys', missing: missingMagic });
|
|
115
|
+
allPassed = false;
|
|
116
|
+
} else {
|
|
117
|
+
console.log(`${C.green} ✓ MAGIC Keys Present (${MAGIC_KEYS.length}/${MAGIC_KEYS.length})${C.reset}`);
|
|
118
|
+
results.push({ check: 'magic_keys', passed: true });
|
|
119
|
+
logWitness(home, 'check_passed', { check: 'magic_keys' });
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// 4. Orchestration Structure Check
|
|
123
|
+
if (artifact.orchestration) {
|
|
124
|
+
const hasDefinitions = artifact.orchestration.definitions && Object.keys(artifact.orchestration.definitions).length > 0;
|
|
125
|
+
const hasFlows = artifact.orchestration.flows && Object.keys(artifact.orchestration.flows).length > 0;
|
|
126
|
+
|
|
127
|
+
if (hasDefinitions && hasFlows) {
|
|
128
|
+
const defCount = Object.keys(artifact.orchestration.definitions).length;
|
|
129
|
+
const flowCount = Object.keys(artifact.orchestration.flows).length;
|
|
130
|
+
console.log(`${C.green} ✓ Orchestration Structure (${defCount} definitions, ${flowCount} flows)${C.reset}`);
|
|
131
|
+
results.push({ check: 'orchestration_structure', passed: true, definitions: defCount, flows: flowCount });
|
|
132
|
+
} else {
|
|
133
|
+
console.log(`${C.yellow} ⚠ Orchestration may be incomplete${C.reset}`);
|
|
134
|
+
results.push({ check: 'orchestration_structure', passed: true, warning: 'may be incomplete' });
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// 5. Integrity Check
|
|
139
|
+
if (!insecure) {
|
|
140
|
+
if (artifact.security?.integrity_ref) {
|
|
141
|
+
const manifestPath = path.resolve(path.dirname(target), artifact.security.integrity_ref);
|
|
142
|
+
if (fs.existsSync(manifestPath)) {
|
|
143
|
+
try {
|
|
144
|
+
const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
|
|
145
|
+
const hash = crypto.createHash('sha256').update(content).digest('hex');
|
|
146
|
+
if (hash === manifest.artifact_sha256) {
|
|
147
|
+
console.log(`${C.green} ✓ Integrity Verified (SHA-256 match)${C.reset}`);
|
|
148
|
+
if (verbose) {
|
|
149
|
+
console.log(`${C.gray} Hash: ${hash}${C.reset}`);
|
|
150
|
+
}
|
|
151
|
+
results.push({ check: 'integrity', passed: true, hash: hash });
|
|
152
|
+
logWitness(home, 'integrity_verified', { hash: hash, manifest: artifact.security.integrity_ref });
|
|
153
|
+
} else {
|
|
154
|
+
console.log(`${C.red} ✖ Integrity Mismatch!${C.reset}`);
|
|
155
|
+
if (verbose) {
|
|
156
|
+
console.log(`${C.gray} Expected: ${manifest.artifact_sha256}${C.reset}`);
|
|
157
|
+
console.log(`${C.gray} Actual: ${hash}${C.reset}`);
|
|
158
|
+
}
|
|
159
|
+
results.push({ check: 'integrity', passed: false, expected: manifest.artifact_sha256, actual: hash });
|
|
160
|
+
logWitness(home, 'integrity_failed', { expected: manifest.artifact_sha256, actual: hash });
|
|
161
|
+
allPassed = false;
|
|
162
|
+
}
|
|
163
|
+
} catch (e) {
|
|
164
|
+
console.log(`${C.red} ✖ Invalid Manifest: ${e.message}${C.reset}`);
|
|
165
|
+
results.push({ check: 'integrity', passed: false, error: e.message });
|
|
166
|
+
allPassed = false;
|
|
167
|
+
}
|
|
168
|
+
} else {
|
|
169
|
+
console.log(`${C.red} ✖ Manifest Not Found: ${artifact.security.integrity_ref}${C.reset}`);
|
|
170
|
+
results.push({ check: 'integrity', passed: false, error: 'manifest not found' });
|
|
171
|
+
logWitness(home, 'integrity_failed', { error: 'manifest not found' });
|
|
172
|
+
allPassed = false;
|
|
173
|
+
}
|
|
174
|
+
} else {
|
|
175
|
+
console.log(`${C.yellow} ⚠ No Integrity Reference (security.integrity_ref)${C.reset}`);
|
|
176
|
+
results.push({ check: 'integrity', passed: true, warning: 'no integrity_ref' });
|
|
177
|
+
}
|
|
178
|
+
} else {
|
|
179
|
+
console.log(`${C.yellow} ⚠ Integrity Check Skipped (--insecure)${C.reset}`);
|
|
180
|
+
results.push({ check: 'integrity', skipped: true });
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// Summary
|
|
184
|
+
console.log('');
|
|
185
|
+
if (allPassed) {
|
|
186
|
+
console.log(`${C.green}${C.bold}✓ VALIDATION PASSED${C.reset}`);
|
|
187
|
+
logWitness(home, 'success', { results: results });
|
|
188
|
+
} else {
|
|
189
|
+
console.log(`${C.red}${C.bold}✖ VALIDATION FAILED${C.reset}`);
|
|
190
|
+
logWitness(home, 'failed', { results: results });
|
|
191
|
+
process.exit(1);
|
|
192
|
+
}
|
|
193
|
+
console.log('');
|
|
194
|
+
};
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JOS VERIFY Command - Self-Verification Suite
|
|
3
|
+
* Implements "Dogfooding" strategy
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const fs = require('fs');
|
|
7
|
+
const path = require('path');
|
|
8
|
+
const { spawnSync, execSync } = require('child_process');
|
|
9
|
+
|
|
10
|
+
const C = {
|
|
11
|
+
reset: '\x1b[0m', bold: '\x1b[1m',
|
|
12
|
+
green: '\x1b[38;5;78m', red: '\x1b[38;5;196m',
|
|
13
|
+
cyan: '\x1b[38;5;51m', gray: '\x1b[38;5;245m',
|
|
14
|
+
yellow: '\x1b[38;5;220m'
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
exports.execute = async (args, home) => {
|
|
18
|
+
console.log(`\n${C.cyan}${C.bold}🦊 JOS Self-Verification${C.reset}\n`);
|
|
19
|
+
|
|
20
|
+
const binDir = path.join(__dirname, '..', '..', 'bin');
|
|
21
|
+
const binJos = path.join(binDir, 'jos');
|
|
22
|
+
|
|
23
|
+
// 1. PATH Injection (Crucial for Windows)
|
|
24
|
+
// We add the bin directory to the front of PATH so 'jos' resolves to our binary
|
|
25
|
+
const env = { ...process.env, CI: 'true' };
|
|
26
|
+
env.PATH = process.platform === 'win32'
|
|
27
|
+
? `${binDir};${process.env.PATH}`
|
|
28
|
+
: `${binDir}:${process.env.PATH}`;
|
|
29
|
+
|
|
30
|
+
let failed = false;
|
|
31
|
+
|
|
32
|
+
// 2. Dogfooding: Run verification.jos
|
|
33
|
+
console.log(`${C.bold}1. Kernel Smoke Tests (verification.jos)${C.reset}`);
|
|
34
|
+
const verifyArtifact = path.join(__dirname, '..', '..', 'artifacts', 'verification.jos');
|
|
35
|
+
|
|
36
|
+
if (!fs.existsSync(verifyArtifact)) {
|
|
37
|
+
console.error(`${C.red}✖ Internal Error: verification.jos not found at ${verifyArtifact}${C.reset}`);
|
|
38
|
+
process.exit(1);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
try {
|
|
42
|
+
// We defer to the 'run' command logic by spawning a child process
|
|
43
|
+
// This ensures identical execution environment to a real user run
|
|
44
|
+
const result = spawnSync(process.execPath, [binJos, 'run', verifyArtifact], {
|
|
45
|
+
encoding: 'utf8',
|
|
46
|
+
env,
|
|
47
|
+
stdio: 'inherit'
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
if (result.status !== 0) {
|
|
51
|
+
console.error(`\n${C.red}✖ Smoke tests failed (Exit Code: ${result.status})${C.reset}`);
|
|
52
|
+
failed = true;
|
|
53
|
+
} else {
|
|
54
|
+
console.log(`${C.green}✓ Smoke tests passed${C.reset}`);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
} catch (e) {
|
|
58
|
+
console.error(`${C.red}✖ Execution failed: ${e.message}${C.reset}`);
|
|
59
|
+
failed = true;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// 3. Functional Test (Init + Validate)
|
|
63
|
+
console.log(`\n${C.bold}2. Functional Lifecycle (Init + Validate)${C.reset}`);
|
|
64
|
+
const TEST_ARTIFACT = 'native-test';
|
|
65
|
+
const TEST_FILE = `${TEST_ARTIFACT}.jos`;
|
|
66
|
+
|
|
67
|
+
// Cleanup
|
|
68
|
+
if (fs.existsSync(TEST_FILE)) fs.unlinkSync(TEST_FILE);
|
|
69
|
+
|
|
70
|
+
try {
|
|
71
|
+
console.log(`${C.gray}→ Initializing ${TEST_ARTIFACT}...${C.reset}`);
|
|
72
|
+
execSync(`"${process.execPath}" "${binJos}" init ${TEST_ARTIFACT} --pipeline`, { env, stdio: 'pipe' });
|
|
73
|
+
|
|
74
|
+
if (!fs.existsSync(TEST_FILE)) {
|
|
75
|
+
throw new Error('Artifact file not created');
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
console.log(`${C.gray}→ Validating artifact...${C.reset}`);
|
|
79
|
+
execSync(`"${process.execPath}" "${binJos}" validate ${TEST_FILE}`, { env, stdio: 'pipe' });
|
|
80
|
+
|
|
81
|
+
console.log(`${C.green}✓ Lifecycle tests passed${C.reset}`);
|
|
82
|
+
|
|
83
|
+
} catch (e) {
|
|
84
|
+
console.error(`${C.red}✖ Functional test failed: ${e.message}${C.reset}`);
|
|
85
|
+
failed = true;
|
|
86
|
+
} finally {
|
|
87
|
+
if (fs.existsSync(TEST_FILE)) fs.unlinkSync(TEST_FILE);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
console.log(`\n${C.gray}----------------------------------------${C.reset}`);
|
|
91
|
+
if (failed) {
|
|
92
|
+
console.log(`${C.red}${C.bold}❌ VERIFICATION FAILED${C.reset}`);
|
|
93
|
+
process.exit(1);
|
|
94
|
+
} else {
|
|
95
|
+
console.log(`${C.green}${C.bold}✅ SYSTEM HEALTHY${C.reset}`);
|
|
96
|
+
process.exit(0);
|
|
97
|
+
}
|
|
98
|
+
};
|