@hybridlabor-api/aos 4.17.0 → 4.18.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/aos-bus.mjs +8 -4
- package/.claude/hooks/go-gate.mjs +1 -1
- package/.claude/hooks/go-token.mjs +17 -2
- package/.claude/hooks/memb-inject.mjs +61 -37
- package/.codex-plugin/plugin.json +1 -1
- package/.opencode/commands/bdb-aos-plan.md +1 -1
- package/README.md +1 -0
- package/THIRD_PARTY_NOTICES.md +2 -2
- package/bin/aos-acp.mjs +27 -1
- package/bin/aos-doctor.mjs +36 -1
- package/bin/aos-uninstall.mjs +16 -2
- package/bin/go-check.mjs +79 -0
- package/bin/guarded-patterns.json +106 -0
- package/commands/plan.md +1 -1
- package/docs/codenotch.md +44 -0
- package/docs/codex-gate-smoke.md +43 -0
- package/docs/delegation-routing.md +32 -0
- package/docs/go-check.md +60 -0
- package/docs/master-session-acp.md +2 -0
- package/docs/opencode-setup.md +18 -0
- package/installer.js +155 -70
- package/lib/codenotch.js +389 -0
- package/lib/retired-skills.js +101 -0
- package/mcps/mcsc/README.md +1 -1
- package/mcps/mcsc/packages/core/src/adapters/agy.js +3 -1
- package/mcps/mcsc/packages/core/src/adapters/codex.js +2 -1
- package/mcps/mcsc/packages/core/src/adapters/opencode.js +2 -1
- package/mcps/mcsc/packages/core/src/depth.js +16 -0
- package/mcps/mcsc/packages/mcp/server.js +15 -2
- package/package.json +2 -2
- package/plugin-commands.json +1 -2
- package/plugin.json +1 -4
- package/plugins/bdb-aos-codex/.codex-plugin/plugin.json +1 -1
- package/plugins/bdb-aos-codex/skills/plan/SKILL.md +1 -1
- package/scripts/codex-gate-smoke.mjs +73 -0
- package/skills/basic/master-session/SKILL.md +11 -0
- package/skills/global_config/agenttrail/SKILL.md +3 -1
- package/skills/global_config/agenttrail/bin/agenttrail.mjs +255 -117
- package/skills/global_config/agenttrail/bin/ensure.mjs +60 -40
- package/skills/global_config/agenttrail/bin/repoid.mjs +70 -0
- package/skills/global_config/agenttrail/public/index.html +9 -1
- package/skills/global_config/aos-setup/scripts/aos-doctor.mjs +1 -1
- package/skills/global_config/bdb-memb-mcp/SKILL.md +5 -4
- package/skills/global_config/bdb-visual-edit/SKILL.md +28 -32
- package/skills/global_config/bdb-visual-edit/references/vite-react-source-attr.md +2 -2
- package/skills/global_config/bdb-visual-edit/scripts/locate-source.mjs +135 -0
- package/skills/global_config/bdb-visual-edit/scripts/sanitize-element.mjs +30 -2
- package/skills/global_config/mcsc/SKILL.md +9 -1
- package/skills/global_config/plan-arbiter/SKILL.md +1 -1
- package/skills/global_config/plan-canvas/SKILL.md +42 -4
- package/skills/global_config/plan-canvas/scripts/lib/plan-builder/README.md +1 -1
- package/skills/global_config/plan-canvas/scripts/lib/plan-builder/render.js +2 -2
- package/skills/global_config/plan-canvas/scripts/lib/plan-canvas/annotate-client/geometry.js +76 -0
- package/skills/global_config/plan-canvas/scripts/lib/plan-canvas/annotate-client/index.js +596 -0
- package/skills/global_config/plan-canvas/scripts/lib/plan-canvas/annotate-client/model.js +192 -0
- package/skills/global_config/plan-canvas/scripts/lib/plan-canvas/annotate-client/toolbar.js +99 -0
- package/skills/global_config/plan-canvas/scripts/lib/plan-canvas/annotate-server.js +282 -0
- package/skills/global_config/plan-canvas/scripts/lib/plan-canvas/annotation-schema.js +210 -0
- package/skills/global_config/plan-canvas/scripts/lib/plan-canvas/route.js +10 -0
- package/skills/global_config/plan-canvas/scripts/lib/plan-canvas/sdk.js +6 -230
- package/skills/global_config/plan-canvas/scripts/lib/plan-canvas/server.js +45 -4
- package/skills/global_config/plan-canvas/scripts/lib/plan-canvas/sessions.js +60 -21
- package/skills/global_config/plan-canvas/scripts/lib/plan-canvas/trail-on-approve.js +103 -0
- package/skills/global_config/plan-canvas/scripts/lib/plan-canvas/ui.js +19 -7
- package/skills/global_config/plan-canvas/scripts/plan-canvas.js +118 -20
- package/skills/global_config/subagent-setup/SKILL.md +6 -0
- package/skills/global_config/subagent-setup/scripts/setup-subagents.mjs +20 -1
- package/skills/playbooks/pb-idea-to-launch/SKILL.md +2 -2
- package/skills/playbooks/pb-redesign-app/SKILL.md +3 -3
- package/skills/playbooks/pb-release-aos/SKILL.md +2 -2
- package/skills/playbooks/pb-ship/SKILL.md +2 -2
- package/skills/playbooks/pb-worktrees-land/SKILL.md +2 -2
- package/skills/global_config/bdb-visual-edit/scripts/pick-snippet.js +0 -27
- package/skills/global_config/visual-edit/README.md +0 -96
- package/skills/global_config/visual-edit/SKILL.md +0 -615
- package/skills/global_config/visual-plan/README.md +0 -93
- package/skills/global_config/visual-plan/SKILL.md +0 -544
- package/skills/global_config/visual-plan/references/canvas.md +0 -139
- package/skills/global_config/visual-plan/references/connection.md +0 -51
- package/skills/global_config/visual-plan/references/document-quality.md +0 -186
- package/skills/global_config/visual-plan/references/exemplar.md +0 -62
- package/skills/global_config/visual-plan/references/local-files.md +0 -99
- package/skills/global_config/visual-plan/references/wireframe.md +0 -319
- package/skills/global_config/visual-recap/README.md +0 -103
- package/skills/global_config/visual-recap/SKILL.md +0 -560
- package/skills/global_config/visual-recap/references/connection.md +0 -51
- package/skills/global_config/visual-recap/references/local-files.md +0 -99
- package/skills/global_config/visual-recap/references/wireframe.md +0 -319
package/installer.js
CHANGED
|
@@ -24,6 +24,7 @@ const readline = require('readline');
|
|
|
24
24
|
const util = require('util');
|
|
25
25
|
const crypto = require('crypto');
|
|
26
26
|
const pluginMigration = require('./lib/plugin-migration');
|
|
27
|
+
const { pruneRetiredSkills } = require('./lib/retired-skills');
|
|
27
28
|
|
|
28
29
|
function verifyDaemonListening(port, name, timeoutMs = 4000) {
|
|
29
30
|
return new Promise((resolve) => {
|
|
@@ -378,6 +379,30 @@ function isNewerVersion(local, remote) {
|
|
|
378
379
|
return false;
|
|
379
380
|
}
|
|
380
381
|
|
|
382
|
+
// Newest dist-tag of `pkg` that is ahead of `localVer`: {tag, version}, or null when none is
|
|
383
|
+
// ahead or npm cannot be reached. `view` is injectable for tests.
|
|
384
|
+
function newestDistTag(pkg, localVer, view = null) {
|
|
385
|
+
try {
|
|
386
|
+
const npmCmd = process.platform === 'win32' ? 'npm.cmd' : 'npm';
|
|
387
|
+
const opts = { stdio: ['ignore', 'pipe', 'ignore'], encoding: 'utf8', timeout: 4000 };
|
|
388
|
+
const out = view
|
|
389
|
+
? view(pkg)
|
|
390
|
+
: process.platform === 'win32'
|
|
391
|
+
? execSync(`"${npmCmd}" view ${pkg} dist-tags --json`, opts)
|
|
392
|
+
: execFileSync(npmCmd, ['view', pkg, 'dist-tags', '--json'], opts);
|
|
393
|
+
const distTags = JSON.parse(String(out).trim());
|
|
394
|
+
let best = null;
|
|
395
|
+
for (const [tag, ver] of Object.entries(distTags || {})) {
|
|
396
|
+
if (typeof ver !== 'string' || !isNewerVersion(localVer, ver)) continue;
|
|
397
|
+
if (!best || isNewerVersion(best.version, ver)) best = { tag, version: ver };
|
|
398
|
+
}
|
|
399
|
+
return best;
|
|
400
|
+
} catch (e) {
|
|
401
|
+
logDebug(e, `npm view ${pkg}`);
|
|
402
|
+
return null;
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
|
|
381
406
|
function checkForUpdates() {
|
|
382
407
|
return new Promise((resolve) => {
|
|
383
408
|
const req = https.get(`https://registry.npmjs.org/${pkg.name}/latest`, { timeout: 1500 }, (res) => {
|
|
@@ -683,25 +708,6 @@ function initSessionManifest(existingManifest, sourceDirs) {
|
|
|
683
708
|
_sessionHashes = buildKnownSourceHashes(sourceDirs);
|
|
684
709
|
}
|
|
685
710
|
|
|
686
|
-
// Skills that left the package in 4.4.2 (Plan 02: migrated to the private
|
|
687
|
-
// aos-internal repo, per ~/dev/_plans/aos-2026-09-14/), by their flattened
|
|
688
|
-
// directory name at a sync destination.
|
|
689
|
-
//
|
|
690
|
-
// This is deliberately a fixed list, not a diff against what the current
|
|
691
|
-
// payload ships. A generic "anything on disk that is not in skills/ right
|
|
692
|
-
// now" pass was tried first and swept up two unrelated things: skill folders
|
|
693
|
-
// that MCP servers bundle inside their own package tree (e.g.
|
|
694
|
-
// mcps/tdmcp/.agents/skills/...), which happen to share the literal path
|
|
695
|
-
// segment "skills" but belong to a different install entirely; and skills
|
|
696
|
-
// under skills/workspace_agents/, which syncSkillsToGlobalHarnesses already
|
|
697
|
-
// deliberately excludes from the six global destinations, so a stray global
|
|
698
|
-
// copy of one says nothing about whether it is safe to delete. Both are real
|
|
699
|
-
// cleanup opportunities, but they are a separate investigation, not a side
|
|
700
|
-
// effect of this migration's beta test.
|
|
701
|
-
const SKILLS_REMOVED_IN_4_4_2 = new Set([
|
|
702
|
-
'bdbsaastraining', 'bdb-dev-os-skill', 'bdbsaashost', 'bdb-ecosystem-health', 'bdbsaas-ops',
|
|
703
|
-
]);
|
|
704
|
-
|
|
705
711
|
// The exact roots syncSkillsToGlobalHarnesses and the Gemini/Antigravity
|
|
706
712
|
// config-skills path write into. Pruning only touches a manifest entry whose
|
|
707
713
|
// path starts under one of these -- never one that merely contains a
|
|
@@ -718,51 +724,16 @@ function globalSkillDestRoots() {
|
|
|
718
724
|
];
|
|
719
725
|
}
|
|
720
726
|
|
|
721
|
-
//
|
|
722
|
-
//
|
|
723
|
-
// payload no longer ships. That is fine for new skills and updated ones, but
|
|
724
|
-
// it means a skill removed from a release stays on every user's disk
|
|
725
|
-
// forever, through every future update, because nothing after the removal
|
|
726
|
-
// ever looks at what is on disk that no longer has a source. This walks the
|
|
727
|
-
// install manifest -- which already has one entry per file this installer
|
|
728
|
-
// has ever placed -- for the specific skills 4.4.2 removed, under the six
|
|
729
|
-
// known global skill roots, and deletes them. A user-modified file is backed
|
|
730
|
-
// up first, the same way resolveFileConflict backs up a user edit it is
|
|
731
|
-
// about to overwrite, rather than silently deleting local changes.
|
|
727
|
+
// Retires skills the package no longer ships (lib/retired-skills.js). Edited or foreign files are
|
|
728
|
+
// copied to the backup dir before the skill folder is removed.
|
|
732
729
|
function pruneRemovedSkills(manifest) {
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
if (!root) continue;
|
|
741
|
-
const skillDirName = targetPath.slice(root.length + 1).split(path.sep)[0];
|
|
742
|
-
if (!SKILLS_REMOVED_IN_4_4_2.has(skillDirName)) continue;
|
|
743
|
-
|
|
744
|
-
if (fs.existsSync(targetPath)) {
|
|
745
|
-
const diskHash = computeFileHash(targetPath);
|
|
746
|
-
const manifestEntry = manifest[targetPath];
|
|
747
|
-
if (diskHash !== null && manifestEntry && diskHash !== manifestEntry.sha256) {
|
|
748
|
-
const bakPath = `${targetPath}.${timestamp}.bak`;
|
|
749
|
-
try { fs.copyFileSync(targetPath, bakPath); } catch (e) { logDebug(e, 'prune-removed-skill backup'); }
|
|
750
|
-
log.warn(`[manifest] Retired skill left a user-edited file, backed up to ${bakPath} instead of deleting it.`);
|
|
751
|
-
} else {
|
|
752
|
-
try { fs.unlinkSync(targetPath); removedFiles++; } catch (e) { logDebug(e, 'prune-removed-skill unlink'); }
|
|
753
|
-
}
|
|
754
|
-
staleDirs.add(path.join(root, skillDirName));
|
|
755
|
-
}
|
|
756
|
-
delete manifest[targetPath];
|
|
757
|
-
}
|
|
758
|
-
|
|
759
|
-
for (const dir of staleDirs) {
|
|
760
|
-
try { fs.rmSync(dir, { recursive: true, force: true }); } catch (e) { logDebug(e, 'prune-removed-skill rmdir'); }
|
|
761
|
-
}
|
|
762
|
-
|
|
763
|
-
if (staleDirs.size > 0) {
|
|
764
|
-
log.step(`Removed ${removedFiles} file(s) from ${staleDirs.size} retired skill install(s) no longer shipped.`);
|
|
765
|
-
}
|
|
730
|
+
pruneRetiredSkills({
|
|
731
|
+
home: homeDir,
|
|
732
|
+
manifest,
|
|
733
|
+
roots: globalSkillDestRoots(),
|
|
734
|
+
backupDir: path.join(homeDir, '.agents', 'backups', `retired-skills-${timestamp}`),
|
|
735
|
+
log,
|
|
736
|
+
});
|
|
766
737
|
}
|
|
767
738
|
|
|
768
739
|
function flushSessionManifest() {
|
|
@@ -4015,12 +3986,68 @@ const OPENCODE_LOOP_SHELL_WARNING = 'opencode-loop: /loop-shell style commands r
|
|
|
4015
3986
|
'tool.execute.before, and so the AOS go-gate, may never see them (unverified). ' +
|
|
4016
3987
|
'Do not schedule git push, publish or other gated commands through them.';
|
|
4017
3988
|
|
|
3989
|
+
let codenotchResult = null;
|
|
3990
|
+
async function maybeInstallCodenotch() {
|
|
3991
|
+
if (process.platform !== 'darwin' && process.platform !== 'win32') return;
|
|
3992
|
+
const codenotch = require('./lib/codenotch.js');
|
|
3993
|
+
codenotchResult = await codenotch.runCodenotchStep({
|
|
3994
|
+
interactive: !isAutoYes,
|
|
3995
|
+
dryRun: DRY_RUN,
|
|
3996
|
+
ask: async (message, initialValue = true) => { const a = await askConfirm({ message, initialValue }); return !isCancel(a) && !!a; },
|
|
3997
|
+
log: { info: (m) => log.info(m), warn: (m) => log.warn(m), success: (m) => log.success(m) },
|
|
3998
|
+
});
|
|
3999
|
+
const line = codenotch.codenotchSummaryLine(codenotchResult);
|
|
4000
|
+
if (line) (codenotchResult.status === 'error' || /FAILED/.test(line) ? log.warn : log.info)(line);
|
|
4001
|
+
}
|
|
4002
|
+
|
|
4018
4003
|
function parseOpencodeOptional(argv = process.argv, env = process.env) {
|
|
4019
4004
|
const flag = argv.find((a) => a.startsWith('--opencode-optional='));
|
|
4020
4005
|
const raw = [env.AOS_OPENCODE_OPTIONAL, flag && flag.slice('--opencode-optional='.length)].filter(Boolean).join(',');
|
|
4021
4006
|
return new Set(raw.split(',').map((x) => x.trim().toLowerCase()).filter(Boolean));
|
|
4022
4007
|
}
|
|
4023
4008
|
|
|
4009
|
+
// Opt-in OpenCode permission. Off unless AOS_OPENCODE_PERMISSION=external_directory or
|
|
4010
|
+
// --opencode-permission=external_directory. Only permission.external_directory is ever set,
|
|
4011
|
+
// as path patterns (object form verified in the OpenCode config schema; ~ expands per its docs).
|
|
4012
|
+
const OPENCODE_EXTERNAL_DIRECTORY_RULES = { '~/.agents/**': 'allow', '~/.config/opencode/**': 'allow' };
|
|
4013
|
+
|
|
4014
|
+
function parseOpencodePermission(argv = process.argv, env = process.env) {
|
|
4015
|
+
const flag = argv.find((a) => a.startsWith('--opencode-permission='));
|
|
4016
|
+
const raw = [env.AOS_OPENCODE_PERMISSION, flag && flag.slice('--opencode-permission='.length)].filter(Boolean).join(',');
|
|
4017
|
+
return new Set(raw.split(',').map((x) => x.trim().toLowerCase()).filter(Boolean));
|
|
4018
|
+
}
|
|
4019
|
+
|
|
4020
|
+
function applyOpencodePermission(data, configPath, wanted) {
|
|
4021
|
+
for (const name of wanted) {
|
|
4022
|
+
if (name !== 'external_directory') log.warn(`Unknown OpenCode permission "${name}" ignored.`);
|
|
4023
|
+
}
|
|
4024
|
+
if (!wanted.has('external_directory') || DRY_RUN) return;
|
|
4025
|
+
const perm = data.permission;
|
|
4026
|
+
if (perm !== undefined && (perm === null || typeof perm !== 'object' || Array.isArray(perm))) {
|
|
4027
|
+
log.warn('opencode.jsonc "permission" is not an object (string shorthand?); external_directory not set, left untouched.');
|
|
4028
|
+
return;
|
|
4029
|
+
}
|
|
4030
|
+
if (perm && 'external_directory' in perm) {
|
|
4031
|
+
if (JSON.stringify(perm.external_directory) !== JSON.stringify(OPENCODE_EXTERNAL_DIRECTORY_RULES)) {
|
|
4032
|
+
log.message('opencode.jsonc already has permission.external_directory; left untouched.');
|
|
4033
|
+
}
|
|
4034
|
+
return;
|
|
4035
|
+
}
|
|
4036
|
+
if (configPath && fs.existsSync(configPath)) {
|
|
4037
|
+
if (readJsoncFile(configPath) === null) {
|
|
4038
|
+
log.warn(`Could not parse ${configPath}; permission.external_directory not set.`);
|
|
4039
|
+
return;
|
|
4040
|
+
}
|
|
4041
|
+
const bak = `${configPath}.${timestamp}.bak`;
|
|
4042
|
+
try { fs.copyFileSync(configPath, bak); } catch (e) {
|
|
4043
|
+
log.warn(`Could not back up ${configPath}, skipping permission.external_directory: ${e.message}`);
|
|
4044
|
+
return;
|
|
4045
|
+
}
|
|
4046
|
+
}
|
|
4047
|
+
data.permission = Object.assign(perm || {}, { external_directory: { ...OPENCODE_EXTERNAL_DIRECTORY_RULES } });
|
|
4048
|
+
log.step('Added opt-in OpenCode permission.external_directory for AOS paths (comments in opencode.jsonc are not preserved on rewrite)');
|
|
4049
|
+
}
|
|
4050
|
+
|
|
4024
4051
|
const pluginPackageName = (entry) => {
|
|
4025
4052
|
const str = typeof entry === 'string' ? entry : (Array.isArray(entry) ? String(entry[0]) : '');
|
|
4026
4053
|
return str.replace(/(?<=.)@[^@/]*$/, '');
|
|
@@ -4108,7 +4135,7 @@ function installOpencodeCommands(srcDirPath, destDirPath) {
|
|
|
4108
4135
|
// Sync merges MCP servers in the same pass and writes once). When `data` is
|
|
4109
4136
|
// omitted the function loads and saves the config itself, which is what lets the
|
|
4110
4137
|
// Quick Update path register the plugin as well as copy it.
|
|
4111
|
-
function installOpencodePlugin({ targetHome = homeDir, configPath = null, data = null, optional = parseOpencodeOptional() } = {}) {
|
|
4138
|
+
function installOpencodePlugin({ targetHome = homeDir, configPath = null, data = null, optional = parseOpencodeOptional(), permission = parseOpencodePermission() } = {}) {
|
|
4112
4139
|
const opencodeDir = configPath
|
|
4113
4140
|
? path.dirname(configPath)
|
|
4114
4141
|
: (process.platform === 'win32'
|
|
@@ -4195,6 +4222,8 @@ function installOpencodePlugin({ targetHome = homeDir, configPath = null, data =
|
|
|
4195
4222
|
}
|
|
4196
4223
|
}
|
|
4197
4224
|
|
|
4225
|
+
applyOpencodePermission(data, configPath, permission instanceof Set ? permission : new Set(permission || []));
|
|
4226
|
+
|
|
4198
4227
|
if (ownsWrite) {
|
|
4199
4228
|
// Write only on a real change. readJsoncFile strips comments, so
|
|
4200
4229
|
// serialising an unchanged config would silently eat a user's comments
|
|
@@ -4284,6 +4313,26 @@ function installGlobalHooks({ targetHome = homeDir, targetGemini = geminiDir } =
|
|
|
4284
4313
|
|
|
4285
4314
|
// 5. Global CLI launcher binaries (aos-config, aos-dashboard, aos-uninstall)
|
|
4286
4315
|
installGlobalBinaries();
|
|
4316
|
+
|
|
4317
|
+
// 6. Fixed-path GO check for AO and other non-hook callers
|
|
4318
|
+
installGoCheck({ targetHome });
|
|
4319
|
+
}
|
|
4320
|
+
|
|
4321
|
+
// go-check.mjs is the fixed-path GO check for callers that are not a harness hook (AO).
|
|
4322
|
+
// It imports go-gate.mjs from its own directory, so both land in ~/.aos/bin, together with
|
|
4323
|
+
// the guarded patterns as JSON. Same conflict/backup rules as every other installed file.
|
|
4324
|
+
function installGoCheck({ targetHome = homeDir } = {}) {
|
|
4325
|
+
const dest = path.join(targetHome, '.aos', 'bin');
|
|
4326
|
+
const files = [
|
|
4327
|
+
[path.join(srcDir, 'bin', 'go-check.mjs'), 'go-check.mjs'],
|
|
4328
|
+
[path.join(srcDir, '.claude', 'hooks', 'go-gate.mjs'), 'go-gate.mjs'],
|
|
4329
|
+
[path.join(srcDir, 'bin', 'guarded-patterns.json'), 'guarded-patterns.json'],
|
|
4330
|
+
];
|
|
4331
|
+
if (!files.every(([src]) => fs.existsSync(src))) return false;
|
|
4332
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
4333
|
+
for (const [src, name] of files) copyDirRecursiveSync(src, path.join(dest, name));
|
|
4334
|
+
log.step(`Installed go-check to ${dest}`);
|
|
4335
|
+
return true;
|
|
4287
4336
|
}
|
|
4288
4337
|
|
|
4289
4338
|
function installGlobalBinaries() {
|
|
@@ -4620,6 +4669,21 @@ function mergeCodexTomlMcpServers(configTomlPath, servers) {
|
|
|
4620
4669
|
return skipped;
|
|
4621
4670
|
}
|
|
4622
4671
|
|
|
4672
|
+
// The go-gate PreToolUse stanza for Codex's config.toml. Whether it fires under `codex exec`
|
|
4673
|
+
// or under aos-acp is UNVERIFIED (docs/codex-gate-smoke.md).
|
|
4674
|
+
function codexGateSnippet(hooksDir) {
|
|
4675
|
+
return [
|
|
4676
|
+
'[[hooks.PreToolUse]]',
|
|
4677
|
+
'matcher = "^(Bash|run_command)$"',
|
|
4678
|
+
'[[hooks.PreToolUse.hooks]]',
|
|
4679
|
+
'type = "command"',
|
|
4680
|
+
`command = ${JSON.stringify(`node "${path.join(hooksDir, 'go-gate.mjs')}"`)}`,
|
|
4681
|
+
'timeout = 30',
|
|
4682
|
+
].join('\n');
|
|
4683
|
+
}
|
|
4684
|
+
|
|
4685
|
+
const CODEX_GATE_NOTICE = 'Codex asks you to trust new or changed hooks before it runs them; approve the go-gate hook in Codex, or it stays inactive. Firing under `codex exec` and under aos-acp is UNVERIFIED: run the smoke test in docs/codex-gate-smoke.md.';
|
|
4686
|
+
|
|
4623
4687
|
// Merge the BDB hooks into ChatGPT Codex CLI's config.toml (~/.codex/config.toml or
|
|
4624
4688
|
// .codex/config.toml), ensuring [features] hooks = true and preserving existing
|
|
4625
4689
|
// non-BDB settings, comments, and MCP servers.
|
|
@@ -4631,12 +4695,7 @@ function mergeCodexTomlHooks(configTomlPath, { projectLocal = false } = {}) {
|
|
|
4631
4695
|
|
|
4632
4696
|
const tomlSnippet = [
|
|
4633
4697
|
'# AOS:HOOKS:START',
|
|
4634
|
-
|
|
4635
|
-
'matcher = "^(Bash|run_command)$"',
|
|
4636
|
-
'[[hooks.PreToolUse.hooks]]',
|
|
4637
|
-
'type = "command"',
|
|
4638
|
-
`command = ${JSON.stringify(`node "${path.join(hooksDir, 'go-gate.mjs')}"`)}`,
|
|
4639
|
-
'timeout = 30',
|
|
4698
|
+
codexGateSnippet(hooksDir),
|
|
4640
4699
|
'',
|
|
4641
4700
|
'[[hooks.Stop]]',
|
|
4642
4701
|
'[[hooks.Stop.hooks]]',
|
|
@@ -5770,6 +5829,7 @@ async function runQuickUpdate(installState) {
|
|
|
5770
5829
|
|
|
5771
5830
|
console.log('');
|
|
5772
5831
|
verifyEcosystemInstallation();
|
|
5832
|
+
await maybeInstallCodenotch();
|
|
5773
5833
|
// Fresh installs open this via universalHarnessSync(); Quick Update never
|
|
5774
5834
|
// did, so a dev-workflow machine only ever saw it once, on day one --
|
|
5775
5835
|
// every subsequent run is a Quick Update, which is what almost every
|
|
@@ -5852,6 +5912,10 @@ async function main() {
|
|
|
5852
5912
|
console.log(pkg.version);
|
|
5853
5913
|
return;
|
|
5854
5914
|
}
|
|
5915
|
+
if (args.includes('--codex-gate')) {
|
|
5916
|
+
console.log(`${codexGateSnippet(path.join(homeDir, '.codex', 'hooks'))}\n\n${CODEX_GATE_NOTICE}`);
|
|
5917
|
+
return;
|
|
5918
|
+
}
|
|
5855
5919
|
if (args.includes('--help') || args.includes('-h') || args[0] === 'help') {
|
|
5856
5920
|
console.log(`Usage: aos [command] [options]
|
|
5857
5921
|
|
|
@@ -5860,6 +5924,8 @@ Commands:
|
|
|
5860
5924
|
doctor|checkup Check the installation
|
|
5861
5925
|
|
|
5862
5926
|
Options:
|
|
5927
|
+
--codex-gate Print the go-gate [[hooks.PreToolUse]] stanza for ~/.codex/config.toml
|
|
5928
|
+
and the Codex hook-trust note, then exit (writes nothing)
|
|
5863
5929
|
-y, --yes Non-interactive install (implied without a TTY)
|
|
5864
5930
|
--dry-run Show what would change
|
|
5865
5931
|
--opencode-optional=LIST
|
|
@@ -5867,6 +5933,18 @@ Options:
|
|
|
5867
5933
|
AOS_OPENCODE_OPTIONAL. Pinned plugin[] entries are appended after a
|
|
5868
5934
|
config backup; rtk only prints a brew hint. Off by default. AOS never
|
|
5869
5935
|
runs foreign installers and never touches OpenCode's mcp set.
|
|
5936
|
+
--no-codenotch macOS and Windows only (never Linux): BDB AO Codenotch (desktop app,
|
|
5937
|
+
from hybridlabor-api/bdb-ao-codenotch) installs by default;
|
|
5938
|
+
skip it with this flag or AOS_CODENOTCH=0. --codenotch or
|
|
5939
|
+
AOS_CODENOTCH=1 forces it. Interactive prompt defaults to yes. Failures
|
|
5940
|
+
only warn and never fail the install. SHA-256 verified; Windows runs
|
|
5941
|
+
the per-user installer silently (/S, no admin). Never overwrites an app
|
|
5942
|
+
AOS did not install. See docs/codenotch.md.
|
|
5943
|
+
--opencode-permission=external_directory
|
|
5944
|
+
Opt in to OpenCode's permission.external_directory for ~/.agents and
|
|
5945
|
+
~/.config/opencode only (path patterns, allow), or set
|
|
5946
|
+
AOS_OPENCODE_PERMISSION. Existing keys are never overwritten; a string
|
|
5947
|
+
"permission" is refused. Config backed up first. Off by default.
|
|
5870
5948
|
--plugin-migration=off|check
|
|
5871
5949
|
Skip (off) or only report (check) the bdb-aos plugin registration and
|
|
5872
5950
|
removal of AOS's own loose skill copies; same as AOS_PLUGIN_MIGRATION.
|
|
@@ -6281,6 +6359,7 @@ Options:
|
|
|
6281
6359
|
|
|
6282
6360
|
console.log('');
|
|
6283
6361
|
verifyEcosystemInstallation();
|
|
6362
|
+
await maybeInstallCodenotch();
|
|
6284
6363
|
|
|
6285
6364
|
outro(`🎉 Installation complete! Targets: ${targets.map(t => t.value).join(', ')}${aosCliRequested ? ' + AOS CLI' : ''} · Tier: ${tier === '1' ? 'Pro MEDIA' : 'Basic'}${DRY_RUN ? ' · DRY-RUN (nothing was modified)' : ''}`);
|
|
6286
6365
|
}
|
|
@@ -6291,6 +6370,8 @@ if (require.main === module) {
|
|
|
6291
6370
|
|
|
6292
6371
|
// Exported for tests -- requiring installer.js must not launch the TUI.
|
|
6293
6372
|
module.exports = {
|
|
6373
|
+
newestDistTag,
|
|
6374
|
+
verifyEcosystemInstallation,
|
|
6294
6375
|
installBinaryAtomically,
|
|
6295
6376
|
installOSAgentWorkspace,
|
|
6296
6377
|
readGoBuildInfo,
|
|
@@ -6317,9 +6398,13 @@ module.exports = {
|
|
|
6317
6398
|
mergeCodexHooks: mergeCodexTomlHooks,
|
|
6318
6399
|
mergeCodexTomlMcpServers,
|
|
6319
6400
|
installGlobalHooks,
|
|
6401
|
+
installGoCheck,
|
|
6402
|
+
codexGateSnippet,
|
|
6403
|
+
CODEX_GATE_NOTICE,
|
|
6320
6404
|
installOpencodePlugin,
|
|
6321
6405
|
installOpencodeCommands,
|
|
6322
6406
|
parseOpencodeOptional,
|
|
6407
|
+
maybeInstallCodenotch,
|
|
6323
6408
|
pluginMigrationMode,
|
|
6324
6409
|
runPluginMigration,
|
|
6325
6410
|
installProjectHarness,
|