@hybridlabor-api/aos 4.7.0 → 4.7.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.
Files changed (34) hide show
  1. package/.agents/agents.md +8 -3
  2. package/.agents/nodes.json +2 -1
  3. package/.agents/state.schema.json +24 -0
  4. package/.agents/vendor-manifest.json +6 -0
  5. package/.agents/workflows/startcycle-graph.md +2 -2
  6. package/.claude/agents/architect.md +5 -4
  7. package/.claude/agents/techlead.md +2 -0
  8. package/.claude/workflows/startcycle-dispatch.mjs +175 -17
  9. package/.opencode/agents/architect.md +5 -4
  10. package/.opencode/agents/techlead.md +2 -0
  11. package/THIRD_PARTY_NOTICES.md +9 -1
  12. package/bin/aos-doctor.mjs +366 -0
  13. package/bin/aos-store.mjs +167 -0
  14. package/docs/AUDIT_BRIEF_ECC_STORE.md +122 -0
  15. package/docs/PLAN_AOS_STORE_PHASE1.md +190 -0
  16. package/installer.js +41 -1
  17. package/lib/aos-archify-contract.mjs +277 -0
  18. package/lib/ecc-store-index.json +1 -0
  19. package/mcp_config.json +4 -0
  20. package/mcps/mcsc/packages/core/src/adapters/codex.js +160 -37
  21. package/package.json +6 -2
  22. package/scripts/build-ecc-store-index.mjs +147 -0
  23. package/skills/basic/startcycle-graph/SKILL.md +13 -0
  24. package/skills/global_config/agenttrail/bin/agenttrail.mjs +153 -42
  25. package/skills/global_config/agenttrail/public/index.html +5 -4
  26. package/skills/global_config/archify/examples/dataflow-product-analytics.html +15048 -0
  27. package/skills/global_config/archify/examples/lifecycle-agent-run.html +14983 -0
  28. package/skills/global_config/archify/examples/sequence-cache-miss-request.html +15063 -0
  29. package/skills/global_config/archify/examples/web-app-rendered.html +15012 -0
  30. package/skills/global_config/archify/examples/workflow-agent-tool-call-rendered.html +15054 -0
  31. package/skills/global_config/ask-tim/SKILL.md +10 -0
  32. package/skills/global_config/mcsc/SKILL.md +60 -0
  33. package/skills/global_config/plan-canvas/scripts/lib/plan-canvas/server.js +31 -6
  34. package/skills/global_config/plan-canvas/scripts/plan-canvas.js +4 -2
