@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/run.js
CHANGED
|
@@ -1,244 +1,244 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* JOS RUN Command - Execute .jos artifacts
|
|
3
|
-
* Complies with JOSFOXAI MAGIC contract
|
|
4
|
-
* Integrity Strategy: Detached Manifest (.sig.json)
|
|
5
|
-
* Format version v0.0.7 — Specification maturity v0.1.0 (Alpha)
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
const fs = require('fs');
|
|
9
|
-
const path = require('path');
|
|
10
|
-
const { execSync, spawn } = require('child_process');
|
|
11
|
-
const crypto = require('crypto');
|
|
12
|
-
|
|
13
|
-
// AURORA colors
|
|
14
|
-
const C = {
|
|
15
|
-
reset: '\x1b[0m', bold: '\x1b[1m', dim: '\x1b[2m',
|
|
16
|
-
purple: '\x1b[38;5;135m', cyan: '\x1b[38;5;51m',
|
|
17
|
-
green: '\x1b[38;5;78m', red: '\x1b[38;5;196m',
|
|
18
|
-
yellow: '\x1b[38;5;220m', white: '\x1b[38;5;255m',
|
|
19
|
-
gray: '\x1b[38;5;245m', blue: '\x1b[38;5;39m'
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
// Witness Logging
|
|
23
|
-
function logWitness(home, eventType, data) {
|
|
24
|
-
const runId = global.JOS_RUN_ID || new Date().toISOString().replace(/[:.]/g, '-');
|
|
25
|
-
global.JOS_RUN_ID = runId;
|
|
26
|
-
|
|
27
|
-
const runDir = path.join(home, 'runs', runId);
|
|
28
|
-
if (!fs.existsSync(runDir)) fs.mkdirSync(runDir, { recursive: true });
|
|
29
|
-
|
|
30
|
-
const event = {
|
|
31
|
-
timestamp: new Date().toISOString(),
|
|
32
|
-
type: `run:${eventType}`,
|
|
33
|
-
...data
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
fs.appendFileSync(path.join(runDir, 'events.jsonl'), JSON.stringify(event) + '\n');
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
// Compute SHA-256 integrity
|
|
40
|
-
function computeIntegrity(content) {
|
|
41
|
-
return crypto.createHash('sha256').update(content).digest('hex');
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// Verify Integrity using Detached Manifest
|
|
45
|
-
function verifyIntegrity(artifactPath, content, artifact) {
|
|
46
|
-
const integrityRef = artifact.security?.integrity_ref;
|
|
47
|
-
if (!integrityRef) return { valid: true, warning: "open (no integrity_ref)" };
|
|
48
|
-
|
|
49
|
-
const manifestPath = path.resolve(path.dirname(artifactPath), integrityRef);
|
|
50
|
-
if (!fs.existsSync(manifestPath)) {
|
|
51
|
-
return { valid: false, error: `Manifest not found at ${manifestPath}` };
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
let manifest;
|
|
55
|
-
try {
|
|
56
|
-
manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
|
|
57
|
-
} catch (e) {
|
|
58
|
-
return { valid: false, error: "Invalid manifest JSON" };
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
const actualHash = computeIntegrity(content);
|
|
62
|
-
if (actualHash !== manifest.artifact_sha256) {
|
|
63
|
-
return {
|
|
64
|
-
valid: false,
|
|
65
|
-
error: `Hash mismatch. Expected: ${manifest.artifact_sha256.substring(0, 16)}..., Got: ${actualHash.substring(0, 16)}...`
|
|
66
|
-
};
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
return { valid: true, verified: true, hash: actualHash };
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
exports.execute = async (args, home) => {
|
|
73
|
-
const target = args[0];
|
|
74
|
-
const dryRun = args.includes('--dry-run');
|
|
75
|
-
const insecure = args.includes('--insecure');
|
|
76
|
-
|
|
77
|
-
if (args.includes('--help') || !target) {
|
|
78
|
-
console.log(`
|
|
79
|
-
${C.purple}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${C.reset}
|
|
80
|
-
${C.bold}JOS RUN${C.reset} // Execute .jos artifacts
|
|
81
|
-
${C.purple}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${C.reset}
|
|
82
|
-
|
|
83
|
-
${C.bold}Usage:${C.reset}
|
|
84
|
-
jos run <file.jos> [options]
|
|
85
|
-
|
|
86
|
-
${C.bold}Options:${C.reset}
|
|
87
|
-
--flow <name> Flow to execute (default: main)
|
|
88
|
-
--dry-run Simulate without executing
|
|
89
|
-
--insecure Skip integrity verification
|
|
90
|
-
|
|
91
|
-
${C.bold}Example:${C.reset}
|
|
92
|
-
jos run orchestration.jos --flow publish_all --dry-run
|
|
93
|
-
`);
|
|
94
|
-
return;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
let artifactPath = path.resolve(target);
|
|
98
|
-
if (!fs.existsSync(artifactPath)) {
|
|
99
|
-
if (fs.existsSync(path.join(home, 'artifacts', target))) {
|
|
100
|
-
artifactPath = path.join(home, 'artifacts', target);
|
|
101
|
-
} else {
|
|
102
|
-
console.log(`${C.red}✖ Artifact not found:${C.reset} ${target}`);
|
|
103
|
-
process.exit(1);
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
const content = fs.readFileSync(artifactPath, 'utf8');
|
|
108
|
-
const artifact = JSON.parse(content);
|
|
109
|
-
|
|
110
|
-
// Init Witness
|
|
111
|
-
logWitness(home, 'start', { artifact: artifactPath, dryRun: dryRun });
|
|
112
|
-
|
|
113
|
-
// Header
|
|
114
|
-
console.log(`\n${C.purple}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${C.reset}`);
|
|
115
|
-
console.log(`${C.cyan}${C.bold}JOS RUN${C.reset} // ${C.gray}JOSFOXAI MAGIC Runtime${C.reset}`);
|
|
116
|
-
console.log(`${C.purple}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${C.reset}\n`);
|
|
117
|
-
|
|
118
|
-
// Mode indicator
|
|
119
|
-
if (dryRun) {
|
|
120
|
-
console.log(`${C.yellow}${C.bold}⚡ DRY RUN MODE${C.reset} ${C.gray}— No commands will be executed${C.reset}\n`);
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
// Artifact info
|
|
124
|
-
console.log(`${C.cyan}📦 Artifact:${C.reset} ${artifact.meta?.name || path.basename(artifactPath)}`);
|
|
125
|
-
console.log(`${C.cyan}📄 File:${C.reset} ${path.basename(artifactPath)}`);
|
|
126
|
-
console.log(`${C.cyan}🆔 ID:${C.reset} ${artifact.id_jos || 'N/A'}`);
|
|
127
|
-
|
|
128
|
-
// Integrity verification
|
|
129
|
-
if (!insecure) {
|
|
130
|
-
const integrity = verifyIntegrity(artifactPath, content, artifact);
|
|
131
|
-
if (!integrity.valid) {
|
|
132
|
-
console.log(`${C.cyan}🔐 Integrity:${C.reset} ${C.red}FAILED - ${integrity.error}${C.reset}`);
|
|
133
|
-
logWitness(home, 'integrity_failed', { error: integrity.error });
|
|
134
|
-
process.exit(1);
|
|
135
|
-
} else if (integrity.verified) {
|
|
136
|
-
console.log(`${C.cyan}🔐 Integrity:${C.reset} ${C.green}✓ Verified${C.reset} ${C.gray}(${integrity.hash.substring(0, 16)}...)${C.reset}`);
|
|
137
|
-
logWitness(home, 'integrity_verified', { hash: integrity.hash });
|
|
138
|
-
} else {
|
|
139
|
-
console.log(`${C.cyan}🔐 Integrity:${C.reset} ${C.yellow}⚠ ${integrity.warning}${C.reset}`);
|
|
140
|
-
}
|
|
141
|
-
} else {
|
|
142
|
-
console.log(`${C.cyan}🔐 Integrity:${C.reset} ${C.yellow}⚠ Skipped (--insecure)${C.reset}`);
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
// MAGIC validation
|
|
146
|
-
const hasMagic = artifact.intention && artifact.guardrails && artifact.capabilities;
|
|
147
|
-
console.log(`${C.cyan}✨ MAGIC:${C.reset} ${hasMagic ? C.green + '✓ Valid' : C.yellow + '⚠ Partial'}${C.reset}`);
|
|
148
|
-
|
|
149
|
-
// Intention
|
|
150
|
-
if (artifact.intention?.objective) {
|
|
151
|
-
console.log(`${C.cyan}🎯 Intention:${C.reset} ${artifact.intention.objective}`);
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
// Guardrails
|
|
155
|
-
if (artifact.guardrails?.avoid?.length > 0) {
|
|
156
|
-
console.log(`${C.cyan}🛡️ Guardrails:${C.reset} ${artifact.guardrails.avoid.join(', ')}`);
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
// Flow selection
|
|
160
|
-
const flowName = args.includes('--flow') ? args[args.indexOf('--flow') + 1] : 'main';
|
|
161
|
-
const flow = artifact.orchestration?.flows?.[flowName] ||
|
|
162
|
-
artifact.orchestration?.pipelines?.[flowName];
|
|
163
|
-
|
|
164
|
-
if (!flow) {
|
|
165
|
-
console.log(`\n${C.red}✖ Flow '${flowName}' not found.${C.reset}`);
|
|
166
|
-
const available = [
|
|
167
|
-
...Object.keys(artifact.orchestration?.flows || {}),
|
|
168
|
-
...Object.keys(artifact.orchestration?.pipelines || {})
|
|
169
|
-
];
|
|
170
|
-
if (available.length > 0) {
|
|
171
|
-
console.log(`${C.gray}Available flows: ${available.join(', ')}${C.reset}`);
|
|
172
|
-
}
|
|
173
|
-
process.exit(1);
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
// Execution plan
|
|
177
|
-
console.log(`\n${C.cyan}▶ Flow:${C.reset} ${C.bold}${flowName}${C.reset}`);
|
|
178
|
-
if (flow.description) {
|
|
179
|
-
console.log(`${C.gray} ${flow.description}${C.reset}`);
|
|
180
|
-
}
|
|
181
|
-
console.log(`${C.gray} Steps: ${flow.steps?.join(' → ') || 'none'}${C.reset}\n`);
|
|
182
|
-
|
|
183
|
-
// Execute steps
|
|
184
|
-
let stepIndex = 0;
|
|
185
|
-
for (const stepName of flow.steps || []) {
|
|
186
|
-
stepIndex++;
|
|
187
|
-
const def = artifact.orchestration.definitions?.[stepName];
|
|
188
|
-
|
|
189
|
-
if (!def) {
|
|
190
|
-
console.log(`${C.red} [${stepIndex}] ✖ ${stepName}: Definition not found${C.reset}`);
|
|
191
|
-
logWitness(home, 'step_error', { step: stepName, error: 'definition not found' });
|
|
192
|
-
continue;
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
logWitness(home, 'step_start', { step: stepName, type: def.type, index: stepIndex });
|
|
196
|
-
|
|
197
|
-
const typeIcon = def.type === 'shell' ? '⚡' : def.type === 'jos' ? '📦' : '●';
|
|
198
|
-
|
|
199
|
-
if (dryRun) {
|
|
200
|
-
console.log(`${C.yellow} [${stepIndex}] ${typeIcon} ${stepName}${C.reset}`);
|
|
201
|
-
if (def.description) console.log(`${C.gray} ${def.description}${C.reset}`);
|
|
202
|
-
if (def.type === 'shell') {
|
|
203
|
-
const cmdPreview = def.command.length > 60 ? def.command.substring(0, 60) + '...' : def.command;
|
|
204
|
-
console.log(`${C.dim} $ ${cmdPreview}${C.reset}`);
|
|
205
|
-
} else if (def.type === 'jos') {
|
|
206
|
-
console.log(`${C.dim} → ${def.artifact}${C.reset}`);
|
|
207
|
-
}
|
|
208
|
-
logWitness(home, 'step_dry_run', { step: stepName });
|
|
209
|
-
continue;
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
// Real execution
|
|
213
|
-
console.log(`${C.blue} [${stepIndex}] ${typeIcon} ${stepName}...${C.reset}`);
|
|
214
|
-
|
|
215
|
-
try {
|
|
216
|
-
if (def.type === 'shell') {
|
|
217
|
-
execSync(def.command, { stdio: 'inherit'
|
|
218
|
-
console.log(`${C.green} ✓ Complete${C.reset}`);
|
|
219
|
-
} else if (def.type === 'jos') {
|
|
220
|
-
console.log(`${C.purple} Running sub-artifact: ${def.artifact}${C.reset}`);
|
|
221
|
-
const subPath = path.resolve(path.dirname(artifactPath), def.artifact);
|
|
222
|
-
const binJos = process.argv[1];
|
|
223
|
-
execSync(`${process.execPath} "${binJos}" run "${subPath}" ${insecure ? '--insecure' : ''} --flow main`, {
|
|
224
|
-
stdio: 'inherit'
|
|
225
|
-
});
|
|
226
|
-
}
|
|
227
|
-
logWitness(home, 'step_complete', { step: stepName, success: true });
|
|
228
|
-
} catch (e) {
|
|
229
|
-
console.log(`${C.red} ✖ Failed: ${e.message}${C.reset}`);
|
|
230
|
-
logWitness(home, 'step_failed', { step: stepName, error: e.message });
|
|
231
|
-
logWitness(home, 'run_failed', { lastStep: stepName });
|
|
232
|
-
process.exit(1);
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
// Success
|
|
237
|
-
console.log(`\n${C.green}${C.bold}✓ ${dryRun ? 'Dry run complete' : 'Execution complete'}${C.reset}`);
|
|
238
|
-
if (artifact.intention?.success_criteria) {
|
|
239
|
-
console.log(`${C.gray} Success criteria: ${artifact.intention.success_criteria}${C.reset}`);
|
|
240
|
-
}
|
|
241
|
-
console.log('');
|
|
242
|
-
|
|
243
|
-
logWitness(home, 'success', { dryRun: dryRun, stepsExecuted: stepIndex });
|
|
244
|
-
};
|
|
1
|
+
/**
|
|
2
|
+
* JOS RUN Command - Execute .jos artifacts
|
|
3
|
+
* Complies with JOSFOXAI MAGIC contract
|
|
4
|
+
* Integrity Strategy: Detached Manifest (.sig.json)
|
|
5
|
+
* Format version v0.0.7 — Specification maturity v0.1.0 (Alpha)
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const fs = require('fs');
|
|
9
|
+
const path = require('path');
|
|
10
|
+
const { execSync, spawn } = require('child_process');
|
|
11
|
+
const crypto = require('crypto');
|
|
12
|
+
|
|
13
|
+
// AURORA colors
|
|
14
|
+
const C = {
|
|
15
|
+
reset: '\x1b[0m', bold: '\x1b[1m', dim: '\x1b[2m',
|
|
16
|
+
purple: '\x1b[38;5;135m', cyan: '\x1b[38;5;51m',
|
|
17
|
+
green: '\x1b[38;5;78m', red: '\x1b[38;5;196m',
|
|
18
|
+
yellow: '\x1b[38;5;220m', white: '\x1b[38;5;255m',
|
|
19
|
+
gray: '\x1b[38;5;245m', blue: '\x1b[38;5;39m'
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
// Witness Logging
|
|
23
|
+
function logWitness(home, eventType, data) {
|
|
24
|
+
const runId = global.JOS_RUN_ID || new Date().toISOString().replace(/[:.]/g, '-');
|
|
25
|
+
global.JOS_RUN_ID = runId;
|
|
26
|
+
|
|
27
|
+
const runDir = path.join(home, 'runs', runId);
|
|
28
|
+
if (!fs.existsSync(runDir)) fs.mkdirSync(runDir, { recursive: true });
|
|
29
|
+
|
|
30
|
+
const event = {
|
|
31
|
+
timestamp: new Date().toISOString(),
|
|
32
|
+
type: `run:${eventType}`,
|
|
33
|
+
...data
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
fs.appendFileSync(path.join(runDir, 'events.jsonl'), JSON.stringify(event) + '\n');
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Compute SHA-256 integrity
|
|
40
|
+
function computeIntegrity(content) {
|
|
41
|
+
return crypto.createHash('sha256').update(content).digest('hex');
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Verify Integrity using Detached Manifest
|
|
45
|
+
function verifyIntegrity(artifactPath, content, artifact) {
|
|
46
|
+
const integrityRef = artifact.security?.integrity_ref;
|
|
47
|
+
if (!integrityRef) return { valid: true, warning: "open (no integrity_ref)" };
|
|
48
|
+
|
|
49
|
+
const manifestPath = path.resolve(path.dirname(artifactPath), integrityRef);
|
|
50
|
+
if (!fs.existsSync(manifestPath)) {
|
|
51
|
+
return { valid: false, error: `Manifest not found at ${manifestPath}` };
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
let manifest;
|
|
55
|
+
try {
|
|
56
|
+
manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
|
|
57
|
+
} catch (e) {
|
|
58
|
+
return { valid: false, error: "Invalid manifest JSON" };
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const actualHash = computeIntegrity(content);
|
|
62
|
+
if (actualHash !== manifest.artifact_sha256) {
|
|
63
|
+
return {
|
|
64
|
+
valid: false,
|
|
65
|
+
error: `Hash mismatch. Expected: ${manifest.artifact_sha256.substring(0, 16)}..., Got: ${actualHash.substring(0, 16)}...`
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return { valid: true, verified: true, hash: actualHash };
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
exports.execute = async (args, home) => {
|
|
73
|
+
const target = args[0];
|
|
74
|
+
const dryRun = args.includes('--dry-run');
|
|
75
|
+
const insecure = args.includes('--insecure');
|
|
76
|
+
|
|
77
|
+
if (args.includes('--help') || !target) {
|
|
78
|
+
console.log(`
|
|
79
|
+
${C.purple}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${C.reset}
|
|
80
|
+
${C.bold}JOS RUN${C.reset} // Execute .jos artifacts
|
|
81
|
+
${C.purple}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${C.reset}
|
|
82
|
+
|
|
83
|
+
${C.bold}Usage:${C.reset}
|
|
84
|
+
jos run <file.jos> [options]
|
|
85
|
+
|
|
86
|
+
${C.bold}Options:${C.reset}
|
|
87
|
+
--flow <name> Flow to execute (default: main)
|
|
88
|
+
--dry-run Simulate without executing
|
|
89
|
+
--insecure Skip integrity verification
|
|
90
|
+
|
|
91
|
+
${C.bold}Example:${C.reset}
|
|
92
|
+
jos run orchestration.jos --flow publish_all --dry-run
|
|
93
|
+
`);
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
let artifactPath = path.resolve(target);
|
|
98
|
+
if (!fs.existsSync(artifactPath)) {
|
|
99
|
+
if (fs.existsSync(path.join(home, 'artifacts', target))) {
|
|
100
|
+
artifactPath = path.join(home, 'artifacts', target);
|
|
101
|
+
} else {
|
|
102
|
+
console.log(`${C.red}✖ Artifact not found:${C.reset} ${target}`);
|
|
103
|
+
process.exit(1);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const content = fs.readFileSync(artifactPath, 'utf8');
|
|
108
|
+
const artifact = JSON.parse(content);
|
|
109
|
+
|
|
110
|
+
// Init Witness
|
|
111
|
+
logWitness(home, 'start', { artifact: artifactPath, dryRun: dryRun });
|
|
112
|
+
|
|
113
|
+
// Header
|
|
114
|
+
console.log(`\n${C.purple}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${C.reset}`);
|
|
115
|
+
console.log(`${C.cyan}${C.bold}JOS RUN${C.reset} // ${C.gray}JOSFOXAI MAGIC Runtime${C.reset}`);
|
|
116
|
+
console.log(`${C.purple}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${C.reset}\n`);
|
|
117
|
+
|
|
118
|
+
// Mode indicator
|
|
119
|
+
if (dryRun) {
|
|
120
|
+
console.log(`${C.yellow}${C.bold}⚡ DRY RUN MODE${C.reset} ${C.gray}— No commands will be executed${C.reset}\n`);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Artifact info
|
|
124
|
+
console.log(`${C.cyan}📦 Artifact:${C.reset} ${artifact.meta?.name || path.basename(artifactPath)}`);
|
|
125
|
+
console.log(`${C.cyan}📄 File:${C.reset} ${path.basename(artifactPath)}`);
|
|
126
|
+
console.log(`${C.cyan}🆔 ID:${C.reset} ${artifact.id_jos || 'N/A'}`);
|
|
127
|
+
|
|
128
|
+
// Integrity verification
|
|
129
|
+
if (!insecure) {
|
|
130
|
+
const integrity = verifyIntegrity(artifactPath, content, artifact);
|
|
131
|
+
if (!integrity.valid) {
|
|
132
|
+
console.log(`${C.cyan}🔐 Integrity:${C.reset} ${C.red}FAILED - ${integrity.error}${C.reset}`);
|
|
133
|
+
logWitness(home, 'integrity_failed', { error: integrity.error });
|
|
134
|
+
process.exit(1);
|
|
135
|
+
} else if (integrity.verified) {
|
|
136
|
+
console.log(`${C.cyan}🔐 Integrity:${C.reset} ${C.green}✓ Verified${C.reset} ${C.gray}(${integrity.hash.substring(0, 16)}...)${C.reset}`);
|
|
137
|
+
logWitness(home, 'integrity_verified', { hash: integrity.hash });
|
|
138
|
+
} else {
|
|
139
|
+
console.log(`${C.cyan}🔐 Integrity:${C.reset} ${C.yellow}⚠ ${integrity.warning}${C.reset}`);
|
|
140
|
+
}
|
|
141
|
+
} else {
|
|
142
|
+
console.log(`${C.cyan}🔐 Integrity:${C.reset} ${C.yellow}⚠ Skipped (--insecure)${C.reset}`);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// MAGIC validation
|
|
146
|
+
const hasMagic = artifact.intention && artifact.guardrails && artifact.capabilities;
|
|
147
|
+
console.log(`${C.cyan}✨ MAGIC:${C.reset} ${hasMagic ? C.green + '✓ Valid' : C.yellow + '⚠ Partial'}${C.reset}`);
|
|
148
|
+
|
|
149
|
+
// Intention
|
|
150
|
+
if (artifact.intention?.objective) {
|
|
151
|
+
console.log(`${C.cyan}🎯 Intention:${C.reset} ${artifact.intention.objective}`);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Guardrails
|
|
155
|
+
if (artifact.guardrails?.avoid?.length > 0) {
|
|
156
|
+
console.log(`${C.cyan}🛡️ Guardrails:${C.reset} ${artifact.guardrails.avoid.join(', ')}`);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Flow selection
|
|
160
|
+
const flowName = args.includes('--flow') ? args[args.indexOf('--flow') + 1] : 'main';
|
|
161
|
+
const flow = artifact.orchestration?.flows?.[flowName] ||
|
|
162
|
+
artifact.orchestration?.pipelines?.[flowName];
|
|
163
|
+
|
|
164
|
+
if (!flow) {
|
|
165
|
+
console.log(`\n${C.red}✖ Flow '${flowName}' not found.${C.reset}`);
|
|
166
|
+
const available = [
|
|
167
|
+
...Object.keys(artifact.orchestration?.flows || {}),
|
|
168
|
+
...Object.keys(artifact.orchestration?.pipelines || {})
|
|
169
|
+
];
|
|
170
|
+
if (available.length > 0) {
|
|
171
|
+
console.log(`${C.gray}Available flows: ${available.join(', ')}${C.reset}`);
|
|
172
|
+
}
|
|
173
|
+
process.exit(1);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Execution plan
|
|
177
|
+
console.log(`\n${C.cyan}▶ Flow:${C.reset} ${C.bold}${flowName}${C.reset}`);
|
|
178
|
+
if (flow.description) {
|
|
179
|
+
console.log(`${C.gray} ${flow.description}${C.reset}`);
|
|
180
|
+
}
|
|
181
|
+
console.log(`${C.gray} Steps: ${flow.steps?.join(' → ') || 'none'}${C.reset}\n`);
|
|
182
|
+
|
|
183
|
+
// Execute steps
|
|
184
|
+
let stepIndex = 0;
|
|
185
|
+
for (const stepName of flow.steps || []) {
|
|
186
|
+
stepIndex++;
|
|
187
|
+
const def = artifact.orchestration.definitions?.[stepName];
|
|
188
|
+
|
|
189
|
+
if (!def) {
|
|
190
|
+
console.log(`${C.red} [${stepIndex}] ✖ ${stepName}: Definition not found${C.reset}`);
|
|
191
|
+
logWitness(home, 'step_error', { step: stepName, error: 'definition not found' });
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
logWitness(home, 'step_start', { step: stepName, type: def.type, index: stepIndex });
|
|
196
|
+
|
|
197
|
+
const typeIcon = def.type === 'shell' ? '⚡' : def.type === 'jos' ? '📦' : '●';
|
|
198
|
+
|
|
199
|
+
if (dryRun) {
|
|
200
|
+
console.log(`${C.yellow} [${stepIndex}] ${typeIcon} ${stepName}${C.reset}`);
|
|
201
|
+
if (def.description) console.log(`${C.gray} ${def.description}${C.reset}`);
|
|
202
|
+
if (def.type === 'shell') {
|
|
203
|
+
const cmdPreview = def.command.length > 60 ? def.command.substring(0, 60) + '...' : def.command;
|
|
204
|
+
console.log(`${C.dim} $ ${cmdPreview}${C.reset}`);
|
|
205
|
+
} else if (def.type === 'jos') {
|
|
206
|
+
console.log(`${C.dim} → ${def.artifact}${C.reset}`);
|
|
207
|
+
}
|
|
208
|
+
logWitness(home, 'step_dry_run', { step: stepName });
|
|
209
|
+
continue;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// Real execution
|
|
213
|
+
console.log(`${C.blue} [${stepIndex}] ${typeIcon} ${stepName}...${C.reset}`);
|
|
214
|
+
|
|
215
|
+
try {
|
|
216
|
+
if (def.type === 'shell') {
|
|
217
|
+
execSync(def.command, { stdio: 'inherit' });
|
|
218
|
+
console.log(`${C.green} ✓ Complete${C.reset}`);
|
|
219
|
+
} else if (def.type === 'jos') {
|
|
220
|
+
console.log(`${C.purple} Running sub-artifact: ${def.artifact}${C.reset}`);
|
|
221
|
+
const subPath = path.resolve(path.dirname(artifactPath), def.artifact);
|
|
222
|
+
const binJos = process.argv[1];
|
|
223
|
+
execSync(`${process.execPath} "${binJos}" run "${subPath}" ${insecure ? '--insecure' : ''} --flow main`, {
|
|
224
|
+
stdio: 'inherit'
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
logWitness(home, 'step_complete', { step: stepName, success: true });
|
|
228
|
+
} catch (e) {
|
|
229
|
+
console.log(`${C.red} ✖ Failed: ${e.message}${C.reset}`);
|
|
230
|
+
logWitness(home, 'step_failed', { step: stepName, error: e.message });
|
|
231
|
+
logWitness(home, 'run_failed', { lastStep: stepName });
|
|
232
|
+
process.exit(1);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// Success
|
|
237
|
+
console.log(`\n${C.green}${C.bold}✓ ${dryRun ? 'Dry run complete' : 'Execution complete'}${C.reset}`);
|
|
238
|
+
if (artifact.intention?.success_criteria) {
|
|
239
|
+
console.log(`${C.gray} Success criteria: ${artifact.intention.success_criteria}${C.reset}`);
|
|
240
|
+
}
|
|
241
|
+
console.log('');
|
|
242
|
+
|
|
243
|
+
logWitness(home, 'success', { dryRun: dryRun, stepsExecuted: stepIndex });
|
|
244
|
+
};
|