@matt82198/aesop 0.1.0 → 0.3.1
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/CHANGELOG.md +117 -2
- package/README.md +59 -218
- package/bin/cli.js +168 -41
- package/daemons/run-watchdog.sh +16 -4
- package/daemons/selfheal.sh +231 -0
- package/docs/ANY-REPO.md +427 -0
- package/docs/CONTRIBUTING.md +72 -0
- package/docs/DEMO.md +334 -0
- package/docs/HOOK-INSTALL.md +15 -56
- package/docs/INSTALL.md +74 -4
- package/docs/PORTING.md +166 -0
- package/docs/README.md +33 -3
- package/docs/TEAM-STATE.md +372 -0
- package/docs/reproduce.md +33 -3
- package/driver/CLAUDE.md +150 -0
- package/driver/README.md +383 -0
- package/driver/aesop.config.example.json +80 -0
- package/driver/agent_driver.py +355 -0
- package/driver/backend_config.py +253 -0
- package/driver/claude_code_driver.py +198 -0
- package/driver/codex_driver.py +673 -0
- package/driver/openai_compatible_driver.py +249 -0
- package/driver/openai_transport.py +179 -0
- package/driver/verification_policy.py +75 -0
- package/driver/wave_bridge.py +254 -0
- package/driver/wave_loop.py +1408 -0
- package/driver/wave_scheduler.py +890 -0
- package/hooks/pre-push-policy.sh +131 -33
- package/mcp/server.mjs +320 -4
- package/monitor/collect-signals.mjs +69 -0
- package/package.json +22 -14
- package/skills/CLAUDE.md +132 -2
- package/skills/buildsystem/SKILL.md +330 -0
- package/skills/buildsystem/wave-flat-dispatch.template.mjs +658 -0
- package/skills/fleet/SKILL.md +113 -0
- package/skills/power/SKILL.md +246 -131
- package/state_store/__init__.py +4 -2
- package/state_store/api.py +19 -4
- package/state_store/coordination.py +209 -0
- package/state_store/identity.py +51 -0
- package/state_store/projections.py +63 -0
- package/state_store/read_api.py +156 -0
- package/state_store/store.py +185 -73
- package/state_store/write_api.py +462 -0
- package/templates/wave-presets/data.json +65 -0
- package/templates/wave-presets/library.json +65 -0
- package/templates/wave-presets/saas.json +64 -0
- package/tools/audit_report.py +388 -0
- package/tools/bench_runner.py +100 -3
- package/tools/ci_merge_wait.py +256 -35
- package/tools/ci_workflow_lint.py +430 -0
- package/tools/claudemd_drift.py +394 -0
- package/tools/claudemd_lint.py +359 -0
- package/tools/common.py +39 -3
- package/tools/cost_ceiling.py +166 -43
- package/tools/cost_econ.py +480 -0
- package/tools/cost_projection.py +559 -0
- package/tools/crossos_drift.py +394 -0
- package/tools/defect_escape.py +252 -0
- package/tools/doctor.js +1 -1
- package/tools/eod_sweep.py +188 -26
- package/tools/fleet.js +260 -0
- package/tools/fleet_ledger.py +209 -7
- package/tools/git_identity_check.py +315 -0
- package/tools/health-score.js +40 -0
- package/tools/health_score.py +361 -0
- package/tools/metrics_gate.py +13 -4
- package/tools/mutation_test.py +523 -0
- package/tools/portability_check.py +206 -0
- package/tools/proposals.mjs +47 -2
- package/tools/reconcile.py +7 -4
- package/tools/reproduce.js +405 -0
- package/tools/secret_scan.py +207 -65
- package/tools/self_stats.py +20 -0
- package/tools/stall_check.py +247 -16
- package/tools/stateapi_lint.py +325 -0
- package/tools/test_battery.py +173 -0
- package/tools/transcript_digest.py +380 -0
- package/tools/verify_activity_filter.py +437 -0
- package/tools/verify_agent_inspector.py +2 -0
- package/tools/verify_cost_panel.py +345 -0
- package/tools/verify_dash.py +2 -0
- package/tools/verify_dispatch_panel.py +301 -0
- package/tools/verify_failure_drilldown.py +188 -0
- package/tools/verify_prboard.py +2 -0
- package/tools/verify_scorecards.py +281 -0
- package/tools/verify_submit_encoding.py +2 -0
- package/tools/verify_ui_trio.py +409 -0
- package/tools/verify_wave_telemetry.py +268 -0
- package/tools/wave_backlog_analyzer.py +490 -0
- package/tools/wave_ledger_hook.py +150 -0
- package/tools/wave_preflight.py +779 -0
- package/tools/wave_resume.py +215 -0
- package/tools/wave_templates.py +340 -0
- package/ui/agents.py +68 -14
- package/ui/collectors.py +81 -55
- package/ui/config.py +7 -2
- package/ui/cost.py +231 -12
- package/ui/handler.py +383 -55
- package/ui/quality_scorecard.py +232 -0
- package/ui/sse.py +3 -3
- package/ui/wave_audit_tail.py +213 -0
- package/ui/wave_dispatch.py +280 -0
- package/ui/wave_failure.py +288 -0
- package/ui/wave_gantt.py +152 -0
- package/ui/wave_reasoning_tail.py +176 -0
- package/ui/wave_telemetry.py +383 -0
- package/ui/web/dist/assets/index-CNQxaiOW.css +1 -0
- package/ui/web/dist/assets/index-CP68RIh3.js +9 -0
- package/ui/web/dist/index.html +2 -2
- package/bin/CLAUDE.md +0 -76
- package/daemons/CLAUDE.md +0 -36
- package/dash/CLAUDE.md +0 -32
- package/docs/archive/README.md +0 -3
- package/docs/archive/spikes/tiered-cognition/ACTIVATION.md +0 -125
- package/docs/archive/spikes/tiered-cognition/DESIGN.md +0 -287
- package/docs/archive/spikes/tiered-cognition/FINDINGS.md +0 -113
- package/docs/archive/spikes/tiered-cognition/README.md +0 -27
- package/docs/archive/spikes/tiered-cognition/aesop-cognition.example.md +0 -32
- package/docs/archive/spikes/tiered-cognition/force-model-policy.merged.mjs +0 -673
- package/docs/archive/spikes/tiered-cognition/strip-tools-hook.mjs +0 -434
- package/hooks/CLAUDE.md +0 -89
- package/mcp/CLAUDE.md +0 -213
- package/monitor/CLAUDE.md +0 -40
- package/scan/CLAUDE.md +0 -30
- package/state_store/CLAUDE.md +0 -39
- package/tools/CLAUDE.md +0 -79
- package/ui/CLAUDE.md +0 -127
- package/ui/web/dist/assets/index-0qQYnvMC.js +0 -9
- package/ui/web/dist/assets/index-BdIlFieV.css +0 -1
|
@@ -0,0 +1,405 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Aesop reproduce — offline verification suite
|
|
5
|
+
*
|
|
6
|
+
* Mirrors .github/workflows/reproduce.yml for local execution.
|
|
7
|
+
*
|
|
8
|
+
* Modes:
|
|
9
|
+
* REPO: Full test suites (Node.js, Python, Shell, React, benchmarks)
|
|
10
|
+
* INSTALLED: Shipped self-checks (doctor, health-score, secret-scan selftest, packaging)
|
|
11
|
+
*
|
|
12
|
+
* Exit: 0 = all checks pass, 1 = any check failed
|
|
13
|
+
* Output: ASCII table with per-step timing
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
const fs = require('fs');
|
|
17
|
+
const path = require('path');
|
|
18
|
+
const { execSync, spawnSync } = require('child_process');
|
|
19
|
+
|
|
20
|
+
const CURRENT_DIR = process.cwd();
|
|
21
|
+
const PACKAGE_ROOT = path.join(__dirname, '..');
|
|
22
|
+
|
|
23
|
+
// ANSI colors
|
|
24
|
+
const COLORS = {
|
|
25
|
+
GREEN: '\x1b[32m',
|
|
26
|
+
RED: '\x1b[31m',
|
|
27
|
+
YELLOW: '\x1b[33m',
|
|
28
|
+
RESET: '\x1b[0m',
|
|
29
|
+
BOLD: '\x1b[1m',
|
|
30
|
+
DIM: '\x1b[2m'
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
function colorPass() {
|
|
34
|
+
return `${COLORS.GREEN}PASS${COLORS.RESET}`;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function colorFail() {
|
|
38
|
+
return `${COLORS.RED}FAIL${COLORS.RESET}`;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function colorSkip() {
|
|
42
|
+
return `${COLORS.YELLOW}SKIP${COLORS.RESET}`;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Detect context: repo checkout vs installed package
|
|
46
|
+
function detectContext() {
|
|
47
|
+
// Repo checkout has .git/config and package.json with npm scripts
|
|
48
|
+
const hasGitConfig = fs.existsSync(path.join(PACKAGE_ROOT, '.git', 'config'));
|
|
49
|
+
const hasPackageJson = fs.existsSync(path.join(PACKAGE_ROOT, 'package.json'));
|
|
50
|
+
const hasTestScripts = hasPackageJson && (() => {
|
|
51
|
+
try {
|
|
52
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(PACKAGE_ROOT, 'package.json'), 'utf8'));
|
|
53
|
+
return pkg.scripts && pkg.scripts['test:node'] && pkg.scripts['test:py'];
|
|
54
|
+
} catch {
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
})();
|
|
58
|
+
|
|
59
|
+
// Installed package is in node_modules with limited structure
|
|
60
|
+
const isInstalled = !hasGitConfig && !hasTestScripts;
|
|
61
|
+
|
|
62
|
+
return isInstalled ? 'installed' : 'repo';
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Format timing for display
|
|
66
|
+
function formatTiming(ms) {
|
|
67
|
+
if (ms < 1000) {
|
|
68
|
+
return `${ms}ms`;
|
|
69
|
+
}
|
|
70
|
+
const sec = (ms / 1000).toFixed(1);
|
|
71
|
+
return `${sec}s`;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Format a result row
|
|
75
|
+
function formatRow(label, status, timing, hint) {
|
|
76
|
+
const statusStr = status === 'PASS' ? colorPass() : (status === 'FAIL' ? colorFail() : colorSkip());
|
|
77
|
+
const timingStr = timing ? ` [${formatTiming(timing)}]` : '';
|
|
78
|
+
const hintStr = hint ? ` — ${hint}` : '';
|
|
79
|
+
const paddedLabel = label.padEnd(50);
|
|
80
|
+
return ` ${paddedLabel} ${statusStr}${timingStr}${hintStr}`;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Run a subprocess and return pass/fail
|
|
84
|
+
function runSubprocess(label, args, options = {}) {
|
|
85
|
+
const { cwd = PACKAGE_ROOT, stdio = 'inherit', skipIfMissing = null } = options;
|
|
86
|
+
|
|
87
|
+
if (skipIfMissing && !fs.existsSync(skipIfMissing)) {
|
|
88
|
+
return {
|
|
89
|
+
label,
|
|
90
|
+
status: 'SKIP',
|
|
91
|
+
timing: 0,
|
|
92
|
+
passed: true,
|
|
93
|
+
hint: `${path.basename(skipIfMissing)} not found`
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const startTime = Date.now();
|
|
98
|
+
try {
|
|
99
|
+
const result = spawnSync(args[0], args.slice(1), {
|
|
100
|
+
stdio,
|
|
101
|
+
cwd,
|
|
102
|
+
encoding: 'utf8'
|
|
103
|
+
});
|
|
104
|
+
const timing = Date.now() - startTime;
|
|
105
|
+
|
|
106
|
+
if (result.status === 0 || result.status === null) {
|
|
107
|
+
return { label, status: 'PASS', timing, passed: true };
|
|
108
|
+
} else {
|
|
109
|
+
let hint;
|
|
110
|
+
if (stdio === 'pipe' && result.stderr) {
|
|
111
|
+
hint = result.stderr.split('\n')[0].slice(0, 80);
|
|
112
|
+
} else if (stdio === 'pipe' && result.stdout) {
|
|
113
|
+
hint = result.stdout.split('\n')[0].slice(0, 80);
|
|
114
|
+
}
|
|
115
|
+
return { label, status: 'FAIL', timing, passed: false, hint };
|
|
116
|
+
}
|
|
117
|
+
} catch (e) {
|
|
118
|
+
const timing = Date.now() - startTime;
|
|
119
|
+
return { label, status: 'FAIL', timing, passed: false, hint: e.message.slice(0, 80) };
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Repo mode: full test suite
|
|
124
|
+
function runRepoMode() {
|
|
125
|
+
console.log(`\n${COLORS.BOLD}Running Full Test Suite (Repo Mode)${COLORS.RESET}\n`);
|
|
126
|
+
|
|
127
|
+
const results = [];
|
|
128
|
+
|
|
129
|
+
// Step 1: Node syntax check
|
|
130
|
+
results.push(runSubprocess(
|
|
131
|
+
'Node syntax check (*.mjs excluding .template.mjs)',
|
|
132
|
+
['bash', '-c', 'git ls-files "*.mjs" | grep -v ".template.mjs$" | while read f; do [ -n "$f" ] && node --check "$f" || true; done'],
|
|
133
|
+
{ stdio: 'pipe' }
|
|
134
|
+
));
|
|
135
|
+
|
|
136
|
+
// Step 2: Shell syntax check
|
|
137
|
+
results.push(runSubprocess(
|
|
138
|
+
'Shell syntax check (*.sh)',
|
|
139
|
+
['bash', '-c', 'git ls-files "*.sh" | while read f; do [ -n "$f" ] && bash -n "$f" || true; done'],
|
|
140
|
+
{ stdio: 'pipe' }
|
|
141
|
+
));
|
|
142
|
+
|
|
143
|
+
// Step 3: Node.js tests
|
|
144
|
+
results.push(runSubprocess(
|
|
145
|
+
'Node.js tests (npm run test:node)',
|
|
146
|
+
['npm', 'run', 'test:node'],
|
|
147
|
+
{ stdio: 'inherit' }
|
|
148
|
+
));
|
|
149
|
+
|
|
150
|
+
// Step 4: Shell test suites
|
|
151
|
+
results.push(runSubprocess(
|
|
152
|
+
'Shell test suites (npm run test:sh)',
|
|
153
|
+
['npm', 'run', 'test:sh'],
|
|
154
|
+
{ stdio: 'inherit' }
|
|
155
|
+
));
|
|
156
|
+
|
|
157
|
+
// Step 5: React component tests (vitest)
|
|
158
|
+
const uiWebDir = path.join(PACKAGE_ROOT, 'ui', 'web');
|
|
159
|
+
if (fs.existsSync(uiWebDir)) {
|
|
160
|
+
results.push(runSubprocess(
|
|
161
|
+
'React component tests (vitest)',
|
|
162
|
+
['bash', '-c', `cd ${JSON.stringify(uiWebDir)} && npm ci && npx vitest run`],
|
|
163
|
+
{ stdio: 'inherit' }
|
|
164
|
+
));
|
|
165
|
+
} else {
|
|
166
|
+
results.push({
|
|
167
|
+
label: 'React component tests (vitest)',
|
|
168
|
+
status: 'SKIP',
|
|
169
|
+
timing: 0,
|
|
170
|
+
passed: true,
|
|
171
|
+
hint: 'ui/web not found'
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Step 6: Python tool compile check
|
|
176
|
+
results.push(runSubprocess(
|
|
177
|
+
'Python tool import/compile smoke gate',
|
|
178
|
+
['bash', '-c', 'python -m compileall -q tools/ && python -m unittest tests.test_tools_importable -v'],
|
|
179
|
+
{ stdio: 'pipe' }
|
|
180
|
+
));
|
|
181
|
+
|
|
182
|
+
// Step 7: Python tests
|
|
183
|
+
results.push(runSubprocess(
|
|
184
|
+
'Python tests (unittest discover)',
|
|
185
|
+
['bash', '-c', 'python -m unittest discover -s tests -p "test_*.py" -v'],
|
|
186
|
+
{ stdio: 'inherit' }
|
|
187
|
+
));
|
|
188
|
+
|
|
189
|
+
// Step 8: Benchmark scorer tests
|
|
190
|
+
results.push(runSubprocess(
|
|
191
|
+
'Benchmark scorer tests (test_bench_runner)',
|
|
192
|
+
['python', '-m', 'unittest', 'tests.test_bench_runner', '-v'],
|
|
193
|
+
{ stdio: 'pipe' }
|
|
194
|
+
));
|
|
195
|
+
|
|
196
|
+
// Step 9: Benchmark reproduction
|
|
197
|
+
results.push(runSubprocess(
|
|
198
|
+
'Offline benchmark reproduction',
|
|
199
|
+
['python', 'tools/bench_runner.py', '--runner', 'mock'],
|
|
200
|
+
{ stdio: 'pipe' }
|
|
201
|
+
));
|
|
202
|
+
|
|
203
|
+
return results;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// Classify doctor failures: expected pre-init findings vs real failures
|
|
207
|
+
// Expected on fresh systems: missing config, missing hooks, missing dirs (if tarball unpack incomplete)
|
|
208
|
+
// Real failures: Node version < 18, Python missing, not in git repo
|
|
209
|
+
function classifyDoctorFailure(output) {
|
|
210
|
+
const lines = output.split('\n');
|
|
211
|
+
const failures = [];
|
|
212
|
+
// Expected pre-init directory names from doctor.js checkDirectories()
|
|
213
|
+
const expectedDirs = ['daemons', 'dash', 'monitor', 'tools', 'ui'];
|
|
214
|
+
|
|
215
|
+
for (const line of lines) {
|
|
216
|
+
if (line.includes('✗') || line.includes('FAIL')) {
|
|
217
|
+
failures.push(line);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// Check if all failures match expected pre-init patterns
|
|
222
|
+
const allExpected = failures.every(failure => {
|
|
223
|
+
// Pattern 1: Missing config file
|
|
224
|
+
if (failure.includes('aesop.config.json not found')) {
|
|
225
|
+
return true;
|
|
226
|
+
}
|
|
227
|
+
// Pattern 2: Pre-push hook not installed
|
|
228
|
+
if (failure.includes('Pre-push hook not installed')) {
|
|
229
|
+
return true;
|
|
230
|
+
}
|
|
231
|
+
// Pattern 3: Missing directories — verify line contains only expected directory names
|
|
232
|
+
if (failure.includes('Missing:')) {
|
|
233
|
+
// Extract the part after "Missing:"
|
|
234
|
+
const afterMissing = failure.substring(failure.indexOf('Missing:') + 8);
|
|
235
|
+
// Check if all mentioned items are valid directory names
|
|
236
|
+
const items = afterMissing.split(',').map(item => item.trim());
|
|
237
|
+
return items.every(item => expectedDirs.includes(item));
|
|
238
|
+
}
|
|
239
|
+
return false;
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
return { allExpected, failures };
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// Installed mode: shipped self-checks
|
|
246
|
+
function runInstalledMode() {
|
|
247
|
+
console.log(`\n${COLORS.BOLD}Running Shipped Self-Checks (Installed Mode)${COLORS.RESET}\n`);
|
|
248
|
+
|
|
249
|
+
const results = [];
|
|
250
|
+
|
|
251
|
+
// Step 1: Doctor check — distinguish expected pre-init findings from real failures
|
|
252
|
+
const doctorJs = path.join(PACKAGE_ROOT, 'tools', 'doctor.js');
|
|
253
|
+
const doctorResult = (() => {
|
|
254
|
+
if (!fs.existsSync(doctorJs)) {
|
|
255
|
+
return {
|
|
256
|
+
label: 'Preflight checks (aesop doctor)',
|
|
257
|
+
status: 'SKIP',
|
|
258
|
+
timing: 0,
|
|
259
|
+
passed: true,
|
|
260
|
+
hint: 'doctor.js not found'
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
const startTime = Date.now();
|
|
265
|
+
try {
|
|
266
|
+
const result = spawnSync('node', [doctorJs], {
|
|
267
|
+
stdio: 'pipe',
|
|
268
|
+
encoding: 'utf8'
|
|
269
|
+
});
|
|
270
|
+
const timing = Date.now() - startTime;
|
|
271
|
+
|
|
272
|
+
if (result.status === 0) {
|
|
273
|
+
return { label: 'Preflight checks (aesop doctor)', status: 'PASS', timing, passed: true };
|
|
274
|
+
} else {
|
|
275
|
+
// Doctor failed; classify whether it's expected pre-init findings or real failure
|
|
276
|
+
const output = result.stdout || result.stderr || '';
|
|
277
|
+
const { allExpected } = classifyDoctorFailure(output);
|
|
278
|
+
|
|
279
|
+
if (allExpected) {
|
|
280
|
+
// Expected pre-init findings (missing config, hooks, etc.) — pass but note it
|
|
281
|
+
return {
|
|
282
|
+
label: 'Preflight checks (aesop doctor)',
|
|
283
|
+
status: 'PASS',
|
|
284
|
+
timing,
|
|
285
|
+
passed: true,
|
|
286
|
+
hint: 'Expected pre-init findings (run `aesop doctor` to initialize)'
|
|
287
|
+
};
|
|
288
|
+
} else {
|
|
289
|
+
// Real failure (e.g., Node/Python missing, not in git repo)
|
|
290
|
+
const hint = result.stderr ? result.stderr.split('\n')[0].slice(0, 80) : 'doctor check failed';
|
|
291
|
+
return { label: 'Preflight checks (aesop doctor)', status: 'FAIL', timing, passed: false, hint };
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
} catch (e) {
|
|
295
|
+
const timing = Date.now() - startTime;
|
|
296
|
+
return {
|
|
297
|
+
label: 'Preflight checks (aesop doctor)',
|
|
298
|
+
status: 'FAIL',
|
|
299
|
+
timing,
|
|
300
|
+
passed: false,
|
|
301
|
+
hint: e.message.slice(0, 80)
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
})();
|
|
305
|
+
results.push(doctorResult);
|
|
306
|
+
|
|
307
|
+
// Step 2: Health score check
|
|
308
|
+
const healthScoreJs = path.join(PACKAGE_ROOT, 'tools', 'health-score.js');
|
|
309
|
+
results.push(runSubprocess(
|
|
310
|
+
'Health score check (aesop health-score)',
|
|
311
|
+
['node', healthScoreJs],
|
|
312
|
+
{ stdio: 'pipe', skipIfMissing: healthScoreJs }
|
|
313
|
+
));
|
|
314
|
+
|
|
315
|
+
// Step 3: Secret-scan selftest
|
|
316
|
+
const scannerSelftest = path.join(PACKAGE_ROOT, 'tools', 'scanner_selftest.py');
|
|
317
|
+
results.push(runSubprocess(
|
|
318
|
+
'Secret-scan selftest',
|
|
319
|
+
['python', scannerSelftest],
|
|
320
|
+
{ stdio: 'pipe', skipIfMissing: scannerSelftest }
|
|
321
|
+
));
|
|
322
|
+
|
|
323
|
+
// Step 4: Packaging assertions (check required files are shipped)
|
|
324
|
+
const startTime = Date.now();
|
|
325
|
+
let packagingPassed = true;
|
|
326
|
+
let packagingHint;
|
|
327
|
+
try {
|
|
328
|
+
const requiredDirs = ['tools', 'daemons', 'dash', 'monitor', 'ui', 'docs'];
|
|
329
|
+
const requiredFiles = ['aesop.config.example.json', 'README.md', 'LICENSE'];
|
|
330
|
+
|
|
331
|
+
const missing = [];
|
|
332
|
+
for (const dir of requiredDirs) {
|
|
333
|
+
const dirPath = path.join(PACKAGE_ROOT, dir);
|
|
334
|
+
if (!fs.existsSync(dirPath) || !fs.statSync(dirPath).isDirectory()) {
|
|
335
|
+
missing.push(dir);
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
for (const file of requiredFiles) {
|
|
340
|
+
const filePath = path.join(PACKAGE_ROOT, file);
|
|
341
|
+
if (!fs.existsSync(filePath)) {
|
|
342
|
+
missing.push(file);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
if (missing.length > 0) {
|
|
347
|
+
packagingPassed = false;
|
|
348
|
+
packagingHint = `Missing: ${missing.join(', ')}`;
|
|
349
|
+
}
|
|
350
|
+
} catch (e) {
|
|
351
|
+
packagingPassed = false;
|
|
352
|
+
packagingHint = e.message.slice(0, 80);
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
const packagingTiming = Date.now() - startTime;
|
|
356
|
+
results.push({
|
|
357
|
+
label: 'Packaging assertions',
|
|
358
|
+
status: packagingPassed ? 'PASS' : 'FAIL',
|
|
359
|
+
timing: packagingTiming,
|
|
360
|
+
passed: packagingPassed,
|
|
361
|
+
hint: packagingHint
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
return results;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
// Main execution
|
|
368
|
+
(async function main() {
|
|
369
|
+
try {
|
|
370
|
+
const context = detectContext();
|
|
371
|
+
console.log(`${COLORS.DIM}Context: ${context}${COLORS.RESET}`);
|
|
372
|
+
|
|
373
|
+
let results;
|
|
374
|
+
if (context === 'repo') {
|
|
375
|
+
results = runRepoMode();
|
|
376
|
+
} else {
|
|
377
|
+
results = runInstalledMode();
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
// Print results table
|
|
381
|
+
console.log(`\n${COLORS.BOLD}Results${COLORS.RESET}\n`);
|
|
382
|
+
for (const result of results) {
|
|
383
|
+
console.log(formatRow(result.label, result.status, result.timing, result.hint));
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
// Summary
|
|
387
|
+
const passCount = results.filter(r => r.passed).length;
|
|
388
|
+
const failCount = results.filter(r => !r.passed).length;
|
|
389
|
+
const totalTime = results.reduce((sum, r) => sum + (r.timing || 0), 0);
|
|
390
|
+
|
|
391
|
+
console.log(`\n${COLORS.BOLD}Summary: ${passCount}/${results.length} checks passed${COLORS.RESET}`);
|
|
392
|
+
console.log(`${COLORS.DIM}Total time: ${formatTiming(totalTime)}${COLORS.RESET}\n`);
|
|
393
|
+
|
|
394
|
+
if (failCount === 0) {
|
|
395
|
+
console.log(`${COLORS.GREEN}✓ All checks passed${COLORS.RESET}\n`);
|
|
396
|
+
process.exitCode = 0;
|
|
397
|
+
} else {
|
|
398
|
+
console.log(`${COLORS.RED}✗ ${failCount} check(s) failed${COLORS.RESET}\n`);
|
|
399
|
+
process.exitCode = 1;
|
|
400
|
+
}
|
|
401
|
+
} catch (err) {
|
|
402
|
+
console.error(`${COLORS.RED}Error: ${err.message}${COLORS.RESET}`);
|
|
403
|
+
process.exit(1);
|
|
404
|
+
}
|
|
405
|
+
})();
|