@hybridlabor-api/aos 4.5.0 → 4.5.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/.claude/hooks/memb-inject.mjs +135 -40
- package/.claude/workflows/startcycle-dispatch.mjs +318 -3
- package/bin/aos-dashboard.mjs +8 -2
- package/installer.js +203 -7
- package/package.json +1 -1
- package/skills/global_config/aos-setup/SKILL.md +7 -9
- package/skills/global_config/aos-setup/scripts/aos-doctor.mjs +43 -1
- package/skills/global_config/openwiki-skill/scripts/install_daemon.ps1 +107 -18
- package/.agents/skills/firecrawl/SKILL.md +0 -149
- package/.agents/skills/firecrawl/rules/install.md +0 -82
- package/.agents/skills/firecrawl/rules/security.md +0 -26
- package/.agents/skills/firecrawl-agent/SKILL.md +0 -58
- package/.agents/skills/firecrawl-build/SKILL.md +0 -39
- package/.agents/skills/firecrawl-build-interact/SKILL.md +0 -68
- package/.agents/skills/firecrawl-build-onboarding/SKILL.md +0 -103
- package/.agents/skills/firecrawl-build-onboarding/references/auth-flow.md +0 -39
- package/.agents/skills/firecrawl-build-onboarding/references/project-setup.md +0 -20
- package/.agents/skills/firecrawl-build-onboarding/references/sdk-installation.md +0 -17
- package/.agents/skills/firecrawl-build-scrape/SKILL.md +0 -69
- package/.agents/skills/firecrawl-build-search/SKILL.md +0 -69
- package/.agents/skills/firecrawl-crawl/SKILL.md +0 -59
- package/.agents/skills/firecrawl-download/SKILL.md +0 -70
- package/.agents/skills/firecrawl-interact/SKILL.md +0 -84
- package/.agents/skills/firecrawl-map/SKILL.md +0 -51
- package/.agents/skills/firecrawl-scrape/SKILL.md +0 -69
- package/.agents/skills/firecrawl-search/SKILL.md +0 -60
- package/mcps/RhinoMCP/cc-plugin/.claude/settings.json +0 -10
- package/mcps/after-effects-mcp/build/index.js +0 -840
- package/mcps/after-effects-mcp/build/scripts/applyEffect.jsx +0 -153
- package/mcps/after-effects-mcp/build/scripts/applyEffectTemplate.jsx +0 -218
- package/mcps/after-effects-mcp/build/scripts/createComposition.jsx +0 -71
- package/mcps/after-effects-mcp/build/scripts/createShapeLayer.jsx +0 -147
- package/mcps/after-effects-mcp/build/scripts/createSolidLayer.jsx +0 -114
- package/mcps/after-effects-mcp/build/scripts/createTextLayer.jsx +0 -115
- package/mcps/after-effects-mcp/build/scripts/getLayerInfo.jsx +0 -192
- package/mcps/after-effects-mcp/build/scripts/getProjectInfo.jsx +0 -90
- package/mcps/after-effects-mcp/build/scripts/listCompositions.jsx +0 -50
- package/mcps/after-effects-mcp/build/scripts/mcp-bridge-auto.jsx +0 -1773
- package/mcps/after-effects-mcp/build/scripts/setLayerProperties.jsx +0 -160
- package/mcps/computer-use-mcp/dist/client.d.ts +0 -150
- package/mcps/computer-use-mcp/dist/client.js +0 -136
- package/mcps/computer-use-mcp/dist/entrypoint.d.ts +0 -16
- package/mcps/computer-use-mcp/dist/entrypoint.js +0 -26
- package/mcps/computer-use-mcp/dist/native.d.ts +0 -212
- package/mcps/computer-use-mcp/dist/native.js +0 -50
- package/mcps/computer-use-mcp/dist/server.d.ts +0 -32
- package/mcps/computer-use-mcp/dist/server.js +0 -342
- package/mcps/computer-use-mcp/dist/session.d.ts +0 -101
- package/mcps/computer-use-mcp/dist/session.js +0 -2372
package/installer.js
CHANGED
|
@@ -3175,11 +3175,44 @@ function injectHarnessRules() {
|
|
|
3175
3175
|
// most (a fresh install got it; every machine that already had AOS did not).
|
|
3176
3176
|
function installGlobalHooks() {
|
|
3177
3177
|
const hooksSrc = path.join(srcDir, '.claude', 'hooks');
|
|
3178
|
+
const workflowsSrc = path.join(srcDir, '.claude', 'workflows');
|
|
3179
|
+
|
|
3180
|
+
// 1. Claude Code
|
|
3178
3181
|
if (fs.existsSync(hooksSrc)) {
|
|
3179
3182
|
copyDirRecursiveSync(hooksSrc, path.join(homeDir, '.claude', 'hooks'));
|
|
3180
3183
|
log.step(`Installed hooks to ${path.join(homeDir, '.claude', 'hooks')}`);
|
|
3181
3184
|
}
|
|
3185
|
+
if (fs.existsSync(workflowsSrc)) {
|
|
3186
|
+
copyDirRecursiveSync(workflowsSrc, path.join(homeDir, '.claude', 'workflows'));
|
|
3187
|
+
}
|
|
3182
3188
|
mergeBdbSettingsHooks(path.join(homeDir, '.claude', 'settings.json'));
|
|
3189
|
+
|
|
3190
|
+
// 2. Google Antigravity
|
|
3191
|
+
const agyHooksDir = path.join(geminiDir, 'config', 'hooks');
|
|
3192
|
+
const agyWorkflowsDir = path.join(geminiDir, 'config', 'workflows');
|
|
3193
|
+
if (fs.existsSync(hooksSrc)) {
|
|
3194
|
+
copyDirRecursiveSync(hooksSrc, agyHooksDir);
|
|
3195
|
+
log.step(`Installed hooks to ${agyHooksDir}`);
|
|
3196
|
+
}
|
|
3197
|
+
if (fs.existsSync(workflowsSrc)) {
|
|
3198
|
+
copyDirRecursiveSync(workflowsSrc, agyWorkflowsDir);
|
|
3199
|
+
}
|
|
3200
|
+
mergeAntigravityHooks(path.join(geminiDir, 'config', 'hooks.json'));
|
|
3201
|
+
if (fs.existsSync(path.join(geminiDir, 'antigravity-cli'))) {
|
|
3202
|
+
mergeAntigravityHooks(path.join(geminiDir, 'antigravity-cli', 'hooks.json'));
|
|
3203
|
+
}
|
|
3204
|
+
|
|
3205
|
+
// 3. OpenAI Codex CLI
|
|
3206
|
+
const codexHooksDir = path.join(homeDir, '.codex', 'hooks');
|
|
3207
|
+
const codexWorkflowsDir = path.join(homeDir, '.codex', 'workflows');
|
|
3208
|
+
if (fs.existsSync(hooksSrc)) {
|
|
3209
|
+
copyDirRecursiveSync(hooksSrc, codexHooksDir);
|
|
3210
|
+
log.step(`Installed hooks to ${codexHooksDir}`);
|
|
3211
|
+
}
|
|
3212
|
+
if (fs.existsSync(workflowsSrc)) {
|
|
3213
|
+
copyDirRecursiveSync(workflowsSrc, codexWorkflowsDir);
|
|
3214
|
+
}
|
|
3215
|
+
mergeCodexTomlHooks(path.join(homeDir, '.codex', 'config.toml'));
|
|
3183
3216
|
}
|
|
3184
3217
|
|
|
3185
3218
|
// Merge the BDB hooks -- the two gates plus the memB ambient-memory hook --
|
|
@@ -3258,12 +3291,161 @@ function mergeBdbSettingsHooks(settingsPath, { projectLocal = false } = {}) {
|
|
|
3258
3291
|
}
|
|
3259
3292
|
|
|
3260
3293
|
try {
|
|
3294
|
+
fs.mkdirSync(path.dirname(settingsPath), { recursive: true });
|
|
3261
3295
|
fs.writeFileSync(settingsPath, JSON.stringify(buildMerged(existing), null, 2) + '\n');
|
|
3262
3296
|
} catch (e) {
|
|
3263
3297
|
log.warn(`Could not write ${settingsPath}: ${e.message}`);
|
|
3264
3298
|
}
|
|
3265
3299
|
}
|
|
3266
3300
|
|
|
3301
|
+
// Merge the BDB hooks into Google Antigravity's hooks.json (.agents/hooks.json or
|
|
3302
|
+
// ~/.gemini/config/hooks.json), preserving user-defined foreign hooks.
|
|
3303
|
+
function mergeAntigravityHooks(hooksPath, { projectLocal = false } = {}) {
|
|
3304
|
+
const bdbHookScripts = ['go-gate.mjs', 'graph-gate.mjs', 'memb-inject.mjs', 'startcycle-dispatch.mjs'];
|
|
3305
|
+
const isBdbEntry = (entry) => {
|
|
3306
|
+
const cmds = (entry && Array.isArray(entry.hooks) ? entry.hooks : [entry])
|
|
3307
|
+
.map((h) => (h && typeof h.command === 'string' ? h.command : (typeof h === 'string' ? h : '')))
|
|
3308
|
+
.join(' ');
|
|
3309
|
+
return bdbHookScripts.some((name) => cmds.includes(name));
|
|
3310
|
+
};
|
|
3311
|
+
|
|
3312
|
+
const baseDir = path.dirname(hooksPath);
|
|
3313
|
+
const hooksDir = projectLocal ? path.join(currentDir, '.agents', 'hooks') : path.join(baseDir, 'hooks');
|
|
3314
|
+
const workflowsDir = projectLocal ? path.join(currentDir, '.agents', 'workflows') : path.join(baseDir, 'workflows');
|
|
3315
|
+
const globalHooksDir = projectLocal ? path.join(homeDir, '.gemini', 'config', 'hooks') : hooksDir;
|
|
3316
|
+
|
|
3317
|
+
const bdbHooks = {
|
|
3318
|
+
PreToolUse: [
|
|
3319
|
+
{
|
|
3320
|
+
matcher: "run_command|Bash",
|
|
3321
|
+
hooks: [{ type: "command", command: `node "${path.join(hooksDir, 'go-gate.mjs')}"`, timeout: 10000 }]
|
|
3322
|
+
}
|
|
3323
|
+
],
|
|
3324
|
+
Stop: [
|
|
3325
|
+
{
|
|
3326
|
+
hooks: [{ type: "command", command: `node "${path.join(hooksDir, 'graph-gate.mjs')}"`, timeout: 10000 }]
|
|
3327
|
+
}
|
|
3328
|
+
],
|
|
3329
|
+
PreInvocation: [
|
|
3330
|
+
{
|
|
3331
|
+
hooks: [
|
|
3332
|
+
{ type: "command", command: `node "${path.join(globalHooksDir, 'memb-inject.mjs')}"`, timeout: 8000 },
|
|
3333
|
+
{ type: "command", command: `node "${path.join(workflowsDir, 'startcycle-dispatch.mjs')}"`, timeout: 30000 }
|
|
3334
|
+
]
|
|
3335
|
+
}
|
|
3336
|
+
]
|
|
3337
|
+
};
|
|
3338
|
+
|
|
3339
|
+
const buildMerged = (existing) => {
|
|
3340
|
+
const merged = existing && typeof existing === 'object' ? existing : {};
|
|
3341
|
+
merged.hooks = merged.hooks && typeof merged.hooks === 'object' ? merged.hooks : {};
|
|
3342
|
+
for (const [event, entries] of Object.entries(bdbHooks)) {
|
|
3343
|
+
const foreignEntries = (Array.isArray(merged.hooks[event]) ? merged.hooks[event] : [])
|
|
3344
|
+
.filter((e) => !isBdbEntry(e));
|
|
3345
|
+
merged.hooks[event] = [...foreignEntries, ...entries];
|
|
3346
|
+
}
|
|
3347
|
+
return merged;
|
|
3348
|
+
};
|
|
3349
|
+
|
|
3350
|
+
let existing = null;
|
|
3351
|
+
if (fs.existsSync(hooksPath)) {
|
|
3352
|
+
existing = readJsonFile(hooksPath);
|
|
3353
|
+
if (!existing) {
|
|
3354
|
+
const backupCopy = `${hooksPath}.corrupt_${timestamp}.bak`;
|
|
3355
|
+
const sideCarPath = `${hooksPath}.bdb-new.json`;
|
|
3356
|
+
let backupWritten = true;
|
|
3357
|
+
try {
|
|
3358
|
+
fs.copyFileSync(hooksPath, backupCopy);
|
|
3359
|
+
} catch (copyError) {
|
|
3360
|
+
backupWritten = false;
|
|
3361
|
+
log.warn(`Could not create the hooks backup: ${copyError.message}`);
|
|
3362
|
+
}
|
|
3363
|
+
try {
|
|
3364
|
+
fs.writeFileSync(sideCarPath, JSON.stringify(buildMerged(null), null, 2) + '\n');
|
|
3365
|
+
} catch (writeError) {
|
|
3366
|
+
log.warn(`Could not write ${path.basename(sideCarPath)}: ${writeError.message}`);
|
|
3367
|
+
}
|
|
3368
|
+
log.warn(`${path.basename(hooksPath)} is not valid JSON - hook merge skipped, nothing overwritten.`);
|
|
3369
|
+
if (backupWritten) log.warn(`Backup copy: ${backupCopy}`);
|
|
3370
|
+
log.warn(`BDB-wired hooks: ${sideCarPath}`);
|
|
3371
|
+
return;
|
|
3372
|
+
}
|
|
3373
|
+
}
|
|
3374
|
+
|
|
3375
|
+
try {
|
|
3376
|
+
fs.mkdirSync(path.dirname(hooksPath), { recursive: true });
|
|
3377
|
+
fs.writeFileSync(hooksPath, JSON.stringify(buildMerged(existing), null, 2) + '\n');
|
|
3378
|
+
} catch (e) {
|
|
3379
|
+
log.warn(`Could not write ${hooksPath}: ${e.message}`);
|
|
3380
|
+
}
|
|
3381
|
+
}
|
|
3382
|
+
|
|
3383
|
+
// Merge the BDB hooks into ChatGPT Codex CLI's config.toml (~/.codex/config.toml or
|
|
3384
|
+
// .codex/config.toml), ensuring [features] hooks = true and preserving existing
|
|
3385
|
+
// non-BDB settings, comments, and MCP servers.
|
|
3386
|
+
function mergeCodexTomlHooks(configTomlPath, { projectLocal = false } = {}) {
|
|
3387
|
+
const baseDir = path.dirname(configTomlPath);
|
|
3388
|
+
const hooksDir = projectLocal ? path.join(currentDir, '.codex', 'hooks') : path.join(baseDir, 'hooks');
|
|
3389
|
+
const workflowsDir = projectLocal ? path.join(currentDir, '.codex', 'workflows') : path.join(baseDir, 'workflows');
|
|
3390
|
+
const globalHooksDir = projectLocal ? path.join(homeDir, '.codex', 'hooks') : hooksDir;
|
|
3391
|
+
|
|
3392
|
+
const tomlSnippet = [
|
|
3393
|
+
'# AOS:HOOKS:START',
|
|
3394
|
+
'[[hooks.PreToolUse]]',
|
|
3395
|
+
'matcher = "^(Bash|run_command)$"',
|
|
3396
|
+
'[[hooks.PreToolUse.hooks]]',
|
|
3397
|
+
'type = "command"',
|
|
3398
|
+
`command = ${JSON.stringify(`node "${path.join(hooksDir, 'go-gate.mjs')}"`)}`,
|
|
3399
|
+
'timeout = 30',
|
|
3400
|
+
'',
|
|
3401
|
+
'[[hooks.Stop]]',
|
|
3402
|
+
'[[hooks.Stop.hooks]]',
|
|
3403
|
+
'type = "command"',
|
|
3404
|
+
`command = ${JSON.stringify(`node "${path.join(hooksDir, 'graph-gate.mjs')}"`)}`,
|
|
3405
|
+
'timeout = 30',
|
|
3406
|
+
'',
|
|
3407
|
+
'[[hooks.UserPromptSubmit]]',
|
|
3408
|
+
'[[hooks.UserPromptSubmit.hooks]]',
|
|
3409
|
+
'type = "command"',
|
|
3410
|
+
`command = ${JSON.stringify(`node "${path.join(globalHooksDir, 'memb-inject.mjs')}"`)}`,
|
|
3411
|
+
'timeout = 30',
|
|
3412
|
+
'',
|
|
3413
|
+
'[[hooks.UserPromptSubmit]]',
|
|
3414
|
+
'[[hooks.UserPromptSubmit.hooks]]',
|
|
3415
|
+
'type = "command"',
|
|
3416
|
+
`command = ${JSON.stringify(`node "${path.join(workflowsDir, 'startcycle-dispatch.mjs')}"`)}`,
|
|
3417
|
+
'timeout = 30',
|
|
3418
|
+
'# AOS:HOOKS:END'
|
|
3419
|
+
].join('\n');
|
|
3420
|
+
|
|
3421
|
+
let content = fs.existsSync(configTomlPath) ? fs.readFileSync(configTomlPath, 'utf8') : '';
|
|
3422
|
+
|
|
3423
|
+
// Ensure [features] hooks = true
|
|
3424
|
+
const hasHooksFeature = /(?:hooks|codex_hooks)\s*=\s*true/m.test(content);
|
|
3425
|
+
if (!hasHooksFeature) {
|
|
3426
|
+
if (/^\[features\]/m.test(content)) {
|
|
3427
|
+
content = content.replace(/^\[features\]/m, '[features]\nhooks = true');
|
|
3428
|
+
} else {
|
|
3429
|
+
content = `[features]\nhooks = true\n\n${content.trimStart()}`;
|
|
3430
|
+
}
|
|
3431
|
+
}
|
|
3432
|
+
|
|
3433
|
+
// Replace existing AOS:HOOKS block or append
|
|
3434
|
+
const hookBlockRegex = /# AOS:HOOKS:START[\s\S]*?# AOS:HOOKS:END/;
|
|
3435
|
+
if (hookBlockRegex.test(content)) {
|
|
3436
|
+
content = content.replace(hookBlockRegex, tomlSnippet);
|
|
3437
|
+
} else {
|
|
3438
|
+
content = `${content.trimEnd()}\n\n${tomlSnippet}\n`;
|
|
3439
|
+
}
|
|
3440
|
+
|
|
3441
|
+
try {
|
|
3442
|
+
fs.mkdirSync(path.dirname(configTomlPath), { recursive: true });
|
|
3443
|
+
fs.writeFileSync(configTomlPath, content, { mode: 0o600 });
|
|
3444
|
+
} catch (e) {
|
|
3445
|
+
log.warn(`Could not write ${configTomlPath}: ${e.message}`);
|
|
3446
|
+
}
|
|
3447
|
+
}
|
|
3448
|
+
|
|
3267
3449
|
// Tier 9 (Local Project Harness): drop the dispatcher contract into the
|
|
3268
3450
|
// CURRENT PROJECT only -- no writes to $HOME, no global skill/MCP sync, and
|
|
3269
3451
|
// this runs as an early return BEFORE any global install step. A bare
|
|
@@ -3276,22 +3458,29 @@ function mergeBdbSettingsHooks(settingsPath, { projectLocal = false } = {}) {
|
|
|
3276
3458
|
// non-interactively via `--project-harness` (combine with -y for CI).
|
|
3277
3459
|
function installProjectHarness() {
|
|
3278
3460
|
const projectClaudeDir = path.join(currentDir, '.claude');
|
|
3279
|
-
|
|
3461
|
+
const projectAgentsDir = path.join(currentDir, '.agents');
|
|
3462
|
+
const projectCodexDir = path.join(currentDir, '.codex');
|
|
3463
|
+
|
|
3464
|
+
installStep(`create harness directories`, () => {
|
|
3280
3465
|
fs.mkdirSync(projectClaudeDir, { recursive: true });
|
|
3466
|
+
fs.mkdirSync(projectAgentsDir, { recursive: true });
|
|
3467
|
+
fs.mkdirSync(projectCodexDir, { recursive: true });
|
|
3281
3468
|
}, 'The harness copies below will most likely fail as well.');
|
|
3282
3469
|
|
|
3283
3470
|
installStep('copy .agents/ contract into project', () => {
|
|
3284
3471
|
const agentsSrc = path.join(srcDir, '.agents');
|
|
3285
3472
|
if (!fs.existsSync(agentsSrc)) throw new Error(`missing payload: ${agentsSrc}`);
|
|
3286
|
-
copyDirRecursiveSync(agentsSrc,
|
|
3287
|
-
log.step(`Copied .agents/ contract to ${
|
|
3473
|
+
copyDirRecursiveSync(agentsSrc, projectAgentsDir);
|
|
3474
|
+
log.step(`Copied .agents/ contract to ${projectAgentsDir}`);
|
|
3288
3475
|
}, 'graph.md / state.schema.json may be missing in the project.');
|
|
3289
3476
|
|
|
3290
3477
|
installStep('copy dispatcher workflows into project', () => {
|
|
3291
3478
|
const workflowsSrc = path.join(srcDir, '.claude', 'workflows');
|
|
3292
3479
|
if (fs.existsSync(workflowsSrc)) {
|
|
3293
3480
|
copyDirRecursiveSync(workflowsSrc, path.join(projectClaudeDir, 'workflows'));
|
|
3294
|
-
|
|
3481
|
+
copyDirRecursiveSync(workflowsSrc, path.join(projectAgentsDir, 'workflows'));
|
|
3482
|
+
copyDirRecursiveSync(workflowsSrc, path.join(projectCodexDir, 'workflows'));
|
|
3483
|
+
log.step(`Copied dispatcher workflows to project harnesses`);
|
|
3295
3484
|
}
|
|
3296
3485
|
}, '/startcycle dispatch degrades to graph.md as a manual guide.');
|
|
3297
3486
|
|
|
@@ -3299,7 +3488,9 @@ function installProjectHarness() {
|
|
|
3299
3488
|
const hooksSrc = path.join(srcDir, '.claude', 'hooks');
|
|
3300
3489
|
if (fs.existsSync(hooksSrc)) {
|
|
3301
3490
|
copyDirRecursiveSync(hooksSrc, path.join(projectClaudeDir, 'hooks'));
|
|
3302
|
-
|
|
3491
|
+
copyDirRecursiveSync(hooksSrc, path.join(projectAgentsDir, 'hooks'));
|
|
3492
|
+
copyDirRecursiveSync(hooksSrc, path.join(projectCodexDir, 'hooks'));
|
|
3493
|
+
log.step(`Copied hooks to project harnesses`);
|
|
3303
3494
|
}
|
|
3304
3495
|
}, 'go-gate / graph-gate enforcement stays inactive in this project.');
|
|
3305
3496
|
|
|
@@ -3311,9 +3502,11 @@ function installProjectHarness() {
|
|
|
3311
3502
|
}
|
|
3312
3503
|
}, 'The dispatcher runs, but its agent-file pointers resolve to nothing.');
|
|
3313
3504
|
|
|
3314
|
-
installStep('wire project
|
|
3505
|
+
installStep('wire project harnesses to local hooks', () => {
|
|
3315
3506
|
mergeBdbSettingsHooks(path.join(projectClaudeDir, 'settings.json'), { projectLocal: true });
|
|
3316
|
-
|
|
3507
|
+
mergeAntigravityHooks(path.join(projectAgentsDir, 'hooks.json'), { projectLocal: true });
|
|
3508
|
+
mergeCodexTomlHooks(path.join(projectCodexDir, 'config.toml'), { projectLocal: true });
|
|
3509
|
+
log.step(`Wired project hooks in Claude, Antigravity, and Codex configurations`);
|
|
3317
3510
|
}, 'The gate hooks exist but are not auto-wired for this project.');
|
|
3318
3511
|
|
|
3319
3512
|
log.success(`Project harness installed to ${currentDir}`);
|
|
@@ -4406,6 +4599,9 @@ module.exports = {
|
|
|
4406
4599
|
detectPlatforms,
|
|
4407
4600
|
markPlatformsExplicit,
|
|
4408
4601
|
mergeBdbSettingsHooks,
|
|
4602
|
+
mergeAntigravityHooks,
|
|
4603
|
+
mergeCodexTomlHooks,
|
|
4604
|
+
mergeCodexHooks: mergeCodexTomlHooks,
|
|
4409
4605
|
installGlobalHooks,
|
|
4410
4606
|
installProjectHarness,
|
|
4411
4607
|
mirrorMcpServersTo,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hybridlabor-api/aos",
|
|
3
|
-
"version": "4.5.
|
|
3
|
+
"version": "4.5.1",
|
|
4
4
|
"description": "AOS — A Curated AI AGENT OS. Optimized agent skills and add-ons like memB, OpenWiki, Heimdall Token Saver, and Godmode architectures.",
|
|
5
5
|
"main": "installer.js",
|
|
6
6
|
"engines": {
|
|
@@ -36,15 +36,12 @@ believing memory works everywhere:
|
|
|
36
36
|
| | Skills | MCP | Hooks |
|
|
37
37
|
|---|---|---|---|
|
|
38
38
|
| Claude Code | `~/.claude/skills` | `~/.claude.json` | **yes** |
|
|
39
|
-
| Antigravity | `~/.gemini/config/skills` | `mcp_config.json` |
|
|
40
|
-
| Codex | `~/.codex/skills` | `config.toml` |
|
|
39
|
+
| Antigravity | `~/.gemini/config/skills` | `mcp_config.json` | **yes** (.agents/hooks.json / hooks.json) |
|
|
40
|
+
| Codex | `~/.codex/skills` | `config.toml` | **yes** (config.toml) |
|
|
41
41
|
| OpenCode | — | `opencode.jsonc` | no |
|
|
42
42
|
| Cursor / Roo | `bdb-skills` | `mcp.json` | no |
|
|
43
43
|
|
|
44
|
-
|
|
45
|
-
the same context arrives through the rule files that harness loads at start —
|
|
46
|
-
see section 5 — which means it is as fresh as the last write, not as fresh as
|
|
47
|
-
the prompt. Say so plainly rather than letting someone assume parity.
|
|
44
|
+
Claude Code, Google Antigravity, and OpenAI Codex have native hook support, allowing memB to inject ambient memory per prompt across all three harnesses. For hookless harnesses (Cursor, Roo, OpenCode, Windsurf), the same context arrives through the rule files that harness loads at start — see section 5 — which means it is as fresh as the last write, not as fresh as the prompt. Say so plainly rather than letting someone assume parity.
|
|
48
45
|
|
|
49
46
|
---
|
|
50
47
|
|
|
@@ -173,7 +170,8 @@ injects the relevant memories as context. It fails open: any error exits `0`
|
|
|
173
170
|
and the prompt proceeds untouched.
|
|
174
171
|
|
|
175
172
|
Since v4.4.0 the installer ships `memb-inject.mjs` into `~/.claude/hooks/` and
|
|
176
|
-
wires it as
|
|
173
|
+
wires it as an automated prompt hook across Claude Code (`UserPromptSubmit` in `settings.json`),
|
|
174
|
+
Google Antigravity (`PreInvocation` in `hooks.json` / `.agents/hooks.json`), and OpenAI Codex (`UserPromptSubmit` in `config.toml`). **v4.4.0's Quick Update did not** — it
|
|
177
175
|
refreshes skills and submodules, and hooks are harness plumbing rather than
|
|
178
176
|
skills, so a machine that already had AOS updated to 4.4.0 without ever
|
|
179
177
|
receiving the hook. Fixed in v4.4.1; a machine that took that update needs one
|
|
@@ -183,7 +181,7 @@ more run:
|
|
|
183
181
|
npx -y @hybridlabor-api/aos@latest
|
|
184
182
|
```
|
|
185
183
|
|
|
186
|
-
The wiring is merged into `~/.claude/settings.json`, never written over
|
|
184
|
+
The wiring is merged into `~/.claude/settings.json`, Antigravity `hooks.json`, and Codex `config.toml`, never written over them:
|
|
187
185
|
user keys and foreign hook entries survive, and a re-run replaces the BDB entry
|
|
188
186
|
rather than adding a second copy.
|
|
189
187
|
|
|
@@ -199,7 +197,7 @@ harness — the memB store is machine-global, and pointing it at
|
|
|
199
197
|
`$CLAUDE_PROJECT_DIR` would make it fail on every prompt in any project the
|
|
200
198
|
harness was never installed into.
|
|
201
199
|
|
|
202
|
-
**On
|
|
200
|
+
**On hookless harnesses** — Cursor, Roo, OpenCode, Windsurf — native hooks are not supported, so the same
|
|
203
201
|
context is written into the rule files that harness loads instead:
|
|
204
202
|
|
|
205
203
|
```bash
|
|
@@ -163,7 +163,7 @@ function checkHooks() {
|
|
|
163
163
|
// the row would go green over a hook carrying a bug this version fixed.
|
|
164
164
|
// Hooks that carry an `aos-hook-version:` line are checked against what this
|
|
165
165
|
// release expects; the ones that do not are existence-only.
|
|
166
|
-
const EXPECTED_VERSION = { 'memb-inject.mjs':
|
|
166
|
+
const EXPECTED_VERSION = { 'memb-inject.mjs': 3 };
|
|
167
167
|
const versionOf = (text) => {
|
|
168
168
|
const m = /^\/\/\s*aos-hook-version:\s*(\d+)/m.exec(text);
|
|
169
169
|
return m ? Number(m[1]) : null;
|
|
@@ -195,6 +195,48 @@ function checkHooks() {
|
|
|
195
195
|
add('hooks', `${file} wired`, wired.includes(file), wired.includes(file) ? `present in ${event}` : `not referenced in ~/.claude/settings.json`,
|
|
196
196
|
'Add it under the matching hooks event in ~/.claude/settings.json (see this skill, section 4).');
|
|
197
197
|
}
|
|
198
|
+
|
|
199
|
+
// Antigravity hook wiring
|
|
200
|
+
const agDir = h('.gemini', 'antigravity-cli');
|
|
201
|
+
const agHooksCandidate = existsSync(path.join(agDir, 'hooks.json'))
|
|
202
|
+
? path.join(agDir, 'hooks.json')
|
|
203
|
+
: existsSync(h('.gemini', 'config', 'hooks.json'))
|
|
204
|
+
? h('.gemini', 'config', 'hooks.json')
|
|
205
|
+
: existsSync(h('.agents', 'hooks.json'))
|
|
206
|
+
? h('.agents', 'hooks.json')
|
|
207
|
+
: null;
|
|
208
|
+
|
|
209
|
+
if (existsSync(agDir) || existsSync(h('.gemini', 'config', 'skills')) || agHooksCandidate) {
|
|
210
|
+
const targetFile = agHooksCandidate || path.join(agDir, 'hooks.json');
|
|
211
|
+
if (existsSync(targetFile)) {
|
|
212
|
+
const agHooks = readJson(targetFile);
|
|
213
|
+
const agWired = JSON.stringify(agHooks?.hooks || {});
|
|
214
|
+
const hasMemb = agWired.includes('memb-inject.mjs');
|
|
215
|
+
add('hooks', 'Antigravity hooks.json wired', hasMemb,
|
|
216
|
+
hasMemb ? `wired in ${tilde(targetFile)}` : `memb-inject.mjs not wired in ${tilde(targetFile)}`,
|
|
217
|
+
'Run installer or mergeAntigravityHooks to wire hooks in hooks.json.');
|
|
218
|
+
} else {
|
|
219
|
+
add('hooks', 'Antigravity hooks.json', false, `missing ${tilde(targetFile)}`,
|
|
220
|
+
'Run installer to create and wire hooks.json for Antigravity.');
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// Codex hook wiring
|
|
225
|
+
const codexDir = h('.codex');
|
|
226
|
+
const codexConf = path.join(codexDir, 'config.toml');
|
|
227
|
+
if (existsSync(codexDir) || existsSync(codexConf)) {
|
|
228
|
+
if (existsSync(codexConf)) {
|
|
229
|
+
let toml = '';
|
|
230
|
+
try { toml = readFileSync(codexConf, 'utf8'); } catch {}
|
|
231
|
+
const hasMemb = toml.includes('memb-inject.mjs');
|
|
232
|
+
add('hooks', 'Codex config.toml wired', hasMemb,
|
|
233
|
+
hasMemb ? `wired in ${tilde(codexConf)}` : `memb-inject.mjs not wired in ${tilde(codexConf)}`,
|
|
234
|
+
'Run installer or mergeCodexTomlHooks to wire hooks in config.toml.');
|
|
235
|
+
} else {
|
|
236
|
+
add('hooks', 'Codex config.toml', false, `missing ${tilde(codexConf)}`,
|
|
237
|
+
'Run installer to create and wire config.toml for Codex.');
|
|
238
|
+
}
|
|
239
|
+
}
|
|
198
240
|
}
|
|
199
241
|
|
|
200
242
|
// ---------------------------------------------------------------- memB
|
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
$UserHome = [System.Environment]::GetFolderPath('UserProfile')
|
|
4
4
|
$ScriptPath = "$UserHome\.gemini\config\skills\openwiki-skill\scripts\openwiki_daemon.py"
|
|
5
5
|
$DaemonLogDir = "$UserHome\.openwiki"
|
|
6
|
+
$VenvDir = "$DaemonLogDir\venv"
|
|
7
|
+
$DaemonPython = ""
|
|
6
8
|
|
|
7
9
|
Write-Host "=========================================================" -ForegroundColor Cyan
|
|
8
10
|
Write-Host " Installing OpenWiki Background Daemon (Windows Task Scheduler)" -ForegroundColor Cyan
|
|
@@ -18,12 +20,73 @@ if (-not (Test-Path $ScriptPath)) {
|
|
|
18
20
|
}
|
|
19
21
|
}
|
|
20
22
|
|
|
21
|
-
# 2. Install Python dependency
|
|
22
|
-
Write-Host "Installing google-genai SDK..." -ForegroundColor Yellow
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
}
|
|
26
|
-
|
|
23
|
+
# 2. Install Python dependency into a dedicated venv
|
|
24
|
+
Write-Host "Installing google-genai SDK into $VenvDir ..." -ForegroundColor Yellow
|
|
25
|
+
if (-not (Test-Path $DaemonLogDir)) {
|
|
26
|
+
New-Item -ItemType Directory -Force -Path $DaemonLogDir | Out-Null
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
$VenvPython = Join-Path $VenvDir "Scripts\python.exe"
|
|
30
|
+
|
|
31
|
+
$UvCmd = Get-Command uv -ErrorAction SilentlyContinue
|
|
32
|
+
if ($UvCmd) {
|
|
33
|
+
try {
|
|
34
|
+
& uv venv "$VenvDir" 2>&1 | Out-Null
|
|
35
|
+
if (Test-Path $VenvPython) {
|
|
36
|
+
$InstallOutput = & uv pip install --python $VenvPython --quiet google-genai 2>&1
|
|
37
|
+
if ($LASTEXITCODE -eq 0) {
|
|
38
|
+
$DaemonPython = $VenvPython
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
} catch {}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if ([string]::IsNullOrWhiteSpace($DaemonPython)) {
|
|
45
|
+
$SysCmd = Get-Command python -ErrorAction SilentlyContinue
|
|
46
|
+
if ($SysCmd) {
|
|
47
|
+
$SysPython = if ($SysCmd.Path) { $SysCmd.Path } elseif ($SysCmd.Source) { $SysCmd.Source } else { "python" }
|
|
48
|
+
try {
|
|
49
|
+
& $SysPython -m venv "$VenvDir" 2>&1 | Out-Null
|
|
50
|
+
if (Test-Path $VenvPython) {
|
|
51
|
+
$InstallOutput = & $VenvPython -m pip install --quiet google-genai 2>&1
|
|
52
|
+
if ($LASTEXITCODE -eq 0) {
|
|
53
|
+
$DaemonPython = $VenvPython
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
} catch {}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if ([string]::IsNullOrWhiteSpace($DaemonPython)) {
|
|
61
|
+
Write-Host "Warning: could not install google-genai into $VenvDir." -ForegroundColor Yellow
|
|
62
|
+
Write-Host " Reason (last attempt):" -ForegroundColor Yellow
|
|
63
|
+
$SysCmd = Get-Command python -ErrorAction SilentlyContinue
|
|
64
|
+
if ($SysCmd) {
|
|
65
|
+
$SysPython = if ($SysCmd.Path) { $SysCmd.Path } elseif ($SysCmd.Source) { $SysCmd.Source } else { "python" }
|
|
66
|
+
if (Test-Path $VenvPython) {
|
|
67
|
+
$diagOutput = & $VenvPython -m pip install google-genai 2>&1
|
|
68
|
+
if ($diagOutput) {
|
|
69
|
+
$diagOutput | Select-Object -First 8 | ForEach-Object { Write-Host " $_" -ForegroundColor DarkGray }
|
|
70
|
+
}
|
|
71
|
+
} else {
|
|
72
|
+
$diagVenv = & $SysPython -m venv "$VenvDir" 2>&1
|
|
73
|
+
if ($diagVenv) {
|
|
74
|
+
$diagVenv | Select-Object -First 5 | ForEach-Object { Write-Host " $_" -ForegroundColor DarkGray }
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
} else {
|
|
78
|
+
Write-Host " python not found on PATH." -ForegroundColor DarkGray
|
|
79
|
+
}
|
|
80
|
+
Write-Host " The daemon will run in collect-only mode until this is resolved." -ForegroundColor Yellow
|
|
81
|
+
if (Test-Path $VenvPython) {
|
|
82
|
+
$DaemonPython = $VenvPython
|
|
83
|
+
} elseif ($cmd = Get-Command python -ErrorAction SilentlyContinue) {
|
|
84
|
+
$DaemonPython = if ($cmd.Path) { $cmd.Path } elseif ($cmd.Source) { $cmd.Source } else { "python" }
|
|
85
|
+
} else {
|
|
86
|
+
$DaemonPython = "python"
|
|
87
|
+
}
|
|
88
|
+
} else {
|
|
89
|
+
Write-Host " -> google-genai installed; daemon will run under $DaemonPython" -ForegroundColor Green
|
|
27
90
|
}
|
|
28
91
|
|
|
29
92
|
# 3. Resolve provider and API key
|
|
@@ -63,7 +126,10 @@ if ($OpenwikiProvider -eq "google") {
|
|
|
63
126
|
# and is discarded below.
|
|
64
127
|
$env:GEMINI_API_KEY = $ApiKey
|
|
65
128
|
$VerifyScript = Join-Path $PSScriptRoot "verify_api_key.py"
|
|
66
|
-
|
|
129
|
+
if (-not (Test-Path $VerifyScript)) {
|
|
130
|
+
$VerifyScript = Join-Path (Split-Path $ScriptPath -Parent) "verify_api_key.py"
|
|
131
|
+
}
|
|
132
|
+
$VerifyOutput = & $DaemonPython $VerifyScript 2>&1
|
|
67
133
|
$VerifyCode = $LASTEXITCODE
|
|
68
134
|
if ($VerifyCode -eq 0 -and ($VerifyOutput -match "VERIFIED_OK")) {
|
|
69
135
|
Write-Host " -> API key verified." -ForegroundColor Green
|
|
@@ -118,7 +184,7 @@ if (-not (Test-Path $DaemonLogDir)) {
|
|
|
118
184
|
# write the key in clear text into the .cmd under
|
|
119
185
|
# %APPDATA%\Microsoft\Windows\Start Menu\Programs\Startup\, readable by any
|
|
120
186
|
# process in the user context and routinely swept up by backups and sync folders.
|
|
121
|
-
$DaemonCommand = "& {
|
|
187
|
+
$DaemonCommand = "& { & '$DaemonPython' '$ScriptPath' --one-shot }"
|
|
122
188
|
$Action = New-ScheduledTaskAction -Execute "powershell.exe" -Argument "-NoProfile -WindowStyle Hidden -Command `"$DaemonCommand`""
|
|
123
189
|
|
|
124
190
|
# 6. Trigger: every 2 hours via repetition
|
|
@@ -151,7 +217,7 @@ function Install-StartupFallback {
|
|
|
151
217
|
Write-Host " * startup entry -> runs ONCE per logon (--one-shot)" -ForegroundColor Yellow
|
|
152
218
|
Write-Host " Documentation is refreshed only when you log in, or when you run" -ForegroundColor Yellow
|
|
153
219
|
Write-Host " the daemon manually:" -ForegroundColor Yellow
|
|
154
|
-
Write-Host "
|
|
220
|
+
Write-Host " & `"$DaemonPython`" `"$ScriptPath`" --one-shot" -ForegroundColor DarkGray
|
|
155
221
|
Write-Host " To get the 2-hour schedule, re-run this installer from an elevated" -ForegroundColor Yellow
|
|
156
222
|
Write-Host " PowerShell (Run as administrator)." -ForegroundColor Yellow
|
|
157
223
|
}
|
|
@@ -191,17 +257,40 @@ if ($BlockReason -ne "") {
|
|
|
191
257
|
Write-Host " a logon-only startup entry is used instead." -ForegroundColor DarkGray
|
|
192
258
|
}
|
|
193
259
|
Write-Host "Registering task '$TaskName'..." -ForegroundColor Yellow
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
260
|
+
|
|
261
|
+
$CurrentUserName = try { [System.Security.Principal.WindowsIdentity]::GetCurrent().Name } catch { $env:USERNAME }
|
|
262
|
+
$UserPrincipal = try {
|
|
263
|
+
New-ScheduledTaskPrincipal -UserId $CurrentUserName -LogonType Interactive
|
|
197
264
|
} catch {
|
|
198
|
-
$
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
265
|
+
$null
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
$TaskRegistered = $false
|
|
269
|
+
# First attempt: register using interactive user principal (needed for non-elevated users)
|
|
270
|
+
if ($UserPrincipal) {
|
|
271
|
+
try {
|
|
272
|
+
Register-ScheduledTask -TaskName $TaskName -Action $Action -Trigger $Trigger -Settings $Settings -Principal $UserPrincipal -Description "BDB OpenWiki Daemon - Gemma 4 API documentation generator" -Force -ErrorAction Stop | Out-Null
|
|
273
|
+
$TaskRegistered = $true
|
|
274
|
+
$Registered = $true
|
|
275
|
+
} catch {
|
|
276
|
+
Write-Verbose "Registration with interactive principal failed: $($_.Exception.Message). Trying default registration..."
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
# Second attempt: standard registration if principal registration was skipped or failed
|
|
281
|
+
if (-not $TaskRegistered) {
|
|
282
|
+
try {
|
|
283
|
+
Register-ScheduledTask -TaskName $TaskName -Action $Action -Trigger $Trigger -Settings $Settings -Description "BDB OpenWiki Daemon - Gemma 4 API documentation generator" -Force -ErrorAction Stop | Out-Null
|
|
284
|
+
$Registered = $true
|
|
285
|
+
} catch {
|
|
286
|
+
$FailureMessage = $_.Exception.Message
|
|
287
|
+
Write-Warning "Scheduled task registration failed ($FailureMessage)."
|
|
288
|
+
$Reason = "scheduled task registration failed: $FailureMessage"
|
|
289
|
+
if (-not $IsElevated) {
|
|
290
|
+
$Reason = "$Reason (administrator rights are likely required on this system)"
|
|
291
|
+
}
|
|
292
|
+
Install-StartupFallback -Command $DaemonCommand -Reason $Reason
|
|
203
293
|
}
|
|
204
|
-
Install-StartupFallback -Command $DaemonCommand -Reason $Reason
|
|
205
294
|
}
|
|
206
295
|
}
|
|
207
296
|
|