@@ -0,0 +1,366 @@
1
+ #!/usr/bin/env node
2
+ // AOS System Checkup & Doctor: Verifies system dependencies, file placement,
3
+ // cross-platform harness synchronization, daemons and hooks across macOS and Windows.
4
+ // Usage:
5
+ // aos doctor
6
+ // node bin/aos-doctor.mjs [--json] [--net]
7
+
8
+ import { existsSync, readFileSync, readdirSync, statSync } from 'node:fs';
9
+ import { execFileSync, execSync } from 'node:child_process';
10
+ import { connect } from 'node:net';
11
+ import os from 'node:os';
12
+ import path from 'node:path';
13
+
14
+ const HOME = os.homedir();
15
+ const JSON_OUT = process.argv.includes('--json');
16
+ const NET = process.argv.includes('--net');
17
+ const IS_MAC = process.platform === 'darwin';
18
+ const IS_WIN = process.platform === 'win32';
19
+ const IS_ARM64 = process.arch === 'arm64';
20
+
21
+ const h = (...p) => path.join(HOME, ...p);
22
+ const tilde = (p) => (p || '').replace(HOME, '~');
23
+ const readJson = (p) => { try { return JSON.parse(readFileSync(p, 'utf8')); } catch { return null; } };
24
+
25
+ const firstExisting = (candidates) => candidates.find((c) => existsSync(c)) || null;
26
+
27
+ const MODULE_BASES = [
28
+ h('.agents'),
29
+ h('.claude'),
30
+ h('dev', 'bdb-dev'),
31
+ ...(process.env.npm_config_prefix ? [path.join(process.env.npm_config_prefix, 'lib', 'node_modules')] : []),
32
+ '/usr/local/lib/node_modules',
33
+ '/opt/homebrew/lib/node_modules',
34
+ ];
35
+ const findModule = (name) => firstExisting(MODULE_BASES.map((b) => path.join(b, name)));
36
+
37
+ const MCP_DIRS = [
38
+ h('.gemini', 'config', 'mcps'),
39
+ h('Library', 'Application Support', 'Claude', 'mcps'),
40
+ ...(process.env.APPDATA ? [path.join(process.env.APPDATA, 'Claude', 'mcps')] : []),
41
+ h('.cursor', 'mcps'),
42
+ h('.codex', 'mcps'),
43
+ h('.windsurf', 'mcps'),
44
+ ];
45
+
46
+ const results = [];
47
+ const add = (area, name, ok, detail, fix, warningOnly = false) => {
48
+ results.push({ area, name, ok, detail, fix, warningOnly });
49
+ };
50
+
51
+ const which = (bin) => {
52
+ const probe = IS_WIN ? 'where' : 'which';
53
+ try {
54
+ return tilde(execFileSync(probe, [bin], { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] }).trim().split(/\r?\n/)[0]);
55
+ } catch {
56
+ return null;
57
+ }
58
+ };
59
+
60
+ const dirCount = (p) => {
61
+ try {
62
+ return readdirSync(p, { withFileTypes: true }).filter(d => d.isDirectory()).length;
63
+ } catch {
64
+ return 0;
65
+ }
66
+ };
67
+
68
+ function portOpen(port, timeout = 1200) {
69
+ return new Promise((resolve) => {
70
+ const s = connect({ host: '127.0.0.1', port });
71
+ const done = (v) => { s.destroy(); resolve(v); };
72
+ s.setTimeout(timeout);
73
+ s.once('connect', () => done(true));
74
+ s.once('timeout', () => done(false));
75
+ s.once('error', () => done(false));
76
+ });
77
+ }
78
+
79
+ // ---------------------------------------------------------------- 1. System Prereqs
80
+ function checkPrereqs() {
81
+ const nodeMajor = Number(process.versions.node.split('.')[0]);
82
+ add('prereq', 'Node.js runtime', nodeMajor >= 20, `v${process.versions.node} (${nodeMajor >= 22 ? 'optimal for OpenWiki' : '>= 20 required'})`,
83
+ 'Update Node.js to v20 or v22+ via nvm or nodejs.org.');
84
+
85
+ const pyProbe = which('python3') || which('python') || (IS_WIN ? which('py') : null);
86
+ add('prereq', 'Python 3', !!pyProbe, pyProbe || 'missing — needed for memB venv & OpenWiki',
87
+ IS_WIN ? 'Install Python from python.org or winget install Python.Python.3.12' : 'brew install python3');
88
+
89
+ const gitProbe = which('git');
90
+ add('prereq', 'Git CLI', !!gitProbe, gitProbe || 'missing — required for AOS workflows and worktrees',
91
+ IS_WIN ? 'Install Git via git-scm.com or winget install Git.Git' : 'brew install git / xcode-select --install');
92
+
93
+ const uvProbe = which('uv');
94
+ add('prereq', 'uv package manager', !!uvProbe, uvProbe ? `${uvProbe} (fast venv seeding)` : 'optional — pip fallback will be used',
95
+ 'curl -LsSf https://astral.sh/uv/install.sh | sh (or pip install uv)', true);
96
+
97
+ const ghProbe = which('gh');
98
+ add('prereq', 'GitHub CLI (gh)', !!ghProbe, ghProbe ? `${ghProbe}` : 'optional — needed for repo automation & release PRs',
99
+ 'Install GitHub CLI: brew install gh / winget install GitHub.cli', true);
100
+ }
101
+
102
+ // ---------------------------------------------------------------- 2. AOS Core Placement & Store
103
+ function checkAosCore() {
104
+ const manifestPath = h('.agents', '.bdb-manifest.json');
105
+ const manifest = readJson(manifestPath);
106
+ add('aos-core', 'Install Manifest', !!manifest,
107
+ manifest ? `v${manifest.version || '4.x'} · tier ${manifest.tier || 'full'} · modules: ${(manifest.installedModules || []).join(', ') || 'default'}` : `${manifestPath} missing or unreadable`,
108
+ 'Run the AOS installer: npx @hybridlabor-api/aos@latest');
109
+
110
+ // Check store index
111
+ const storeIndexCandidates = [
112
+ path.join(path.dirname(new URL(import.meta.url).pathname), '..', 'lib', 'ecc-store-index.json'),
113
+ h('.agents', 'lib', 'ecc-store-index.json'),
114
+ h('dev', 'bdb-dev', 'bdb-dev-optimized-agent-skills', 'lib', 'ecc-store-index.json')
115
+ ];
116
+ const storeIndexPath = firstExisting(storeIndexCandidates);
117
+ let storeSkillsCount = 0;
118
+ if (storeIndexPath) {
119
+ try {
120
+ const idx = readJson(storeIndexPath);
121
+ storeSkillsCount = (idx?.skills ? Object.keys(idx.skills).length : 0);
122
+ } catch {}
123
+ }
124
+ add('aos-core', 'Offline Store Index', !!storeIndexPath && storeSkillsCount > 0,
125
+ storeIndexPath ? `${tilde(storeIndexPath)} (${storeSkillsCount} catalog skills indexed)` : 'Store index missing',
126
+ 'Run scripts/build-ecc-store-index.mjs or re-run the AOS installer.');
127
+
128
+ // Check MCSC registration
129
+ const mcpConfigCandidates = [
130
+ path.join(path.dirname(new URL(import.meta.url).pathname), '..', 'mcp_config.json'),
131
+ h('.agents', 'mcp_config.json'),
132
+ h('dev', 'bdb-dev', 'bdb-dev-optimized-agent-skills', 'mcp_config.json')
133
+ ];
134
+ const mcpConfigPath = firstExisting(mcpConfigCandidates);
135
+ const mcpConfig = mcpConfigPath ? readJson(mcpConfigPath) : null;
136
+ const hasMcsc = !!mcpConfig?.mcpServers?.mcsc;
137
+ add('aos-core', 'MCSC Telemetry Registration', hasMcsc,
138
+ hasMcsc ? `Registered in ${tilde(mcpConfigPath)}` : 'mcsc missing from mcp_config.json',
139
+ 'Re-run installer to register mcsc cross-harness adapter.');
140
+
141
+ // Retired module check (CDC bug prevention)
142
+ const retired = findModule('bdb-os-agent-workspace');
143
+ if (retired) {
144
+ add('aos-core', 'Retired AO module', false,
145
+ `${tilde(retired)} — archived predecessor with known CDC loop bug`,
146
+ `Remove directory: rm -rf ${tilde(retired)} — AO is now bdb-agent-orchestrator.`);
147
+ }
148
+ }
149
+
150
+ // ---------------------------------------------------------------- 3. Harness Placement & Skills Sync
151
+ function checkHarnesses() {
152
+ const harnesses = [
153
+ { name: 'Claude Code', path: h('.claude', 'skills') },
154
+ { name: 'Gemini / Antigravity', path: firstExisting([h('.gemini', 'config', 'skills'), h('.gemini', 'antigravity-cli', 'skills')]) || h('.gemini', 'config', 'skills') },
155
+ { name: 'Codex', path: h('.codex', 'skills') },
156
+ { name: 'Cursor', path: h('.cursor', 'skills') },
157
+ { name: 'Roo Code', path: h('.roo', 'skills') },
158
+ ];
159
+
160
+ const SENTINEL = 'startcycle';
161
+ for (const hr of harnesses) {
162
+ const exists = existsSync(hr.path);
163
+ const count = dirCount(hr.path);
164
+ const hasSentinel = existsSync(path.join(hr.path, SENTINEL, 'SKILL.md'));
165
+ const ok = exists && count > 0 && hasSentinel;
166
+ add('harnesses', `${hr.name} Skills`, ok,
167
+ ok ? `${tilde(hr.path)} (${count} skills, sentinel verified)` : (exists ? `${tilde(hr.path)} (${count} skills, sentinel missing)` : `${tilde(hr.path)} not synced`),
168
+ `Run 'npx @hybridlabor-api/aos@latest' and select ${hr.name} to sync skills.`, !exists);
169
+ }
170
+
171
+ // OpenCode Plugin check
172
+ const opencodePlugin = firstExisting([
173
+ h('.opencode', 'plugins', 'bdb-aos.js'),
174
+ h('.config', 'opencode', 'plugins', 'bdb-aos.js')
175
+ ]);
176
+ add('harnesses', 'OpenCode Plugin', !!opencodePlugin,
177
+ opencodePlugin ? tilde(opencodePlugin) : 'bdb-aos.js not installed in OpenCode plugins',
178
+ 'Run the AOS installer to wire OpenCode telemetry plugin.', true);
179
+ }
180
+
181
+ // ---------------------------------------------------------------- 4. Hooks & Security Gates
182
+ function checkHooks() {
183
+ const claudeHooksDir = h('.claude', 'hooks');
184
+ const EXPECTED_VERSION = { 'memb-inject.mjs': 5 };
185
+ const versionOf = (text) => {
186
+ const m = /^\/\/\s*aos-hook-version:\s*(\d+)/m.exec(text);
187
+ return m ? Number(m[1]) : null;
188
+ };
189
+
190
+ for (const file of ['go-gate.mjs', 'graph-gate.mjs', 'memb-inject.mjs']) {
191
+ const p = path.join(claudeHooksDir, file);
192
+ if (!existsSync(p)) {
193
+ add('hooks', file, false, 'missing from ~/.claude/hooks',
194
+ 'Run the installer to wire Claude Code safety hooks.');
195
+ continue;
196
+ }
197
+ const want = EXPECTED_VERSION[file];
198
+ if (!want) {
199
+ add('hooks', file, true, tilde(p), '');
200
+ continue;
201
+ }
202
+ const got = versionOf(readFileSync(p, 'utf8'));
203
+ add('hooks', file, got === want,
204
+ got === want ? `${tilde(p)} (v${got})` : `${tilde(p)} (v${got || 'legacy'}, expected v${want})`,
205
+ 'Run the AOS installer to update to latest hook version.');
206
+ }
207
+
208
+ // Claude settings.json wiring
209
+ const claudeSettings = readJson(h('.claude', 'settings.json'));
210
+ const wired = JSON.stringify(claudeSettings?.hooks || {});
211
+ const claudeWiredOk = wired.includes('go-gate.mjs') && wired.includes('memb-inject.mjs');
212
+ add('hooks', 'Claude settings.json wired', claudeWiredOk,
213
+ claudeWiredOk ? 'PreToolUse & UserPromptSubmit registered' : 'Hooks not fully registered in ~/.claude/settings.json',
214
+ 'Run the AOS installer to wire hooks in settings.json.');
215
+
216
+ // Antigravity hooks
217
+ const agHooksFile = firstExisting([
218
+ h('.gemini', 'antigravity-cli', 'hooks.json'),
219
+ h('.gemini', 'config', 'hooks.json'),
220
+ h('.agents', 'hooks.json')
221
+ ]);
222
+ const agHooks = agHooksFile ? readJson(agHooksFile) : null;
223
+ const agWired = JSON.stringify(agHooks?.hooks || {});
224
+ add('hooks', 'Antigravity hooks', agWired.includes('memb-inject.mjs'),
225
+ agHooksFile ? `${tilde(agHooksFile)} (${agWired.includes('memb-inject.mjs') ? 'memb-inject wired' : 'unwired'})` : 'hooks.json not found',
226
+ 'Run the AOS installer to configure Antigravity hooks.', true);
227
+
228
+ // Codex hooks
229
+ const codexConf = h('.codex', 'config.toml');
230
+ let codexToml = '';
231
+ try { codexToml = readFileSync(codexConf, 'utf8'); } catch {}
232
+ add('hooks', 'Codex config.toml hooks', codexToml.includes('AOS:HOOKS'),
233
+ existsSync(codexConf) ? `${tilde(codexConf)} (${codexToml.includes('AOS:HOOKS') ? 'AOS:HOOKS block wired' : 'no AOS:HOOKS'})` : `${tilde(codexConf)} missing`,
234
+ 'Run the AOS installer to wire Codex hooks.', true);
235
+ }
236
+
237
+ // ---------------------------------------------------------------- 5. Daemons & Ecosystem Modules (Including AO)
238
+ async function checkDaemonsAndModules() {
239
+ // memB
240
+ const membDir = findModule('memB');
241
+ const membListening = await portOpen(8088);
242
+ add('daemons', 'memB WebUI (:8088)', membListening,
243
+ membListening ? 'Active & listening on http://127.0.0.1:8088' : 'Not listening on port 8088',
244
+ IS_MAC ? 'launchctl load -w ~/Library/LaunchAgents/com.bdb.memb.webui.plist' : 'Start src/backend/server.py in memB module.');
245
+
246
+ // Synapse 3D
247
+ const synapseListening = await portOpen(7781);
248
+ add('daemons', 'Synapse 3D (:7781)', synapseListening,
249
+ synapseListening ? 'Active & listening on http://127.0.0.1:7781' : 'Not listening on port 7781',
250
+ IS_MAC ? 'launchctl load -w ~/Library/LaunchAgents/com.bdb.synapse.plist' : 'synapse serve --port 7781', true);
251
+
252
+ // BDB OS Remote Gateway
253
+ const remoteListening = await portOpen(9080);
254
+ add('daemons', 'Remote Gateway (:9080)', remoteListening,
255
+ remoteListening ? 'Active & listening on port 9080' : 'Not listening on port 9080',
256
+ 'Start gateway via ~/dev/bdb-dev/bdb-os-remote/start-gateway.sh', true);
257
+
258
+ // BDB Agent Orchestrator (AO)
259
+ const aoBin = which('ao') || (existsSync(h('.local', 'bin', 'ao')) ? h('.local', 'bin', 'ao') : null);
260
+ let aoVer = null;
261
+ if (aoBin) {
262
+ try {
263
+ aoVer = execFileSync(aoBin, ['--version'], { encoding: 'utf8', timeout: 5000, stdio: ['ignore', 'pipe', 'ignore'] }).trim();
264
+ } catch {}
265
+ }
266
+ const aoListening = await portOpen(3101);
267
+ let aoServiceInfo = 'Not running';
268
+ if (aoBin) {
269
+ try {
270
+ const statusOut = execFileSync(aoBin, ['service', 'status'], { encoding: 'utf8', timeout: 5000, stdio: ['ignore', 'pipe', 'ignore'] });
271
+ const runningLine = statusOut.split('\n').find(l => l.toLowerCase().includes('running'));
272
+ if (runningLine) aoServiceInfo = runningLine.trim();
273
+ } catch {}
274
+ }
275
+
276
+ const aoOk = !!aoBin;
277
+ add('daemons', 'AO Agent Orchestrator', aoOk,
278
+ aoBin ? `${tilde(aoBin)} (${aoVer || 'installed'}) · Daemon :3101: ${aoListening ? 'ONLINE' : 'STOPPED'} (${aoServiceInfo})` : 'ao binary not found',
279
+ IS_MAC && IS_ARM64
280
+ ? 'Enable AO in the installer or run: ao service install'
281
+ : 'AO binary is arm64 macOS native; build from source on other platforms: github.com/hybridlabor-api/bdb-agent-orchestrator', false);
282
+
283
+ // Code-signing check for AO on macOS
284
+ if (IS_MAC && aoBin) {
285
+ let signed = false;
286
+ try {
287
+ execSync(`codesign -v "${aoBin}"`, { stdio: 'ignore' });
288
+ signed = true;
289
+ } catch {}
290
+ add('security', 'AO Binary Signature (AMFI)', signed,
291
+ signed ? 'Binary code-signed (AMFI safe)' : 'Unsigned binary — AMFI might terminate on launch',
292
+ `Run: codesign -s - -f "${aoBin}"`);
293
+ }
294
+ }
295
+
296
+ // ---------------------------------------------------------------- 6. Output & Announcement
297
+ function printAoAnnouncement() {
298
+ console.log(`
299
+ ╭──────────────────────────────────────────────────────────────────────────────╮
300
+ │ │
301
+ │ 🚀 BDB AGENT ORCHESTRATOR APP — FINALE BETA JETZT VERFÜGBAR! │
302
+ │ │
303
+ │ Die nächste Generation der Cross-Harness Multi-Agenten-Orchestrierung │
304
+ │ ist jetzt als finale Beta für alle User freigeschaltet. │
305
+ │ │
306
+ │ • Dashboard & WebUI: http://localhost:3101 │
307
+ │ • Service-Befehl: ao service install (Hintergrunddienst aktivieren) │
308
+ │ • Quick Launch: ao open oder ao service status │
309
+ │ • Features: Session-Telemetrie, Live-AgentTrail & Multi-Workspaces│
310
+ │ │
311
+ ╰──────────────────────────────────────────────────────────────────────────────╯
312
+ `);
313
+ }
314
+
315
+ function report() {
316
+ if (JSON_OUT) {
317
+ const ok = results.filter(r => !r.warningOnly).every(r => r.ok);
318
+ console.log(JSON.stringify({ ok, platform: process.platform, arch: process.arch, results }, null, 2));
319
+ return;
320
+ }
321
+
322
+ printAoAnnouncement();
323
+
324
+ console.log(`\n======================================================`);
325
+ console.log(` 🩺 AOS SYSTEM CHECKUP & DIAGNOSTIC REPORT`);
326
+ console.log(` Platform: ${process.platform} (${process.arch}) · Node: ${process.version}`);
327
+ console.log(`======================================================`);
328
+
329
+ let currentArea = '';
330
+ for (const r of results) {
331
+ if (r.area !== currentArea) {
332
+ currentArea = r.area;
333
+ console.log(`\n[${currentArea.toUpperCase()}]`);
334
+ }
335
+ const icon = r.ok ? '✅' : (r.warningOnly ? '⚠️ ' : '❌');
336
+ console.log(` ${icon} ${r.name.padEnd(28)} ${r.detail}`);
337
+ if (!r.ok && r.fix) {
338
+ console.log(` ↳ Fix: ${r.fix}`);
339
+ }
340
+ }
341
+
342
+ const criticalFails = results.filter(r => !r.ok && !r.warningOnly);
343
+ const warnings = results.filter(r => !r.ok && r.warningOnly);
344
+
345
+ console.log(`\n------------------------------------------------------`);
346
+ if (criticalFails.length === 0) {
347
+ console.log(`🎉 ALL CRITICAL CHECKS PASSED (${results.length - warnings.length}/${results.length})! AOS is properly configured.`);
348
+ if (warnings.length > 0) {
349
+ console.log(` (${warnings.length} optional warning(s) detected — see hints above).`);
350
+ }
351
+ } else {
352
+ console.log(`⚠️ ${criticalFails.length} critical check(s) need attention! Follow the fix instructions above.`);
353
+ }
354
+ console.log(`------------------------------------------------------\n`);
355
+ }
356
+
357
+ // ---------------------------------------------------------------- Run
358
+ checkPrereqs();
359
+ checkAosCore();
360
+ checkHarnesses();
361
+ checkHooks();
362
+ await checkDaemonsAndModules();
363
+ report();
364
+
365
+ const hasCriticalFails = results.some(r => !r.ok && !r.warningOnly);
366
+ process.exit(hasCriticalFails ? 1 : 0);
@@ -0,0 +1,167 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { createHash } from 'node:crypto';
4
+ import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from 'node:fs';
5
+ import { homedir } from 'node:os';
6
+ import { basename, dirname, join, resolve } from 'node:path';
7
+ import { fileURLToPath } from 'node:url';
8
+
9
+ const ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..');
10
+ const INDEX_PATH = join(ROOT, 'lib', 'ecc-store-index.json');
11
+ const index = JSON.parse(readFileSync(INDEX_PATH, 'utf8'));
12
+ const args = process.argv.slice(2);
13
+ const dryRun = args.includes('--dry-run');
14
+ const project = args.includes('--project');
15
+ const positional = args.filter((arg) => !arg.startsWith('--'));
16
+ const option = (name) => args.find((arg) => arg === name || arg.startsWith(`${name}=`))?.split('=').slice(1).join('=');
17
+
18
+ function loadIndex() {
19
+ if (!index.pinned_commit || !index.skills || !index.subagents) throw new Error('Invalid AOS store index');
20
+ return index;
21
+ }
22
+
23
+ function allItems(type) {
24
+ const selected = type === 'agents' || type === 'subagents' ? 'subagents' : 'skills';
25
+ return Object.entries(index[selected] || {}).map(([name, item]) => ({ name, item, type: selected }));
26
+ }
27
+
28
+ function findItem(name) {
29
+ for (const type of ['skills', 'subagents']) {
30
+ if (index[type]?.[name]) return { name, item: index[type][name], type };
31
+ }
32
+ return null;
33
+ }
34
+
35
+ function localSkillNames() {
36
+ const names = new Set();
37
+ const visit = (dir) => {
38
+ if (!existsSync(dir)) return;
39
+ for (const entry of readdirSync(dir, { withFileTypes: true })) {
40
+ const fullPath = join(dir, entry.name);
41
+ if (entry.isDirectory()) visit(fullPath);
42
+ else if (entry.name === 'SKILL.md') names.add(basename(dirname(fullPath)));
43
+ }
44
+ };
45
+ visit(join(ROOT, 'skills'));
46
+ return names;
47
+ }
48
+
49
+ function localAgentNames() {
50
+ const names = new Set();
51
+ for (const dir of [join(ROOT, '.claude', 'agents'), join(ROOT, '.agents', 'agents'), join(ROOT, 'agents')]) {
52
+ if (!existsSync(dir)) continue;
53
+ for (const entry of readdirSync(dir)) names.add(entry.replace(/\.md$/i, ''));
54
+ }
55
+ return names;
56
+ }
57
+
58
+ function globalRoots(type) {
59
+ const home = homedir();
60
+ return type === 'skills'
61
+ ? [
62
+ join(home, '.agents', 'skills'),
63
+ join(home, '.claude', 'skills'),
64
+ join(home, '.codex', 'skills'),
65
+ join(home, '.cursor', 'skills'),
66
+ join(home, '.roo', 'skills'),
67
+ join(home, '.gemini', 'config', 'skills'),
68
+ ]
69
+ : [
70
+ join(home, '.agents', 'agents'),
71
+ join(home, '.claude', 'agents'),
72
+ join(home, '.codex', 'agents'),
73
+ join(home, '.cursor', 'agents'),
74
+ join(home, '.roo', 'agents'),
75
+ join(home, '.gemini', 'config', 'agents'),
76
+ ];
77
+ }
78
+
79
+ function printItems(items) {
80
+ if (items.length === 0) {
81
+ console.log('No store items found.');
82
+ return;
83
+ }
84
+ for (const { name, item, type } of items) {
85
+ const kind = type === 'skills' ? 'skill' : 'agent';
86
+ console.log(`${kind}\t${name}\t${item.category}\t${item.description}`);
87
+ }
88
+ console.log(`\n${items.length} item(s).`);
89
+ }
90
+
91
+ async function download(upstreamPath) {
92
+ const url = `https://raw.githubusercontent.com/affaan-m/ECC/${index.pinned_commit}/${upstreamPath}`;
93
+ const response = await fetch(url, { headers: { 'user-agent': 'aos-store' } });
94
+ if (!response.ok) throw new Error(`Download failed (${response.status}): ${url}`);
95
+ return Buffer.from(await response.arrayBuffer());
96
+ }
97
+
98
+ function targetsFor(type, name) {
99
+ if (project) {
100
+ return type === 'skills'
101
+ ? [join(process.cwd(), 'skills', name, 'SKILL.md')]
102
+ : [join(process.cwd(), 'agents', `${name}.md`)];
103
+ }
104
+ return globalRoots(type).map((root) => type === 'skills'
105
+ ? join(root, name, 'SKILL.md')
106
+ : join(root, `${name}.md`));
107
+ }
108
+
109
+ async function install(name) {
110
+ if (!/^[A-Za-z0-9_-]+$/.test(name)) throw new Error(`Invalid store name: ${name}`);
111
+ const found = findItem(name);
112
+ if (!found) throw new Error(`Store item not found: ${name}`);
113
+ const { item, type } = found;
114
+ const coreNames = type === 'skills' ? localSkillNames() : localAgentNames();
115
+ if (coreNames.has(name)) {
116
+ console.log(`Skipped ${name}: AOS core already provides it.`);
117
+ return;
118
+ }
119
+ const targets = targetsFor(type, name);
120
+ if (dryRun) {
121
+ for (const target of targets) console.log(`[dry-run] write ${target}`);
122
+ return;
123
+ }
124
+ const content = await download(item.upstream_path);
125
+ const digest = createHash('sha256').update(content).digest('hex');
126
+ if (digest !== item.sha256) throw new Error(`SHA-256 mismatch for ${name}: expected ${item.sha256}, got ${digest}`);
127
+ for (const target of targets) {
128
+ mkdirSync(dirname(target), { recursive: true });
129
+ writeFileSync(target, content);
130
+ console.log(`Installed ${name} -> ${target}`);
131
+ }
132
+ }
133
+
134
+ function usage() {
135
+ console.log('Usage:');
136
+ console.log(' aos store list [--type=skills|agents]');
137
+ console.log(' aos store search <query>');
138
+ console.log(' aos store install <name> [--project] [--dry-run]');
139
+ }
140
+
141
+ async function main() {
142
+ loadIndex();
143
+ const command = positional[0] || 'list';
144
+ if (command === 'list') {
145
+ printItems(allItems(option('--type') || 'skills'));
146
+ return;
147
+ }
148
+ if (command === 'search') {
149
+ const query = (positional[1] || '').toLowerCase();
150
+ if (!query) throw new Error('Search requires a query.');
151
+ const items = allItems(option('--type') || '').filter(({ name, item }) => `${name} ${item.description} ${item.category}`.toLowerCase().includes(query));
152
+ printItems(items);
153
+ return;
154
+ }
155
+ if (command === 'install') {
156
+ if (!positional[1]) throw new Error('Install requires a store item name.');
157
+ await install(positional[1]);
158
+ return;
159
+ }
160
+ usage();
161
+ process.exitCode = 1;
162
+ }
163
+
164
+ main().catch((error) => {
165
+ console.error(`aos store: ${error.message}`);
166
+ process.exitCode = 1;
167
+ });
@@ -0,0 +1,122 @@
1
+ # Audit Brief: AOS Skill, Subagent & Extras Store (ECC Fork Integration)
2
+
3
+ **Datum:** 2026-09-24
4
+ **Projekt:** `@hybridlabor-api/aos` (AOS — Curated AI Agent OS)
5
+ **Dokumenttyp:** Architektur- & Sicherheits-Audit-Briefing für externe Reviewer- / Auditor-Agenten
6
+ **Status:** Vor Implementierung (Architektur-Review)
7
+
8
+ ---
9
+
10
+ ## 1. Executive Summary & Zielsetzung
11
+
12
+ AOS (`@hybridlabor-api/aos`) ist ein multi-harness Agenten-Betriebssystem für autonome Coding-Pipelines (unterstützt Claude Code, Google Antigravity, Codex, Cursor, Roo Code und OpenCode). Aktuell liefert AOS ca. 185 kuratierte Kern-Skills und eine 7-Node-Graph-Architektur mit deterministischen Übergängen (Architect → TechLead → Build → Reviewer → Shipping).
13
+
14
+ ### Geplante Erweiterung
15
+ Aufbau eines dezentralen **Skill-, Subagent- und Extras-Stores** als Fallback-Ebene auf Basis eines gepflegten Forks von **[affaan-m/ECC](https://github.com/affaan-m/ECC)** (Everything Claude Code, MIT-Lizenz):
16
+ 1. **Fallback in `/ask-tim`:** Wenn ein Nutzer nach einer Domäne oder einem Framework sucht (z. B. Spring Boot, Godot, Django), das nicht im 185-Skill-Kern von AOS liegt, soll `/ask-tim` automatisch passende Erweiterungen aus dem Store vorschlagen.
17
+ 2. **Fallback in `--skill=<name>`:** Bei Pipeline-Aufrufen wie `/startcycle-graph --skill=django-pro "Ziel"` soll ein lokal fehlender Skill nicht sofort hart mit einer Eskalation abbrechen, sondern im Store gesucht, validiert und on-demand geladen werden.
18
+ 3. **Subagent & Extras Katalog:** Bereitstellung von spezialisierten Auxiliary Agents, Templates, Rules und Hooks aus dem ECC-Ökosystem als modulare AOS-Erweiterungen.
19
+
20
+ ---
21
+
22
+ ## 2. Aktueller Systembestand in AOS (Ist-Zustand)
23
+
24
+ ### 2.1 Relevante Code- & Konfigurations-Pfade
25
+ - **Multi-Harness Installer:** [`installer.js`](file:///Users/timrennings/dev/bdb-dev/bdb-dev-optimized-agent-skills/installer.js) — Synchronisiert Skills, MCP-Configs und Agents nach `~/.claude/`, `~/.agents/`, `~/.codex/`, `~/.cursor/` etc.
26
+ - **Pipeline Dispatcher:** [`.claude/workflows/startcycle-dispatch.mjs`](file:///Users/timrennings/dev/bdb-dev/bdb-dev-optimized-agent-skills/.claude/workflows/startcycle-dispatch.mjs) — Verwaltet den Startcycle-Graph, GO-Gates, mandatory skills (`--skill=<name>`) und Agenten-Orchestrierung.
27
+ - **Skill Router:** [`skills/global_config/ask-tim/SKILL.md`](file:///Users/timrennings/dev/bdb-dev/bdb-dev-optimized-agent-skills/skills/global_config/ask-tim/SKILL.md) — Zentraler Einstiegspunkt für Intent-Erkennung und Skill-Auswahl.
28
+ - **Vendor Tracking:** [`~/.agents/vendor-manifest.json`](file:///Users/timrennings/.agents/vendor-manifest.json) — Pinned Git SHAs für Upstream-Repositories (z. B. `anti-slop`, `skylos`, `claude-red`).
29
+ - **Bereits portierte ECC-Komponenten:** [`THIRD_PARTY_NOTICES.md`](file:///Users/timrennings/dev/bdb-dev/bdb-dev-optimized-agent-skills/THIRD_PARTY_NOTICES.md) — 6 Auxiliary Agents (`silent-failure-hunter`, `security-reviewer`, `go-build-resolver`, `database-reviewer`, `opensource-forker`, `opensource-sanitizer`) und `plan-canvas`.
30
+
31
+ ### 2.2 Bestehende `--skill` Validierungslogik (`startcycle-dispatch.mjs:701-741`)
32
+ ```javascript
33
+ // Aktuelles Verhalten:
34
+ if (mandatorySkillNames.length > 0) {
35
+ const skillCheckResult = await agent(`Check whether each of these skill names resolves to an installed skill...`);
36
+ const missing = skillCheckResult?.missing ?? [];
37
+ if (missing.length > 0) {
38
+ // HARTES ESKALIEREN:
39
+ return await escalate(`--skill named skill(s) that could not be found: ${missing.join(', ')}...`);
40
+ }
41
+ }
42
+ ```
43
+
44
+ ---
45
+
46
+ ## 3. Geplante Soll-Architektur
47
+
48
+ ```mermaid
49
+ flowchart TD
50
+ User([Nutzer-Anfrage / Prompt]) --> Trigger{Einstiegspunkt}
51
+
52
+ Trigger -->|1. /ask-tim Suche| AskTim[ask-tim Router]
53
+ Trigger -->|2. --skill=name Flag| Dispatcher[startcycle-dispatch]
54
+
55
+ AskTim --> CheckCore1{Im 185-Skill AOS Core?}
56
+ Dispatcher --> CheckCore2{Lokal auf Disk installiert?}
57
+
58
+ CheckCore1 -->|Ja| UseCore[Empfehle/Nutze nativen AOS-Skill]
59
+ CheckCore2 -->|Ja| RunCore[Starte Pipeline mit Core-Skill]
60
+
61
+ CheckCore1 -->|Nein| QueryStore[Abfrage lokaler ecc-store-index.json]
62
+ CheckCore2 -->|Nein| QueryStore
63
+
64
+ QueryStore --> MatchFound{Match im Store?}
65
+ MatchFound -->|Nein| FinalEscalate[Eskalation / Keine Treffer]
66
+ MatchFound -->|Ja| StoreAction{Aktion}
67
+
68
+ StoreAction -->|bei /ask-tim| ShowOption[Empfehlung + 'aos store install <name>']
69
+ StoreAction -->|bei --skill| GateCheck[GO-Gate / Confirmation]
70
+
71
+ GateCheck -->|Genehmigt| FetchEngine[On-Demand Sync in ~/.agents/skills/]
72
+ FetchEngine --> ValidateHarness[POSIX & Harness-Tool Linter]
73
+ ValidateHarness --> RunPipeline[Pipeline-Start ohne Unterbrechung]
74
+ ```
75
+
76
+ ---
77
+
78
+ ## 4. Kernfragen & Prüffelder für das Audit
79
+
80
+ Der Auditor-Agent wird gebeten, folgende kritische Fragestellungen strukturiert zu beleuchten:
81
+
82
+ ### 1. GO-Gate & Sicherheit (Supply-Chain-Risiko)
83
+ * **Problem:** Dürfen externe Skills oder Agents während eines autonomen Pipeline-Laufs dynamisch aus einem Remote-Repository nachgeladen werden?
84
+ * **Audit-Frage:** Wie muss die Bestätigung strukturiert sein, damit die strikte AOS-Regel (*"read-only until literal GO"*) nicht kompromittiert wird? Genügt ein lokales, kryptografisch verifiziertes Manifest mit SHA-256 Checksummen?
85
+
86
+ ### 2. Multi-Harness Tool-Inkompatibilitäten
87
+ * **Problem:** `affaan-m/ECC` ist primär für Claude Code konzipiert und verwendet teils hardcodierte Tool-Namen wie `Bash`, `View`, `Edit`, `GlobTool`.
88
+ * **Audit-Frage:** Welche automatisierten Transformations- oder Linter-Regeln müssen beim Ingest/Installationsschritt greifen, damit importierte Skills fehlerfrei in Google Antigravity (`run_command`, `view_file`), OpenAI Codex (`exec`, `read_file`) und Cursor funktionieren?
89
+
90
+ ### 3. Context Window & Token-Budget
91
+ * **Problem:** Ein ungefilterter Import von 400+ Skills würde die Context-Limits und System-Prompts überlasten.
92
+ * **Audit-Frage:** Ist die gewählte Architektur mit einem leichtgewichtigen, lokalen Vektor- oder Metadaten-Index (`ecc-store-index.json` < 100 KB) optimal, und wie sollte das semantische Ranking bei ungenauen Begriffen erfolgen?
93
+
94
+ ### 4. Namenskonflikte & Rangfolge (Precedence)
95
+ * **Problem:** Was passiert, wenn ein ECC-Skill denselben Namen trägt wie ein existierender oder zukünftiger AOS-Kern-Skill (z. B. `tailwind-patterns` oder `tdd-workflow`)?
96
+ * **Audit-Frage:** Sollte ein striktes Namespacing (`ecc/<skill-name>` oder Tagging `origin: ecc`) erzwungen werden, um Overwrites und Seiteneffekte auszuschließen?
97
+
98
+ ### 5. Wartungs- und Sync-Strategie des Forks
99
+ * **Problem:** ECC wird kontinuierlich weiterentwickelt.
100
+ * **Audit-Frage:** Wie sieht eine nachhaltige GitHub-Action-Sync-Pipeline für den Fork `hybridlabor-api/ECC` aus, die neue Upstream-Releases verarbeitet, ohne manuell angepasste Harness-Kompatibilitäts-Fixes zu überschreiben?
101
+
102
+ ---
103
+
104
+ ## 5. Referenzierte Komponenten & Schnittstellen
105
+
106
+ | Komponente | Datei / Pfad | Relevante Zeilen / Kontext |
107
+ |---|---|---|
108
+ | **Pipeline-Dispatcher** | [`.claude/workflows/startcycle-dispatch.mjs`](file:///Users/timrennings/dev/bdb-dev/bdb-dev-optimized-agent-skills/.claude/workflows/startcycle-dispatch.mjs) | Z. 701–741 (Mandatory Skill Check & Eskalation) |
109
+ | **Skill Router** | [`skills/global_config/ask-tim/SKILL.md`](file:///Users/timrennings/dev/bdb-dev/bdb-dev-optimized-agent-skills/skills/global_config/ask-tim/SKILL.md) | Z. 1–70 (Main Flow & Intent Index) |
110
+ | **Vendor Registry** | [`~/.agents/vendor-manifest.json`](file:///Users/timrennings/.agents/vendor-manifest.json) | Vorhandene Pinned-Upstream-Repositories |
111
+ | **Lizenz- & Provenance** | [`THIRD_PARTY_NOTICES.md`](file:///Users/timrennings/dev/bdb-dev/bdb-dev-optimized-agent-skills/THIRD_PARTY_NOTICES.md) | Z. 12–50 (Bisheriger Port von ECC-Agents) |
112
+ | **AOS Installer & Sync** | [`installer.js`](file:///Users/timrennings/dev/bdb-dev/bdb-dev-optimized-agent-skills/installer.js) | Z. 110–135 (Multi-Platform Fan-out) |
113
+
114
+ ---
115
+
116
+ ## 6. Erwartetes Audit-Ergebnis
117
+
118
+ Der externe Auditor-Agent sollte am Ende einen Bericht mit folgendem Schema abliefern:
119
+ 1. **Architektur-Bewertung:** Bestätigung oder Korrektur der vorgeschlagenen Store- und Fallback-Architektur.
120
+ 2. **Identifizierte Risiken:** Kategorisiert nach *Blocker*, *Warnung*, *Empfehlung*.
121
+ 3. **Konkrete Lösungsvorschläge:** Für Tool-Mapping, Token-Schonung und GO-Gate-Integration.
122
+ 4. **Sign-Off / Freigabe-Empfehlung:** Für den Start der Implementierung von Phase 1.