@hybridlabor-api/aos 4.13.2 → 4.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/AGENTS.md +8 -0
- package/.agents/nodes.json +5 -2
- package/.claude/hooks/conventional-commits.mjs +14 -15
- package/.claude/hooks/env-file-protection.mjs +14 -15
- package/.claude/hooks/go-gate.mjs +152 -10
- package/.claude/hooks/go-token.mjs +55 -0
- package/.claude/hooks/memb-inject.mjs +75 -62
- package/.claude/hooks/trail-autostart.mjs +27 -0
- package/.claude/settings.json +18 -0
- package/.claude/workflows/startcycle-dispatch.mjs +11 -4
- package/.opencode/plugins/bdb-aos.js +98 -121
- package/.opencode/plugins/lib/trail-autostart.js +38 -0
- package/CLAUDE.md +1 -1
- package/README.de.md +6 -6
- package/README.md +6 -6
- package/README.pt.md +6 -6
- package/THIRD_PARTY_NOTICES.md +19 -3
- package/assets/header-v5.png +0 -0
- package/bin/aos-acp.mjs +211 -0
- package/bin/aos-doctor.mjs +1 -1
- package/bin/aos-uninstall.mjs +2 -2
- package/docs/master-session-acp.md +51 -0
- package/installer.js +252 -35
- package/mcps/mcsc/packages/mcp/server.js +6 -7
- package/package.json +4 -3
- package/scripts/validate-skills.mjs +76 -0
- package/skills/basic/bdbmediastorm/SKILL.md +1 -1
- package/skills/basic/godmode-shipping/SKILL.md +3 -0
- package/skills/basic/master-session/SKILL.md +89 -0
- package/skills/basic/startcycle/SKILL.md +1 -1
- package/skills/basic/startcycle-graph/SKILL.md +2 -2
- package/skills/basic/startcycle-graph-user/SKILL.md +1 -1
- package/skills/basic/teamwork-preview/SKILL.md +1 -1
- package/skills/bdbrainstorm/SKILL.md +7 -1
- package/skills/global_config/agentic-harness-patterns/SKILL.md +257 -0
- package/skills/global_config/agentic-harness-patterns/metadata.json +10 -0
- package/skills/global_config/agentic-harness-patterns/references/agent-orchestration-pattern.md +97 -0
- package/skills/global_config/agentic-harness-patterns/references/bootstrap-sequence-pattern.md +106 -0
- package/skills/global_config/agentic-harness-patterns/references/context-engineering/compress-pattern.md +78 -0
- package/skills/global_config/agentic-harness-patterns/references/context-engineering/isolate-pattern.md +82 -0
- package/skills/global_config/agentic-harness-patterns/references/context-engineering/select-pattern.md +86 -0
- package/skills/global_config/agentic-harness-patterns/references/context-engineering-pattern.md +29 -0
- package/skills/global_config/agentic-harness-patterns/references/hook-lifecycle-pattern.md +111 -0
- package/skills/global_config/agentic-harness-patterns/references/memory-persistence-pattern.md +109 -0
- package/skills/global_config/agentic-harness-patterns/references/permission-gate-pattern.md +111 -0
- package/skills/global_config/agentic-harness-patterns/references/skill-runtime-pattern.md +104 -0
- package/skills/global_config/agentic-harness-patterns/references/task-decomposition-pattern.md +92 -0
- package/skills/global_config/agentic-harness-patterns/references/tool-registry-pattern.md +101 -0
- package/skills/global_config/agenttrail/SKILL.md +8 -0
- package/skills/global_config/agenttrail/bin/agenttrail.mjs +14 -0
- package/skills/global_config/agenttrail/bin/ensure.mjs +118 -0
- package/skills/global_config/aos-setup/scripts/aos-doctor.mjs +1 -1
- package/skills/global_config/bdb-visual-edit/SKILL.md +51 -0
- package/skills/global_config/bdb-visual-edit/references/vite-react-source-attr.md +59 -0
- package/skills/global_config/bdb-visual-edit/scripts/pick-snippet.js +27 -0
- package/skills/global_config/bdb-visual-edit/scripts/sanitize-element.mjs +123 -0
- package/skills/global_config/factory-collect/SKILL.md +74 -0
- package/skills/global_config/factory-human-digest/SKILL.md +92 -0
- package/skills/global_config/factory-lookback/SKILL.md +95 -0
- package/skills/global_config/factory-review-prs/SKILL.md +63 -0
- package/skills/global_config/git-pr-review/SKILL.md +3 -0
- package/skills/global_config/grilling/SKILL.md +2 -0
- package/skills/global_config/mcsc/SKILL.md +1 -1
- package/skills/global_config/plan-arbiter/SKILL.md +125 -0
- package/skills/global_config/plan-canvas/SKILL.md +62 -5
- package/skills/global_config/plan-canvas/scripts/lib/loopback-guard.js +19 -3
- package/skills/global_config/plan-canvas/scripts/lib/plan-builder/README.md +285 -0
- package/skills/global_config/plan-canvas/scripts/lib/plan-builder/agent-trail.js +129 -0
- package/skills/global_config/plan-canvas/scripts/lib/plan-builder/board-client.js +124 -0
- package/skills/global_config/plan-canvas/scripts/lib/plan-builder/examples/demo-plan/canvas.mdx +19 -0
- package/skills/global_config/plan-canvas/scripts/lib/plan-builder/examples/demo-plan/plan.mdx +18 -0
- package/skills/global_config/plan-canvas/scripts/lib/plan-builder/examples/recap-demo/plan.mdx +72 -0
- package/skills/global_config/plan-canvas/scripts/lib/plan-builder/examples/showcase/README.md +29 -0
- package/skills/global_config/plan-canvas/scripts/lib/plan-builder/examples/showcase/architecture.json +30 -0
- package/skills/global_config/plan-canvas/scripts/lib/plan-builder/examples/showcase/builder/00_architecture.html +14950 -0
- package/skills/global_config/plan-canvas/scripts/lib/plan-builder/examples/showcase/builder/canvas.mdx +511 -0
- package/skills/global_config/plan-canvas/scripts/lib/plan-builder/examples/showcase/builder/plan.mdx +208 -0
- package/skills/global_config/plan-canvas/scripts/lib/plan-builder/examples/showcase/recap/plan.mdx +102 -0
- package/skills/global_config/plan-canvas/scripts/lib/plan-builder/examples/showcase/standard/plan.md +136 -0
- package/skills/global_config/plan-canvas/scripts/lib/plan-builder/examples/signup-storyboard/canvas.mdx +124 -0
- package/skills/global_config/plan-canvas/scripts/lib/plan-builder/examples/signup-storyboard/plan.mdx +37 -0
- package/skills/global_config/plan-canvas/scripts/lib/plan-builder/index.js +188 -0
- package/skills/global_config/plan-canvas/scripts/lib/plan-builder/kit.js +123 -0
- package/skills/global_config/plan-canvas/scripts/lib/plan-builder/mdx.js +411 -0
- package/skills/global_config/plan-canvas/scripts/lib/plan-builder/render.js +1291 -0
- package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/architecture/meta.json +1 -0
- package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/architecture/plan.mdx +195 -0
- package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/architecture/standard.md +95 -0
- package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/bugfix/meta.json +1 -0
- package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/bugfix/plan.mdx +105 -0
- package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/bugfix/standard.md +76 -0
- package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/feature/canvas.mdx +81 -0
- package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/feature/meta.json +1 -0
- package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/feature/plan.mdx +145 -0
- package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/feature/standard.md +76 -0
- package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/migration/meta.json +1 -0
- package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/migration/plan.mdx +172 -0
- package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/migration/standard.md +100 -0
- package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/recap/meta.json +1 -0
- package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/recap/plan.mdx +67 -0
- package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/recap/standard.md +49 -0
- package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/recap-board/canvas.mdx +63 -0
- package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/recap-board/meta.json +1 -0
- package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/recap-board/plan.mdx +49 -0
- package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/recap-board/standard.md +39 -0
- package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/recap-review/meta.json +1 -0
- package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/recap-review/plan.mdx +118 -0
- package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/recap-review/standard.md +57 -0
- package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/release/meta.json +1 -0
- package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/release/plan.mdx +173 -0
- package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/release/standard.md +96 -0
- package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/research/meta.json +1 -0
- package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/research/plan.mdx +91 -0
- package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/research/standard.md +54 -0
- package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/show-control/canvas.mdx +53 -0
- package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/show-control/meta.json +1 -0
- package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/show-control/plan.mdx +225 -0
- package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/show-control/standard.md +111 -0
- package/skills/global_config/plan-canvas/scripts/lib/plan-builder/theme.css +472 -0
- package/skills/global_config/plan-canvas/scripts/lib/plan-builder/trail.js +216 -0
- package/skills/global_config/plan-canvas/scripts/lib/plan-canvas/markdown.js +1 -1
- package/skills/global_config/plan-canvas/scripts/lib/plan-canvas/server.js +37 -4
- package/skills/global_config/plan-canvas/scripts/lib/plan-canvas/ui.js +125 -29
- package/skills/global_config/plan-canvas/scripts/plan-canvas.js +196 -8
- package/skills/global_config/pr-recap/SKILL.md +47 -0
- package/skills/global_config/pr-recap/scripts/pr-recap.mjs +200 -0
- package/skills/global_config/quick-recap/SKILL.md +55 -0
- package/skills/global_config/stay-within-limits/SKILL.md +85 -0
- package/skills/global_config/triage/SKILL.md +3 -0
- package/skills/global_config/visual-edit/README.md +96 -0
- package/skills/global_config/visual-edit/SKILL.md +615 -0
- package/skills/global_config/visual-plan/README.md +93 -0
- package/skills/global_config/visual-plan/SKILL.md +544 -0
- package/skills/global_config/visual-plan/references/canvas.md +139 -0
- package/skills/global_config/visual-plan/references/connection.md +51 -0
- package/skills/global_config/visual-plan/references/document-quality.md +186 -0
- package/skills/global_config/visual-plan/references/exemplar.md +62 -0
- package/skills/global_config/visual-plan/references/local-files.md +99 -0
- package/skills/global_config/visual-plan/references/wireframe.md +319 -0
- package/skills/global_config/visual-recap/README.md +103 -0
- package/skills/global_config/visual-recap/SKILL.md +560 -0
- package/skills/global_config/visual-recap/references/connection.md +51 -0
- package/skills/global_config/visual-recap/references/local-files.md +99 -0
- package/skills/global_config/visual-recap/references/wireframe.md +319 -0
- package/skills/playbooks/pb-ci-fix/SKILL.md +49 -0
- package/skills/playbooks/pb-event-tracker/SKILL.md +45 -0
- package/skills/playbooks/pb-meeting-actions/SKILL.md +42 -0
- package/skills/playbooks/pb-project-new/SKILL.md +48 -0
- package/skills/playbooks/pb-week-plan/SKILL.md +45 -0
- package/assets/header-v4.jpg +0 -0
package/installer.js
CHANGED
|
@@ -2609,10 +2609,7 @@ async function installOSAgentWorkspace() {
|
|
|
2609
2609
|
if (daemonBin !== binTarget) {
|
|
2610
2610
|
installStep('place the ao binary', () => {
|
|
2611
2611
|
fs.mkdirSync(localBinDir, { recursive: true });
|
|
2612
|
-
|
|
2613
|
-
if (!isWin) {
|
|
2614
|
-
fs.chmodSync(binTarget, 0o755);
|
|
2615
|
-
}
|
|
2612
|
+
installBinaryAtomically(daemonBin, binTarget);
|
|
2616
2613
|
log.step(`Installed ao to ${binTarget}`);
|
|
2617
2614
|
}, 'AO cannot be started without its binary.');
|
|
2618
2615
|
}
|
|
@@ -3320,7 +3317,16 @@ async function installMcpsForTarget(paths, ctx) {
|
|
|
3320
3317
|
// spaces) rather than matching the first alphanumeric run anywhere in the
|
|
3321
3318
|
// block, so it can't accidentally pick up a word from prose if the heading
|
|
3322
3319
|
// format changes.
|
|
3323
|
-
function
|
|
3320
|
+
function loadCommonSkills(dir = srcDir) {
|
|
3321
|
+
try {
|
|
3322
|
+
const reg = JSON.parse(fs.readFileSync(path.join(dir, '.agents', 'nodes.json'), 'utf8'));
|
|
3323
|
+
return Array.isArray(reg.common) ? reg.common.filter((s) => typeof s === 'string') : [];
|
|
3324
|
+
} catch {
|
|
3325
|
+
return [];
|
|
3326
|
+
}
|
|
3327
|
+
}
|
|
3328
|
+
|
|
3329
|
+
function parseAgentsMd(content, commonSkills = loadCommonSkills()) {
|
|
3324
3330
|
const blocks = content.split(/\n## /).slice(1);
|
|
3325
3331
|
const agents = [];
|
|
3326
3332
|
for (const raw of blocks) {
|
|
@@ -3350,7 +3356,7 @@ function parseAgentsMd(content) {
|
|
|
3350
3356
|
name,
|
|
3351
3357
|
role: roleMatch[1].trim(),
|
|
3352
3358
|
model: modelMatch ? modelMatch[1].trim() : null,
|
|
3353
|
-
skills: extractListAfter('Primary Skills'),
|
|
3359
|
+
skills: [...new Set([...extractListAfter('Primary Skills'), ...commonSkills])],
|
|
3354
3360
|
mcpServers: extractListAfter('MCP Servers'),
|
|
3355
3361
|
output: outputMatch ? outputMatch[1].trim() : null,
|
|
3356
3362
|
systemPrompt: raw.trim(),
|
|
@@ -3768,6 +3774,21 @@ function installOpencodePlugin({ targetHome = homeDir, configPath = null, data =
|
|
|
3768
3774
|
}
|
|
3769
3775
|
}
|
|
3770
3776
|
|
|
3777
|
+
// The plugin imports its decision logic from ./aos-hooks/ next to itself.
|
|
3778
|
+
const hooksSrc = path.join(srcDir, '.claude', 'hooks');
|
|
3779
|
+
if (fs.existsSync(hooksSrc)) {
|
|
3780
|
+
try {
|
|
3781
|
+
copyDirRecursiveSync(hooksSrc, path.join(opencodeDir, 'plugins', 'aos-hooks'));
|
|
3782
|
+
} catch (e) {
|
|
3783
|
+
log.error(`Could not install OpenCode plugin hooks (OpenCode gates inactive): ${e.message}`);
|
|
3784
|
+
}
|
|
3785
|
+
}
|
|
3786
|
+
|
|
3787
|
+
const trailLibSrc = path.join(srcDir, '.opencode', 'plugins', 'lib');
|
|
3788
|
+
if (fs.existsSync(trailLibSrc)) {
|
|
3789
|
+
try { copyDirRecursiveSync(trailLibSrc, path.join(opencodeDir, 'plugins', 'lib')); } catch (e) { log.warn(`Could not install OpenCode plugin lib: ${e.message}`); }
|
|
3790
|
+
}
|
|
3791
|
+
|
|
3771
3792
|
// Slash-command payloads. Without these the /startcycle-graph command has no
|
|
3772
3793
|
// native resolution and only survives as a raw-text match in the plugin.
|
|
3773
3794
|
const commandsSrc = path.join(srcDir, '.opencode', 'commands');
|
|
@@ -3966,14 +3987,14 @@ function installGlobalBinaries() {
|
|
|
3966
3987
|
// merged result goes to a .bdb-new.json sidecar -- the same recovery pattern
|
|
3967
3988
|
// the MCP config merge in installMcpsForTarget uses.
|
|
3968
3989
|
function mergeBdbSettingsHooks(settingsPath, { projectLocal = false } = {}) {
|
|
3969
|
-
const bdbHookScripts = ['go-gate.mjs', 'graph-gate.mjs', 'memb-inject.mjs', 'trail-relay.mjs', 'conventional-commits.mjs', 'env-file-protection.mjs'];
|
|
3990
|
+
const bdbHookScripts = ['go-gate.mjs', 'go-token.mjs', 'graph-gate.mjs', 'memb-inject.mjs', 'trail-relay.mjs', 'trail-autostart.mjs', 'conventional-commits.mjs', 'env-file-protection.mjs'];
|
|
3970
3991
|
// memb-inject reads the machine-global memB store under $HOME and is
|
|
3971
3992
|
// installed once per machine, so it stays $HOME-anchored even inside a
|
|
3972
3993
|
// project harness -- unlike the two gate hooks, which are per-checkout by
|
|
3973
3994
|
// design. Pointing it at $CLAUDE_PROJECT_DIR would make it fail on every
|
|
3974
3995
|
// prompt in any project the harness was never installed into. trail-relay
|
|
3975
3996
|
// talks to machine-global live-map daemons, so it is anchored the same way.
|
|
3976
|
-
const machineGlobalHooks = ['memb-inject.mjs', 'trail-relay.mjs'];
|
|
3997
|
+
const machineGlobalHooks = ['memb-inject.mjs', 'trail-relay.mjs', 'trail-autostart.mjs'];
|
|
3977
3998
|
const isBdbEntry = (entry) => {
|
|
3978
3999
|
const cmds = (entry && Array.isArray(entry.hooks) ? entry.hooks : [])
|
|
3979
4000
|
.map((h) => (h && typeof h.command === 'string' ? h.command : ''))
|
|
@@ -4050,60 +4071,64 @@ function mergeBdbSettingsHooks(settingsPath, { projectLocal = false } = {}) {
|
|
|
4050
4071
|
// ~/.gemini/config/hooks.json), preserving user-defined foreign hooks.
|
|
4051
4072
|
function mergeAntigravityHooks(hooksPath, { projectLocal = false } = {}) {
|
|
4052
4073
|
const bdbHookScripts = ['go-gate.mjs', 'graph-gate.mjs', 'memb-inject.mjs', 'startcycle-dispatch.mjs', 'trail-relay.mjs', 'conventional-commits.mjs', 'env-file-protection.mjs'];
|
|
4053
|
-
const
|
|
4054
|
-
const cmds = (entry && Array.isArray(entry.hooks) ? entry.hooks : [entry])
|
|
4055
|
-
.map((h) => (h && typeof h.command === 'string' ? h.command : (typeof h === 'string' ? h : '')))
|
|
4056
|
-
.join(' ');
|
|
4057
|
-
return bdbHookScripts.some((name) => cmds.includes(name));
|
|
4058
|
-
};
|
|
4074
|
+
const isBdbHandler = (h) => typeof h?.command === 'string' && bdbHookScripts.some((name) => h.command.includes(name));
|
|
4059
4075
|
|
|
4060
4076
|
const baseDir = path.dirname(hooksPath);
|
|
4061
4077
|
const hooksDir = projectLocal ? path.join(currentDir, '.agents', 'hooks') : path.join(baseDir, 'hooks');
|
|
4062
4078
|
const workflowsDir = projectLocal ? path.join(currentDir, '.agents', 'workflows') : path.join(baseDir, 'workflows');
|
|
4063
4079
|
const globalHooksDir = projectLocal ? path.join(homeDir, '.gemini', 'config', 'hooks') : hooksDir;
|
|
4064
4080
|
|
|
4081
|
+
const cmd = (dir, script, args = '') => `node "${path.join(dir, script)}"${args}`;
|
|
4065
4082
|
const bdbHooks = {
|
|
4066
4083
|
PreToolUse: [
|
|
4067
4084
|
{
|
|
4068
4085
|
matcher: "run_command|Bash",
|
|
4069
4086
|
hooks: [
|
|
4070
|
-
{ type: "command", command:
|
|
4071
|
-
{ type: "command", command:
|
|
4087
|
+
{ type: "command", command: cmd(hooksDir, 'go-gate.mjs'), timeout: 10 },
|
|
4088
|
+
{ type: "command", command: cmd(hooksDir, 'conventional-commits.mjs'), timeout: 10 }
|
|
4072
4089
|
]
|
|
4073
4090
|
},
|
|
4074
4091
|
{
|
|
4075
4092
|
matcher: "write_file|edit_file|replace|Write|Edit|MultiEdit",
|
|
4076
|
-
hooks: [{ type: "command", command:
|
|
4093
|
+
hooks: [{ type: "command", command: cmd(hooksDir, 'env-file-protection.mjs'), timeout: 10 }]
|
|
4077
4094
|
},
|
|
4078
4095
|
{
|
|
4079
|
-
|
|
4096
|
+
matcher: "*",
|
|
4097
|
+
hooks: [{ type: "command", command: cmd(globalHooksDir, 'trail-relay.mjs', ' --agent agy --event PreToolUse'), timeout: 2 }]
|
|
4080
4098
|
}
|
|
4081
4099
|
],
|
|
4082
4100
|
Stop: [
|
|
4083
|
-
{
|
|
4084
|
-
|
|
4085
|
-
},
|
|
4086
|
-
{
|
|
4087
|
-
hooks: [{ type: "command", command: `node "${path.join(globalHooksDir, 'trail-relay.mjs')}" --agent agy --event Stop`, timeout: 2000 }]
|
|
4088
|
-
}
|
|
4101
|
+
{ type: "command", command: cmd(hooksDir, 'graph-gate.mjs'), timeout: 10 },
|
|
4102
|
+
{ type: "command", command: cmd(globalHooksDir, 'trail-relay.mjs', ' --agent agy --event Stop'), timeout: 2 }
|
|
4089
4103
|
],
|
|
4090
4104
|
PreInvocation: [
|
|
4091
|
-
{
|
|
4092
|
-
|
|
4093
|
-
{ type: "command", command: `node "${path.join(globalHooksDir, 'memb-inject.mjs')}"`, timeout: 8000 },
|
|
4094
|
-
{ type: "command", command: `node "${path.join(workflowsDir, 'startcycle-dispatch.mjs')}"`, timeout: 30000 }
|
|
4095
|
-
]
|
|
4096
|
-
}
|
|
4105
|
+
{ type: "command", command: cmd(globalHooksDir, 'memb-inject.mjs'), timeout: 8 },
|
|
4106
|
+
{ type: "command", command: cmd(workflowsDir, 'startcycle-dispatch.mjs'), timeout: 30 }
|
|
4097
4107
|
]
|
|
4098
4108
|
};
|
|
4099
4109
|
|
|
4110
|
+
// Drops BDB handlers (old wrapped or current shape), keeps foreign ones, and
|
|
4111
|
+
// rewraps flat events so previously written `{ hooks: [...] }` entries migrate.
|
|
4112
|
+
const keepForeign = (event, entries) => {
|
|
4113
|
+
const out = [];
|
|
4114
|
+
for (const e of Array.isArray(entries) ? entries : []) {
|
|
4115
|
+
const nested = e && Array.isArray(e.hooks);
|
|
4116
|
+
if (bdbHooks[event][0].hooks) {
|
|
4117
|
+
if (!nested) { if (!isBdbHandler(e)) out.push(e); continue; }
|
|
4118
|
+
const kept = e.hooks.filter((h) => !isBdbHandler(h));
|
|
4119
|
+
if (kept.length) out.push({ ...e, hooks: kept });
|
|
4120
|
+
} else {
|
|
4121
|
+
out.push(...(nested ? e.hooks : [e]).filter((h) => !isBdbHandler(h)));
|
|
4122
|
+
}
|
|
4123
|
+
}
|
|
4124
|
+
return out;
|
|
4125
|
+
};
|
|
4126
|
+
|
|
4100
4127
|
const buildMerged = (existing) => {
|
|
4101
4128
|
const merged = existing && typeof existing === 'object' ? existing : {};
|
|
4102
4129
|
merged.hooks = merged.hooks && typeof merged.hooks === 'object' ? merged.hooks : {};
|
|
4103
4130
|
for (const [event, entries] of Object.entries(bdbHooks)) {
|
|
4104
|
-
|
|
4105
|
-
.filter((e) => !isBdbEntry(e));
|
|
4106
|
-
merged.hooks[event] = [...foreignEntries, ...entries];
|
|
4131
|
+
merged.hooks[event] = [...keepForeign(event, merged.hooks[event]), ...entries];
|
|
4107
4132
|
}
|
|
4108
4133
|
return merged;
|
|
4109
4134
|
};
|
|
@@ -4135,7 +4160,9 @@ function mergeAntigravityHooks(hooksPath, { projectLocal = false } = {}) {
|
|
|
4135
4160
|
|
|
4136
4161
|
try {
|
|
4137
4162
|
fs.mkdirSync(path.dirname(hooksPath), { recursive: true });
|
|
4138
|
-
|
|
4163
|
+
const tmpPath = `${hooksPath}.${process.pid}.tmp`;
|
|
4164
|
+
fs.writeFileSync(tmpPath, JSON.stringify(buildMerged(existing), null, 2) + '\n');
|
|
4165
|
+
fs.renameSync(tmpPath, hooksPath);
|
|
4139
4166
|
} catch (e) {
|
|
4140
4167
|
log.warn(`Could not write ${hooksPath}: ${e.message}`);
|
|
4141
4168
|
}
|
|
@@ -4510,6 +4537,107 @@ function shouldAutostartLaunchpad(overrides = {}) {
|
|
|
4510
4537
|
return isDevEnvironment(overrides);
|
|
4511
4538
|
}
|
|
4512
4539
|
|
|
4540
|
+
// Plan Canvas autostart is strictly opt-in (--autostart-plan-canvas): unlike
|
|
4541
|
+
// the launchpad opener it is NOT implied by a dev checkout. The server never
|
|
4542
|
+
// idle-exits there (AOS_PLAN_CANVAS_IDLE_MS=0 is honoured by server.js).
|
|
4543
|
+
const PLAN_CANVAS_LABEL = 'com.bdb.plan-canvas';
|
|
4544
|
+
|
|
4545
|
+
function shouldAutostartPlanCanvas(overrides = {}) {
|
|
4546
|
+
const argv = overrides.argv || process.argv;
|
|
4547
|
+
return argv.includes('--autostart-plan-canvas');
|
|
4548
|
+
}
|
|
4549
|
+
|
|
4550
|
+
function buildPlanCanvasPlist({ nodeBin, scriptPath, home, logDir }) {
|
|
4551
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
4552
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
4553
|
+
<plist version="1.0">
|
|
4554
|
+
<dict>
|
|
4555
|
+
<key>Label</key>
|
|
4556
|
+
<string>${PLAN_CANVAS_LABEL}</string>
|
|
4557
|
+
<key>ProgramArguments</key>
|
|
4558
|
+
<array>
|
|
4559
|
+
<string>${nodeBin}</string>
|
|
4560
|
+
<string>${scriptPath}</string>
|
|
4561
|
+
<string>server</string>
|
|
4562
|
+
</array>
|
|
4563
|
+
<key>EnvironmentVariables</key>
|
|
4564
|
+
<dict>
|
|
4565
|
+
<key>AOS_PLAN_CANVAS_IDLE_MS</key>
|
|
4566
|
+
<string>0</string>
|
|
4567
|
+
</dict>
|
|
4568
|
+
<key>WorkingDirectory</key>
|
|
4569
|
+
<string>${home}</string>
|
|
4570
|
+
<key>RunAtLoad</key>
|
|
4571
|
+
<true/>
|
|
4572
|
+
<key>KeepAlive</key>
|
|
4573
|
+
<true/>
|
|
4574
|
+
<key>ThrottleInterval</key>
|
|
4575
|
+
<integer>30</integer>
|
|
4576
|
+
<key>StandardOutPath</key>
|
|
4577
|
+
<string>${path.join(logDir, 'plan-canvas.stdout.log')}</string>
|
|
4578
|
+
<key>StandardErrorPath</key>
|
|
4579
|
+
<string>${path.join(logDir, 'plan-canvas.stderr.log')}</string>
|
|
4580
|
+
</dict>
|
|
4581
|
+
</plist>`;
|
|
4582
|
+
}
|
|
4583
|
+
|
|
4584
|
+
// Same bat + hidden-vbs-in-Startup mechanism as the OpenWiki visualizer.
|
|
4585
|
+
function buildPlanCanvasWinFiles({ nodeBin, scriptPath, home, logDir, batPath }) {
|
|
4586
|
+
const out = path.join(logDir, 'plan-canvas.stdout.log');
|
|
4587
|
+
const err = path.join(logDir, 'plan-canvas.stderr.log');
|
|
4588
|
+
return {
|
|
4589
|
+
bat: `@echo off\r\ncd /d "${home}"\r\nset AOS_PLAN_CANVAS_IDLE_MS=0\r\n"${nodeBin}" "${scriptPath}" server >> "${out}" 2>> "${err}"\r\n`,
|
|
4590
|
+
vbs: `Set WshShell = CreateObject("WScript.Shell")\r\nWshShell.CurrentDirectory = "${home}"\r\nWshShell.Run """${batPath}""", 0, False\r\n`,
|
|
4591
|
+
};
|
|
4592
|
+
}
|
|
4593
|
+
|
|
4594
|
+
function installPlanCanvasAutostart(overrides = {}) {
|
|
4595
|
+
if (!shouldAutostartPlanCanvas(overrides)) return false;
|
|
4596
|
+
if ((overrides.dryRun ?? DRY_RUN)) {
|
|
4597
|
+
log.step('[dry-run] would register the Plan Canvas background server (Port 4519, no idle exit)');
|
|
4598
|
+
return false;
|
|
4599
|
+
}
|
|
4600
|
+
const home = overrides.homeDir || homeDir;
|
|
4601
|
+
const platform = overrides.platform || process.platform;
|
|
4602
|
+
const scriptPath = [
|
|
4603
|
+
path.join(home, '.agents', 'skills', 'plan-canvas', 'scripts', 'plan-canvas.js'),
|
|
4604
|
+
path.join(srcDir, 'skills', 'global_config', 'plan-canvas', 'scripts', 'plan-canvas.js'),
|
|
4605
|
+
].find(p => fs.existsSync(p));
|
|
4606
|
+
if (!scriptPath) {
|
|
4607
|
+
log.warn('Plan Canvas autostart skipped: plan-canvas.js not found. Start it with: aos-plan-canvas server');
|
|
4608
|
+
return false;
|
|
4609
|
+
}
|
|
4610
|
+
const nodeBin = overrides.nodeBin || process.execPath;
|
|
4611
|
+
const logDir = path.join(home, '.agents', 'logs');
|
|
4612
|
+
try {
|
|
4613
|
+
fs.mkdirSync(logDir, { recursive: true });
|
|
4614
|
+
if (platform === 'darwin') {
|
|
4615
|
+
const plistPath = path.join(home, 'Library', 'LaunchAgents', `${PLAN_CANVAS_LABEL}.plist`);
|
|
4616
|
+
fs.mkdirSync(path.dirname(plistPath), { recursive: true });
|
|
4617
|
+
fs.writeFileSync(plistPath, buildPlanCanvasPlist({ nodeBin, scriptPath, home, logDir }));
|
|
4618
|
+
if (!overrides.skipLaunchctl) {
|
|
4619
|
+
execSync(`launchctl unload "${plistPath}" 2>/dev/null || true`, { stdio: 'ignore' });
|
|
4620
|
+
execSync(`launchctl load -w "${plistPath}" 2>/dev/null || true`, { stdio: 'ignore' });
|
|
4621
|
+
}
|
|
4622
|
+
log.success('Plan Canvas LaunchAgent registered (Port 4519)');
|
|
4623
|
+
} else if (platform === 'win32') {
|
|
4624
|
+
const startupDir = path.join(overrides.appData || process.env.APPDATA || path.join(home, 'AppData', 'Roaming'), 'Microsoft', 'Windows', 'Start Menu', 'Programs', 'Startup');
|
|
4625
|
+
fs.mkdirSync(startupDir, { recursive: true });
|
|
4626
|
+
const batPath = path.join(home, '.agents', 'run-plan-canvas.bat');
|
|
4627
|
+
const vbsPath = path.join(startupDir, `${PLAN_CANVAS_LABEL}.vbs`);
|
|
4628
|
+
const files = buildPlanCanvasWinFiles({ nodeBin, scriptPath, home, logDir, batPath });
|
|
4629
|
+
fs.writeFileSync(batPath, files.bat, 'utf-8');
|
|
4630
|
+
fs.writeFileSync(vbsPath, files.vbs, 'utf-8');
|
|
4631
|
+
if (!overrides.skipLaunchctl) spawn('wscript.exe', [vbsPath], { detached: true, stdio: 'ignore' }).unref();
|
|
4632
|
+
log.success('Plan Canvas Startup entry registered (Port 4519)');
|
|
4633
|
+
} else {
|
|
4634
|
+
log.step('Plan Canvas autostart is only wired for macOS and Windows. Start it with: aos-plan-canvas server');
|
|
4635
|
+
return false;
|
|
4636
|
+
}
|
|
4637
|
+
return true;
|
|
4638
|
+
} catch (e) { logDebug(e, 'plan canvas autostart'); return false; }
|
|
4639
|
+
}
|
|
4640
|
+
|
|
4513
4641
|
function generateAndOpenLaunchpad(installedModules = []) {
|
|
4514
4642
|
if (DRY_RUN) {
|
|
4515
4643
|
log.step('[dry-run] would generate & open BDB Launchpad HTML');
|
|
@@ -4645,6 +4773,16 @@ function generateAndOpenLaunchpad(installedModules = []) {
|
|
|
4645
4773
|
.card.offline .card-hint {
|
|
4646
4774
|
display: block;
|
|
4647
4775
|
}
|
|
4776
|
+
.card-hint code {
|
|
4777
|
+
font-family: var(--mono);
|
|
4778
|
+
font-style: normal;
|
|
4779
|
+
color: #ffffff;
|
|
4780
|
+
background: #0a0a0a;
|
|
4781
|
+
border: 1px solid var(--accent);
|
|
4782
|
+
border-radius: 4px;
|
|
4783
|
+
padding: 1px 6px;
|
|
4784
|
+
cursor: copy;
|
|
4785
|
+
}
|
|
4648
4786
|
.footer {
|
|
4649
4787
|
margin-top: 28px;
|
|
4650
4788
|
text-align: center;
|
|
@@ -4835,6 +4973,25 @@ function generateAndOpenLaunchpad(installedModules = []) {
|
|
|
4835
4973
|
<span class="status-dot" id="dot-store" title="Checking..."></span>
|
|
4836
4974
|
</div>
|
|
4837
4975
|
</a>
|
|
4976
|
+
<a class="card" href="http://127.0.0.1:4519/" target="_blank">
|
|
4977
|
+
<div class="card-content">
|
|
4978
|
+
<div class="card-icon"><svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
|
|
4979
|
+
<defs><linearGradient id="grad-plancanvas" x1="50%" y1="0%" x2="50%" y2="100%"><stop offset="0%" stop-color="#FFFFFF"/><stop offset="100%" stop-color="#9b30c4"/></linearGradient></defs>
|
|
4980
|
+
<rect x="18" y="22" width="64" height="56" rx="4" fill="url(#grad-plancanvas)" opacity="0.85"/>
|
|
4981
|
+
<rect x="26" y="30" width="22" height="14" rx="1.5" fill="#0a0a0a" opacity="0.6"/><rect x="52" y="30" width="22" height="14" rx="1.5" fill="#0a0a0a" opacity="0.6"/>
|
|
4982
|
+
<line x1="26" y1="54" x2="74" y2="54" stroke="#0a0a0a" stroke-width="2.5" opacity="0.5"/><line x1="26" y1="64" x2="56" y2="64" stroke="#0a0a0a" stroke-width="2.5" opacity="0.5"/>
|
|
4983
|
+
</svg></div>
|
|
4984
|
+
<div class="card-info">
|
|
4985
|
+
<h2>Plan Canvas</h2>
|
|
4986
|
+
<p>Review plans in the browser: annotate, chat, approve</p>
|
|
4987
|
+
<div class="card-hint">offline — run: <code data-copy="aos-plan-canvas server" title="Click to copy">aos-plan-canvas server</code></div>
|
|
4988
|
+
</div>
|
|
4989
|
+
</div>
|
|
4990
|
+
<div class="card-meta">
|
|
4991
|
+
<span class="port-pill">:4519</span>
|
|
4992
|
+
<span class="status-dot" id="dot-plancanvas" title="Checking..."></span>
|
|
4993
|
+
</div>
|
|
4994
|
+
</a>
|
|
4838
4995
|
</div>
|
|
4839
4996
|
<div class="footer">
|
|
4840
4997
|
<span>Autostart Daemons • 127.0.0.1</span>
|
|
@@ -4862,7 +5019,26 @@ function generateAndOpenLaunchpad(installedModules = []) {
|
|
|
4862
5019
|
checkHealth('http://127.0.0.1:9080', 'dot-remote');
|
|
4863
5020
|
checkHealth('http://127.0.0.1:4321', 'dot-openwiki');
|
|
4864
5021
|
checkHealth('http://127.0.0.1:4322', 'dot-store');
|
|
4865
|
-
|
|
5022
|
+
checkHealth('http://127.0.0.1:4519', 'dot-plancanvas');
|
|
5023
|
+
}
|
|
5024
|
+
document.addEventListener('click', (ev) => {
|
|
5025
|
+
const el = ev.target.closest && ev.target.closest('[data-copy]');
|
|
5026
|
+
if (!el) return;
|
|
5027
|
+
ev.preventDefault();
|
|
5028
|
+
ev.stopPropagation();
|
|
5029
|
+
const text = el.getAttribute('data-copy');
|
|
5030
|
+
const fallback = () => {
|
|
5031
|
+
const ta = document.createElement('textarea');
|
|
5032
|
+
ta.value = text;
|
|
5033
|
+
document.body.appendChild(ta);
|
|
5034
|
+
ta.select();
|
|
5035
|
+
try { document.execCommand('copy'); } catch (e) {}
|
|
5036
|
+
ta.remove();
|
|
5037
|
+
};
|
|
5038
|
+
if (navigator.clipboard && navigator.clipboard.writeText) navigator.clipboard.writeText(text).catch(fallback);
|
|
5039
|
+
else fallback();
|
|
5040
|
+
el.title = 'Copied';
|
|
5041
|
+
}, true);
|
|
4866
5042
|
checkAllHealth();
|
|
4867
5043
|
setInterval(checkAllHealth, 5000);
|
|
4868
5044
|
</script>
|
|
@@ -5075,6 +5251,7 @@ async function universalHarnessSync(primaryMcpConfigPath, installedModules = [])
|
|
|
5075
5251
|
}
|
|
5076
5252
|
log.success('Universal Sync Complete!');
|
|
5077
5253
|
generateAndOpenLaunchpad(installedModules);
|
|
5254
|
+
installPlanCanvasAutostart();
|
|
5078
5255
|
}
|
|
5079
5256
|
|
|
5080
5257
|
async function runQuickUpdate(installState) {
|
|
@@ -5241,7 +5418,41 @@ function installAosCli() {
|
|
|
5241
5418
|
}
|
|
5242
5419
|
}
|
|
5243
5420
|
|
|
5421
|
+
// A running daemon may execute dest; overwriting its inode keeps stale code-signature
|
|
5422
|
+
// state on macOS and every new exec dies with SIGKILL. Rename gives dest a fresh inode.
|
|
5423
|
+
function installBinaryAtomically(src, dest) {
|
|
5424
|
+
const tmp = path.join(path.dirname(dest), `.${path.basename(dest)}.${process.pid}.${Date.now()}.tmp`);
|
|
5425
|
+
try {
|
|
5426
|
+
fs.copyFileSync(src, tmp);
|
|
5427
|
+
if (process.platform !== 'win32') fs.chmodSync(tmp, 0o755);
|
|
5428
|
+
fs.renameSync(tmp, dest);
|
|
5429
|
+
} catch (e) {
|
|
5430
|
+
try { fs.unlinkSync(tmp); } catch (_) {}
|
|
5431
|
+
throw e;
|
|
5432
|
+
}
|
|
5433
|
+
}
|
|
5434
|
+
|
|
5244
5435
|
async function main() {
|
|
5436
|
+
const args = process.argv.slice(2);
|
|
5437
|
+
if (args.includes('--version') || args.includes('-V')) {
|
|
5438
|
+
console.log(pkg.version);
|
|
5439
|
+
return;
|
|
5440
|
+
}
|
|
5441
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
5442
|
+
console.log(`Usage: aos [command] [options]
|
|
5443
|
+
|
|
5444
|
+
Commands:
|
|
5445
|
+
store Browse and install skills
|
|
5446
|
+
doctor|checkup Check the installation
|
|
5447
|
+
|
|
5448
|
+
Options:
|
|
5449
|
+
-y, --yes Non-interactive install (implied without a TTY)
|
|
5450
|
+
--dry-run Show what would change
|
|
5451
|
+
--verbose, -v Verbose output
|
|
5452
|
+
-V, --version Print the version and exit
|
|
5453
|
+
-h, --help Print this help and exit`);
|
|
5454
|
+
return;
|
|
5455
|
+
}
|
|
5245
5456
|
if (process.argv[2] === 'store') {
|
|
5246
5457
|
const storeScript = path.join(srcDir, 'bin', 'aos-store.mjs');
|
|
5247
5458
|
const result = spawnSync(process.execPath, [storeScript, ...process.argv.slice(3)], { stdio: 'inherit' });
|
|
@@ -5695,6 +5906,7 @@ if (require.main === module) {
|
|
|
5695
5906
|
|
|
5696
5907
|
// Exported for tests -- requiring installer.js must not launch the TUI.
|
|
5697
5908
|
module.exports = {
|
|
5909
|
+
installBinaryAtomically,
|
|
5698
5910
|
installOSAgentWorkspace,
|
|
5699
5911
|
downloadOrUpdateModule,
|
|
5700
5912
|
detectPlatforms,
|
|
@@ -5726,6 +5938,7 @@ module.exports = {
|
|
|
5726
5938
|
INSTALL_MANIFEST_PATH,
|
|
5727
5939
|
// Agent compilers & pipeline helpers
|
|
5728
5940
|
parseAgentsMd,
|
|
5941
|
+
loadCommonSkills,
|
|
5729
5942
|
compileClaudeAgents,
|
|
5730
5943
|
compileOpenCodeAgents,
|
|
5731
5944
|
compileCodexAgents,
|
|
@@ -5736,6 +5949,10 @@ module.exports = {
|
|
|
5736
5949
|
generateAndOpenLaunchpad,
|
|
5737
5950
|
shouldOpenLaunchpad,
|
|
5738
5951
|
shouldAutostartLaunchpad,
|
|
5952
|
+
shouldAutostartPlanCanvas,
|
|
5953
|
+
buildPlanCanvasPlist,
|
|
5954
|
+
buildPlanCanvasWinFiles,
|
|
5955
|
+
installPlanCanvasAutostart,
|
|
5739
5956
|
isDevEnvironment,
|
|
5740
5957
|
LAUNCHPAD_WEB_MODULES,
|
|
5741
5958
|
LAUNCHPAD_OPEN_FLAGS,
|
|
@@ -64,16 +64,15 @@ async function init() {
|
|
|
64
64
|
|
|
65
65
|
const customRulebook = path.resolve(process.cwd(), 'rulebook.yaml');
|
|
66
66
|
const defaultRulebook = path.resolve(__dirname, '../core/rulebook.default.yaml');
|
|
67
|
-
const rulebookPath = fs.existsSync(customRulebook) ? customRulebook : defaultRulebook;
|
|
68
67
|
|
|
69
68
|
try {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
69
|
+
rules = await loadRulebook({
|
|
70
|
+
defaultsPath: defaultRulebook,
|
|
71
|
+
overridePath: fs.existsSync(customRulebook) ? customRulebook : undefined,
|
|
72
|
+
});
|
|
73
|
+
offerTable = await buildOfferTable(rules, inventory, Date.now());
|
|
75
74
|
} catch (e) {
|
|
76
|
-
console.error(`[mcsc-mcp] Warning: could not load rulebook from ${
|
|
75
|
+
console.error(`[mcsc-mcp] Warning: could not load rulebook from ${defaultRulebook}: ${e.message}`);
|
|
77
76
|
}
|
|
78
77
|
}
|
|
79
78
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hybridlabor-api/aos",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.14.0",
|
|
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": {
|
|
@@ -18,7 +18,8 @@
|
|
|
18
18
|
"aos-config": "bin/aos-config.mjs",
|
|
19
19
|
"aos-store": "bin/aos-store.mjs",
|
|
20
20
|
"aos-doctor": "bin/aos-doctor.mjs",
|
|
21
|
-
"aos-uninstall": "bin/aos-uninstall.mjs"
|
|
21
|
+
"aos-uninstall": "bin/aos-uninstall.mjs",
|
|
22
|
+
"aos-acp": "bin/aos-acp.mjs"
|
|
22
23
|
},
|
|
23
24
|
"scripts": {
|
|
24
25
|
"validate": "node scripts/validate-skills.mjs",
|
|
@@ -27,7 +28,7 @@
|
|
|
27
28
|
"plugin:build": "node scripts/build-plugin-manifest.mjs",
|
|
28
29
|
"plugin:check": "node scripts/build-plugin-manifest.mjs --check",
|
|
29
30
|
"doctor": "node bin/aos-doctor.mjs",
|
|
30
|
-
"test": "node scripts/validate-skills.mjs --selftest && node scripts/validate-skills.mjs && node scripts/build-plugin-manifest.mjs --check && node --test tests/opencode-graph-gate.test.js && node --test tests/cross-harness-hooks.test.js && node tests/aos-store.test.mjs && node --test tests/aos-store-ui.test.mjs && node tests/aos-store-scenario.test.mjs && node tests/aos-doctor.test.mjs && node tests/build-plugin-manifest.test.mjs && node --test tests/agent-models.test.js && node --test tests/installer-p3.test.js"
|
|
31
|
+
"test": "node scripts/validate-skills.mjs --selftest && node scripts/validate-skills.mjs && node scripts/build-plugin-manifest.mjs --check && node --test tests/opencode-graph-gate.test.js && node --test tests/cross-harness-hooks.test.js && node --test tests/plan-canvas-security.test.mjs && node --test tests/plan-canvas-modes.test.mjs && node --test tests/swarm-wiring.test.js && node tests/aos-store.test.mjs && node --test tests/aos-store-ui.test.mjs && node tests/aos-store-scenario.test.mjs && node tests/aos-doctor.test.mjs && node tests/build-plugin-manifest.test.mjs && node --test tests/agent-models.test.js && node --test tests/installer-p3.test.js && node --test tests/installer-binary.test.js && node --test tests/installer-version.test.js && node --test tests/mcsc-server.test.js && node --test tests/antigravity-hooks.test.js && node --test tests/plan-builder.test.mjs && node --test tests/plan-builder-trail.test.mjs && node --test tests/plan-builder-showcase.test.mjs && node --test tests/plan-builder-templates.test.mjs && node --test tests/plan-canvas-home.test.mjs && node --test tests/launchpad-installer.test.js && node --test tests/launchpad-plan-canvas.test.js && node --test tests/go-token.test.js && node --test tests/master-session-skill.test.js && node --test tests/aos-acp.test.js && node --test tests/opencode-go-token.test.js && node --test tests/opencode-adapter.test.js && node --test tests/pr-recap.test.mjs && node --test tests/bdb-visual-edit.test.mjs && node --test tests/opencode-trail-autostart.test.mjs && node --test tests/trail-autostart-hook.test.mjs && node --test tests/agenttrail-ensure.test.mjs"
|
|
31
32
|
},
|
|
32
33
|
"publishConfig": {
|
|
33
34
|
"access": "public"
|
|
@@ -241,6 +241,45 @@ function checkSkillRefs(text, file, known, self, findings) {
|
|
|
241
241
|
}
|
|
242
242
|
}
|
|
243
243
|
|
|
244
|
+
// Playbooks are skills with `kind: playbook`; skills without `kind` are untouched.
|
|
245
|
+
const PB_REQUIRED = ['trigger', 'inputs', 'requires', 'go_points', 'outputs', 'verify', 'difficulty', 'est_time', 'disable-model-invocation'];
|
|
246
|
+
const DIFFICULTY = new Set(['beginner', 'intermediate', 'advanced']);
|
|
247
|
+
const EXTERNAL = ' (external)';
|
|
248
|
+
|
|
249
|
+
export function checkPlaybook(byKey, known) {
|
|
250
|
+
const out = [];
|
|
251
|
+
if (!byKey.has('kind')) return out;
|
|
252
|
+
const add = (code, msg, key) => out.push({ level: 'error', code, line: byKey.get(key)?.line, msg });
|
|
253
|
+
const kind = unquote(byKey.get('kind').value);
|
|
254
|
+
if (kind !== 'playbook') {
|
|
255
|
+
add('E-PB01', `\`kind: ${kind}\` is unknown — the only defined kind is \`playbook\``, 'kind');
|
|
256
|
+
return out;
|
|
257
|
+
}
|
|
258
|
+
for (const k of PB_REQUIRED) if (!byKey.has(k)) add('E-PB03', `playbook is missing required key \`${k}\``, 'kind');
|
|
259
|
+
|
|
260
|
+
const req = byKey.get('requires');
|
|
261
|
+
if (req) {
|
|
262
|
+
const m = /(?:^|\s)skills:\s*\[([^\]]*)\]/.exec(req.value);
|
|
263
|
+
if (!m) add('E-PB05', '`requires.skills` must be a flow-style list, e.g. `skills: [github, ci-pipeline]`', 'requires');
|
|
264
|
+
else {
|
|
265
|
+
for (const raw of m[1].split(',').map((e) => unquote(e)).filter(Boolean)) {
|
|
266
|
+
if (!raw.endsWith(EXTERNAL) && !known.has(raw)) {
|
|
267
|
+
add('E-PB02', `requires skill \`${raw}\`, which is not a skill in this repo — fix the name or mark it \`${raw}${EXTERNAL}\``, 'requires');
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
const diff = byKey.get('difficulty');
|
|
273
|
+
if (diff && !DIFFICULTY.has(unquote(diff.value))) {
|
|
274
|
+
add('E-PB04', `\`difficulty: ${unquote(diff.value)}\` is not one of: ${[...DIFFICULTY].join(', ')}`, 'difficulty');
|
|
275
|
+
}
|
|
276
|
+
const dmi = byKey.get('disable-model-invocation');
|
|
277
|
+
if (dmi && unquote(dmi.value) !== 'true') {
|
|
278
|
+
add('E-PB06', 'playbooks are user-invoked only — set `disable-model-invocation: true`', 'disable-model-invocation');
|
|
279
|
+
}
|
|
280
|
+
return out;
|
|
281
|
+
}
|
|
282
|
+
|
|
244
283
|
function validate() {
|
|
245
284
|
const { skills, strays } = collect();
|
|
246
285
|
const known = new Set(skills.map((f) => basename(dirname(f))));
|
|
@@ -311,6 +350,8 @@ function validate() {
|
|
|
311
350
|
}
|
|
312
351
|
}
|
|
313
352
|
|
|
353
|
+
for (const f of checkPlaybook(byKey, known)) findings.push({ ...f, file: rel });
|
|
354
|
+
|
|
314
355
|
checkLeakedPaths(text, rel, findings);
|
|
315
356
|
checkLocalRefs(text, dir, rel, findings);
|
|
316
357
|
checkSkillRefs(text, rel, known, dirName, findings);
|
|
@@ -461,6 +502,41 @@ function selftest() {
|
|
|
461
502
|
assert.ok(isValidSkillName('a'.repeat(NAME_MAX)), 'a 64-char name is at the limit and valid');
|
|
462
503
|
assert.ok(!isValidSkillName('a'.repeat(NAME_MAX + 1)), 'a 65-char name is over the limit');
|
|
463
504
|
|
|
505
|
+
// Playbook frontmatter (kind: playbook).
|
|
506
|
+
const pb = (over = {}, drop = []) => {
|
|
507
|
+
const base = {
|
|
508
|
+
name: 'pb-x', description: 'd', category: 'bdb-core', kind: 'playbook',
|
|
509
|
+
trigger: '["a"]', inputs: '[repo]',
|
|
510
|
+
requires: '\n skills: [github, gh (external)]\n agents: []\n mcps: []\n store: []',
|
|
511
|
+
go_points: '[]', outputs: '["x"]', verify: '"x"', difficulty: 'beginner',
|
|
512
|
+
est_time: '5 min', 'disable-model-invocation': 'true', ...over,
|
|
513
|
+
};
|
|
514
|
+
const lines = Object.entries(base).filter(([k]) => !drop.includes(k)).map(([k, v]) => `${k}: ${v}`);
|
|
515
|
+
const fm = scanFrontmatter(['---', ...lines, '---'].join('\n'));
|
|
516
|
+
return new Map(fm.keys.map((k) => [k.key, k]));
|
|
517
|
+
};
|
|
518
|
+
const known = new Set(['github', 'ci-pipeline']);
|
|
519
|
+
assert.deepEqual(checkPlaybook(pb(), known), [], 'valid playbook is clean');
|
|
520
|
+
const miss = checkPlaybook(pb({}, ['go_points']), known);
|
|
521
|
+
assert.equal(miss.length, 1);
|
|
522
|
+
assert.equal(miss[0].code, 'E-PB03');
|
|
523
|
+
assert.match(miss[0].msg, /go_points/);
|
|
524
|
+
assert.equal(checkPlaybook(pb({ difficulty: 'expert' }), known)[0].code, 'E-PB04');
|
|
525
|
+
const unk = checkPlaybook(pb({ requires: '\n skills: [github, nope-skill, gh (external)]' }), known);
|
|
526
|
+
assert.equal(unk.length, 1);
|
|
527
|
+
assert.equal(unk[0].code, 'E-PB02');
|
|
528
|
+
assert.match(unk[0].msg, /nope-skill/);
|
|
529
|
+
const kind = checkPlaybook(pb({ kind: 'recipe' }), known);
|
|
530
|
+
assert.equal(kind.length, 1);
|
|
531
|
+
assert.equal(kind[0].code, 'E-PB01');
|
|
532
|
+
assert.equal(checkPlaybook(pb({ requires: '\n skills:\n - github' }), known)[0].code, 'E-PB05');
|
|
533
|
+
assert.equal(checkPlaybook(pb({ 'disable-model-invocation': 'false' }), known)[0].code, 'E-PB06');
|
|
534
|
+
assert.deepEqual(checkPlaybook(pb({}, ['kind', 'trigger', 'inputs', 'requires', 'go_points', 'outputs', 'verify', 'difficulty', 'est_time', 'disable-model-invocation']), known).length, 0, 'no kind, no playbook rules');
|
|
535
|
+
assert.deepEqual(
|
|
536
|
+
checkPlaybook(pb({ requires: '\n skills: ["gh (external)", github,]' }), known), [],
|
|
537
|
+
'quoted item and trailing comma survive',
|
|
538
|
+
);
|
|
539
|
+
|
|
464
540
|
console.log('✓ selftest passed');
|
|
465
541
|
}
|
|
466
542
|
|
|
@@ -76,7 +76,7 @@ Define hardware and software nodes as strict bounded contexts:
|
|
|
76
76
|
|
|
77
77
|
## 5. Mandatory — Plan Canvas Review
|
|
78
78
|
|
|
79
|
-
Before this session concludes, run `aos-plan-canvas open <file>` against `signal-flow.md` (or the combined show-control spec), then `aos-plan-canvas await <file>` and leave it running. The user reviews the signal flow diagram, hardware topology, and failover matrix in the browser (Mermaid renders live, click-to-annotate, chat rail). Do not consider the show architecture finalized before an `approve` verdict. A `request_changes` verdict means revise the artifact and reopen — it live-reloads. This is a plain CLI tool, identical regardless of which agent harness runs this skill. See the `plan-canvas` skill. If a build follows the approve, Trigger A starts the live map (`agenttrail` skill); `aos-archify` can render the signal flow as a workflow or architecture diagram for the review.
|
|
79
|
+
Before this session concludes, choose the planning mode by running `aos-plan-canvas modes` and presenting available modes to the user (see the "Planning mode choice" section in the `plan-canvas` skill). Then run `aos-plan-canvas open <file> --mode <choice>` against `signal-flow.md` (or the combined show-control spec), then `aos-plan-canvas await <file>` and leave it running. The user reviews the signal flow diagram, hardware topology, and failover matrix in the browser (Mermaid renders live, click-to-annotate, chat rail). Do not consider the show architecture finalized before an `approve` verdict. A `request_changes` verdict means revise the artifact and reopen — it live-reloads. This is a plain CLI tool, identical regardless of which agent harness runs this skill. See the `plan-canvas` skill. If a build follows the approve, Trigger A starts the live map (`agenttrail` skill); `aos-archify` can render the signal flow as a workflow or architecture diagram for the review.
|
|
80
80
|
|
|
81
81
|
---
|
|
82
82
|
|
|
@@ -41,6 +41,9 @@ This Godmode extends beyond standard software development. It STRICTLY governs c
|
|
|
41
41
|
* **MediaStorm Deployments:** When executing `/bdbmediastorm` for TouchDesigner, Unreal Engine, or Adobe Suite workflows, you must enforce rigorous release management for `.tox` files, Unreal Blueprints, and showfiles.
|
|
42
42
|
* **Show-Ready Validation:** Never push a creative-tech update to a live production environment (e.g., a running installation or live show) without a verified fallback or backup showfile.
|
|
43
43
|
|
|
44
|
+
## Visual recap
|
|
45
|
+
After the gates pass, `/pr-recap` can build a Plan Builder recap page of the diff with the Verified and Not verified checks. It is informational and does not gate the release. Posting it anywhere stays a human decision.
|
|
46
|
+
|
|
44
47
|
## Universal Agent Harness Integration
|
|
45
48
|
This Godmode is universally compatible and governs all extensions, including the BDB Creator Engine.
|
|
46
49
|
* **Cursor:** Auto-injected via `.cursor/rules/godmode-shipping.mdc`.
|