@hybridlabor-api/aos 4.16.0 → 4.18.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/plugins/marketplace.json +20 -0
- package/.claude/hooks/aos-bus.mjs +8 -4
- package/.claude/hooks/env-file-protection.mjs +19 -1
- package/.claude/hooks/go-gate.mjs +788 -69
- package/.claude/hooks/go-grant.mjs +88 -0
- package/.claude/hooks/go-token.mjs +17 -2
- package/.claude/hooks/memb-inject.mjs +61 -37
- package/.claude/settings.json +8 -0
- package/.codex-plugin/plugin.json +36 -6
- package/.opencode/commands/bdb-aos-brainstorm.md +5 -0
- package/.opencode/commands/bdb-aos-doctor.md +5 -0
- package/.opencode/commands/bdb-aos-graph.md +5 -0
- package/.opencode/commands/bdb-aos-init.md +5 -0
- package/.opencode/commands/bdb-aos-loop.md +5 -0
- package/.opencode/commands/bdb-aos-mastersession.md +5 -0
- package/.opencode/commands/bdb-aos-memb.md +5 -0
- package/.opencode/commands/bdb-aos-orchestrator.md +5 -0
- package/.opencode/commands/bdb-aos-plan.md +5 -0
- package/.opencode/commands/bdb-aos-playbooks.md +5 -0
- package/.opencode/commands/bdb-aos-setup.md +5 -0
- package/.opencode/commands/bdb-aos-shipping.md +5 -0
- package/.opencode/commands/bdb-aos-startproject.md +5 -0
- package/.opencode/commands/bdb-aos-store.md +5 -0
- package/.opencode/plugins/bdb-aos.js +54 -10
- package/README.md +5 -4
- package/THIRD_PARTY_NOTICES.md +2 -2
- package/agy-commands/loop.md +5 -0
- package/bin/aos-acp.mjs +27 -1
- package/bin/aos-doctor.mjs +41 -4
- package/bin/aos-uninstall.mjs +41 -3
- package/bin/go-check.mjs +79 -0
- package/bin/guarded-patterns.json +106 -0
- package/commands/brainstorm.md +5 -0
- package/commands/doctor.md +5 -0
- package/commands/graph.md +5 -0
- package/commands/init.md +5 -0
- package/commands/loop.md +5 -0
- package/commands/mastersession.md +5 -0
- package/commands/memb.md +5 -0
- package/commands/orchestrator.md +5 -0
- package/commands/plan.md +5 -0
- package/commands/playbooks.md +5 -0
- package/commands/setup.md +5 -0
- package/commands/shipping.md +5 -0
- package/commands/startproject.md +5 -0
- package/commands/store.md +5 -0
- package/docs/codenotch.md +44 -0
- package/docs/codex-agy-setup.md +16 -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 +54 -0
- package/docs/plugin-migration.md +61 -0
- package/installer.js +351 -121
- package/lib/codenotch.js +389 -0
- package/lib/plugin-migration.js +462 -0
- package/lib/retired-skills.js +101 -0
- package/lib/store-ui/index.html +9 -1
- package/lib/store-ui/server.mjs +2 -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 +7 -2
- package/plugin-commands.json +143 -0
- package/plugin.json +299 -0
- package/plugins/bdb-aos-codex/.codex-plugin/plugin.json +38 -0
- package/plugins/bdb-aos-codex/skills/brainstorm/SKILL.md +6 -0
- package/plugins/bdb-aos-codex/skills/doctor/SKILL.md +6 -0
- package/plugins/bdb-aos-codex/skills/graph/SKILL.md +6 -0
- package/plugins/bdb-aos-codex/skills/init/SKILL.md +6 -0
- package/plugins/bdb-aos-codex/skills/loop/SKILL.md +6 -0
- package/plugins/bdb-aos-codex/skills/mastersession/SKILL.md +6 -0
- package/plugins/bdb-aos-codex/skills/memb/SKILL.md +6 -0
- package/plugins/bdb-aos-codex/skills/orchestrator/SKILL.md +6 -0
- package/plugins/bdb-aos-codex/skills/plan/SKILL.md +6 -0
- package/plugins/bdb-aos-codex/skills/playbooks/SKILL.md +6 -0
- package/plugins/bdb-aos-codex/skills/setup/SKILL.md +6 -0
- package/plugins/bdb-aos-codex/skills/shipping/SKILL.md +6 -0
- package/plugins/bdb-aos-codex/skills/startproject/SKILL.md +6 -0
- package/plugins/bdb-aos-codex/skills/store/SKILL.md +6 -0
- package/scripts/build-plugin-manifest.mjs +202 -3
- package/scripts/codex-gate-smoke.mjs +73 -0
- package/skills/basic/master-session/SKILL.md +11 -0
- package/skills/bdb-aos/scripts/list-playbooks.mjs +72 -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/gogate/SKILL.md +123 -0
- package/skills/global_config/loop-templates/SKILL.md +27 -0
- package/skills/global_config/loop-templates/references/ci-until-green.md +27 -0
- package/skills/global_config/loop-templates/references/daily-summary.md +27 -0
- package/skills/global_config/loop-templates/references/pr-to-merge.md +27 -0
- package/skills/global_config/loop-templates/references/review-rounds.md +27 -0
- 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/.codex-plugin/marketplace.json +0 -11
- 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
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// UserPromptSubmit hook for the go-gate modes and grants. When the human types,
|
|
3
|
+
// as the whole message (plain form, primary):
|
|
4
|
+
// gogate grant <scope[,scope...]> <15m|2h|1d|session>
|
|
5
|
+
// gogate hard|soft|off|status
|
|
6
|
+
// or the slash form /bdb-aos:gogate ... (rarely verifies, the hook says so),
|
|
7
|
+
// it records the request in ~/.aos/gate/<session-key>.json with a pointer to
|
|
8
|
+
// the prompt (transcript, issue time, text hash). Nothing here is trusted on
|
|
9
|
+
// its own: go-gate.mjs re-reads the transcript at use time and honours an
|
|
10
|
+
// entry only if a human-typed (origin-checked) prompt with that hash exists.
|
|
11
|
+
// A loop, peer, bus or agent prompt may reach this hook, but its transcript
|
|
12
|
+
// entry is not human, so what it records never verifies.
|
|
13
|
+
//
|
|
14
|
+
// CLI: node go-grant.mjs --status [--session <id>] (read-only, prints status)
|
|
15
|
+
|
|
16
|
+
import { readFileSync, realpathSync } from "node:fs";
|
|
17
|
+
import { fileURLToPath } from "node:url";
|
|
18
|
+
import {
|
|
19
|
+
parseGogate, textHash, sessionKey, readState, writeState, gateLog, effectiveGate,
|
|
20
|
+
gogateCommandsFor, statusText, listStateKeys, OPENCODE_MAX_GRANT_MS,
|
|
21
|
+
} from "./go-gate.mjs";
|
|
22
|
+
|
|
23
|
+
const emptyState = (source) => ({ transcript: source, grants: [] });
|
|
24
|
+
|
|
25
|
+
// Applies a gogate prompt to the store. `source` is the transcript path or
|
|
26
|
+
// "opencode:<sessionID>"; `uuid` the message id when the harness knows it.
|
|
27
|
+
// Returns the text for the model (additionalContext), or null for non-gogate prompts.
|
|
28
|
+
export function applyGogate(prompt, { key, source, uuid = null, now = Date.now(), opencode = false }) {
|
|
29
|
+
const p = parseGogate(prompt);
|
|
30
|
+
if (!p) return null;
|
|
31
|
+
const slashNote = p.form === "slash"
|
|
32
|
+
? ` Note: this was a slash command. ${opencode ? "OpenCode accepts only the plain form" : "Claude Code stores slash commands without human-origin data, so the gate will most likely ignore it"}; to make it count, type the plain form as the whole message: \`gogate ${p.cmd === "grant" ? `grant ${p.scopes.join(",")} ${p.session ? "session" : "<duration>"}` : p.cmd || "status"}\`.`
|
|
33
|
+
: "";
|
|
34
|
+
if (p.error) return `gogate: ${p.error}. Nothing changed.`;
|
|
35
|
+
if (!key || !source) return "gogate: no session id in hook input, nothing recorded.";
|
|
36
|
+
if (process.env.AOS_ACP_CLIENT) return "gogate: an aos-acp worker session cannot set modes or grants.";
|
|
37
|
+
if (p.cmd === "status") return status(key);
|
|
38
|
+
if (opencode && p.cmd === "off") return "gogate: `off` is not available on OpenCode (no human-origin signal there). Nothing changed.";
|
|
39
|
+
let st = readState(key);
|
|
40
|
+
if (!st || typeof st !== "object" || st.transcript !== source) st = emptyState(source);
|
|
41
|
+
const src = { transcript: source, uuid, issued_at: new Date(now).toISOString(), text_hash: textHash(prompt) };
|
|
42
|
+
if (p.cmd === "grant") {
|
|
43
|
+
const ms = opencode ? Math.min(p.ms, OPENCODE_MAX_GRANT_MS) : p.ms;
|
|
44
|
+
st.grants = (Array.isArray(st.grants) ? st.grants : []).filter((g) => Date.parse(g?.until) > now);
|
|
45
|
+
for (const scope of p.scopes) st.grants.push({ scope, until: new Date(now + ms).toISOString(), ...(p.session ? { session_key: key } : {}), source: src });
|
|
46
|
+
} else {
|
|
47
|
+
// Append, never overwrite: a later prompt that does not verify must not erase the
|
|
48
|
+
// store entry of the mode that is still in force.
|
|
49
|
+
st.modes = [...(Array.isArray(st.modes) ? st.modes : []), { mode: p.cmd, source: src }].slice(-20);
|
|
50
|
+
}
|
|
51
|
+
try {
|
|
52
|
+
writeState(key, st);
|
|
53
|
+
} catch (e) {
|
|
54
|
+
return `gogate: could NOT record ${p.cmd}: writing ~/.aos/gate failed (${e.code || e.message}). Nothing changed; the gate stays as it was. Tell the human.`;
|
|
55
|
+
}
|
|
56
|
+
gateLog(key, `recorded ${p.form} ${p.cmd}${p.scopes ? ` ${p.scopes.join(",")} ${p.session ? "session" : `${p.ms / 60000}m`}` : ""}`);
|
|
57
|
+
return [
|
|
58
|
+
`gogate: recorded ${p.cmd}${p.scopes ? ` for ${p.scopes.join(", ")}` : ""}${p.session ? " (session = this session id, at most 24h, survives --resume)" : ""}${opencode && p.cmd === "grant" && p.ms > OPENCODE_MAX_GRANT_MS ? " (capped at 2h on OpenCode)" : ""}.`,
|
|
59
|
+
"The gate verifies it against this prompt in the transcript on every use.",
|
|
60
|
+
slashNote,
|
|
61
|
+
"Tell the human what was recorded; never try to change modes or grants yourself.",
|
|
62
|
+
].filter(Boolean).join(" ");
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function status(key) {
|
|
66
|
+
const st = readState(key);
|
|
67
|
+
const eff = st ? effectiveGate(key, { source: st.transcript, cmds: gogateCommandsFor(st.transcript), opencode: String(st.transcript).startsWith("opencode:") }) : { mode: "soft", grants: [], rejected: [] };
|
|
68
|
+
return statusText(key, eff);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const isMain = () => { try { return realpathSync(process.argv[1]) === realpathSync(fileURLToPath(import.meta.url)); } catch { return false; } };
|
|
72
|
+
|
|
73
|
+
if (isMain()) {
|
|
74
|
+
const argv = process.argv.slice(2);
|
|
75
|
+
if (argv.includes("--status")) {
|
|
76
|
+
const i = argv.indexOf("--session");
|
|
77
|
+
const id = i !== -1 ? argv[i + 1] : process.env.AOS_GATE_SESSION || process.env.CLAUDE_SESSION_ID;
|
|
78
|
+
const keys = id ? [sessionKey(id)] : listStateKeys();
|
|
79
|
+
console.log(keys.length ? keys.map(status).join("\n\n") : "AOS go-gate: no session state; every session runs in soft mode with no grants (behaves like hard).");
|
|
80
|
+
process.exit(0);
|
|
81
|
+
}
|
|
82
|
+
try {
|
|
83
|
+
const input = JSON.parse(readFileSync(0, "utf8"));
|
|
84
|
+
const text = applyGogate(input.prompt, { key: sessionKey(input.session_id), source: input.transcript_path });
|
|
85
|
+
if (text) console.log(JSON.stringify({ hookSpecificOutput: { hookEventName: "UserPromptSubmit", additionalContext: text } }));
|
|
86
|
+
} catch { /* a failing hook must never block the prompt */ }
|
|
87
|
+
process.exit(0);
|
|
88
|
+
}
|
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
// master session, record a single-use token that go-gate.mjs in <session-name>
|
|
4
4
|
// accepts. Writes nothing else and never blocks the prompt.
|
|
5
5
|
|
|
6
|
-
import { readFileSync, writeFileSync, mkdirSync, realpathSync } from "node:fs";
|
|
6
|
+
import { readFileSync, writeFileSync, mkdirSync, realpathSync, readdirSync, unlinkSync } from "node:fs";
|
|
7
7
|
import { homedir } from "node:os";
|
|
8
8
|
import { join } from "node:path";
|
|
9
9
|
import { fileURLToPath } from "node:url";
|
|
10
|
-
import { slug } from "./go-gate.mjs";
|
|
10
|
+
import { slug, TOKEN_TTL_MS } from "./go-gate.mjs";
|
|
11
11
|
|
|
12
12
|
function sessionName(transcriptPath) {
|
|
13
13
|
let name = "";
|
|
@@ -24,6 +24,20 @@ function sessionName(transcriptPath) {
|
|
|
24
24
|
return name || process.env.AOS_SESSION_NAME || "";
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
+
// Expired or unreadable tokens are never read again by anyone, so a write is the moment to drop them.
|
|
28
|
+
export function pruneExpiredTokens(dir, now = Date.now()) {
|
|
29
|
+
let files = [];
|
|
30
|
+
try { files = readdirSync(dir).filter((f) => f.endsWith(".token")); } catch { return 0; }
|
|
31
|
+
let removed = 0;
|
|
32
|
+
for (const f of files) {
|
|
33
|
+
let age = NaN;
|
|
34
|
+
try { age = now - Date.parse(JSON.parse(readFileSync(join(dir, f), "utf8"))?.issued_at); } catch { /* unreadable: drop */ }
|
|
35
|
+
if (age >= 0 && age < TOKEN_TTL_MS) continue;
|
|
36
|
+
try { unlinkSync(join(dir, f)); removed++; } catch { /* already gone */ }
|
|
37
|
+
}
|
|
38
|
+
return removed;
|
|
39
|
+
}
|
|
40
|
+
|
|
27
41
|
// Returns the token path, or null. Never throws. An aos-acp worker is a worker
|
|
28
42
|
// by definition and must not mint a token for itself.
|
|
29
43
|
export function issueGoToken(prompt, { transcript_path, session_id, message_id } = {}) {
|
|
@@ -38,6 +52,7 @@ export function issueGoToken(prompt, { transcript_path, session_id, message_id }
|
|
|
38
52
|
if (!target || !tok) return null;
|
|
39
53
|
const dir = join(homedir(), ".aos", "go");
|
|
40
54
|
mkdirSync(dir, { recursive: true });
|
|
55
|
+
pruneExpiredTokens(dir);
|
|
41
56
|
const file = join(dir, `${target}.token`);
|
|
42
57
|
writeFileSync(file, JSON.stringify(tok));
|
|
43
58
|
return file;
|
|
@@ -1,32 +1,41 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
// aos-hook-version:
|
|
2
|
+
// aos-hook-version: 8
|
|
3
3
|
/**
|
|
4
4
|
* memB ambient memory hook for Claude Code, Google Antigravity, and OpenAI Codex.
|
|
5
5
|
*
|
|
6
6
|
* Stamped with aos-hook-version for /aos-setup doctor validation.
|
|
7
7
|
* Reads ~/.MemBDB/memb.db directly through node:sqlite and injects relevant
|
|
8
|
-
* project & user memories as ephemeral context
|
|
9
|
-
*
|
|
8
|
+
* project & user memories as ephemeral context, emitting only the key the
|
|
9
|
+
* calling harness reads:
|
|
10
|
+
* - hookSpecificOutput.additionalContext (Claude Code, OpenAI Codex)
|
|
10
11
|
* - injectSteps (Google Antigravity PreInvocation)
|
|
11
|
-
*
|
|
12
|
+
*
|
|
13
|
+
* Reads rows of the configured user (MEMB_USER_ID, fallback $USER) plus the
|
|
14
|
+
* group ids in MEMB_GROUP_IDS (comma list, default bdb_developer). Rows bound
|
|
15
|
+
* to the current project are injected whatever their category (max 5, 180
|
|
16
|
+
* chars each); global rows still need category `godmode`.
|
|
12
17
|
*
|
|
13
18
|
* Event-aware: SessionStart injects the persona file, the global godmode
|
|
14
19
|
* identity rows, and the current project's cards once per session; every
|
|
15
20
|
* other prompt (UserPromptSubmit) recalls only FTS keyword hits so 40
|
|
16
21
|
* identity facts are not re-sent on every message. Harnesses without a
|
|
17
22
|
* session hook (e.g. Antigravity PreInvocation) get the full block plus
|
|
18
|
-
* identity on
|
|
23
|
+
* identity on the first invocation of a conversation (cached per
|
|
24
|
+
* conversationId); later invocations recall FTS hits only.
|
|
19
25
|
*
|
|
20
26
|
* Fails open: any error exits 0 silently.
|
|
21
27
|
*/
|
|
22
28
|
|
|
23
|
-
import { readFileSync, existsSync, realpathSync } from 'node:fs';
|
|
29
|
+
import { readFileSync, existsSync, realpathSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
24
30
|
import os from 'node:os';
|
|
25
31
|
import path from 'node:path';
|
|
26
32
|
import { fileURLToPath } from 'node:url';
|
|
27
33
|
import { execFileSync } from 'node:child_process';
|
|
28
34
|
|
|
29
35
|
const COLLECTION = 'bdb_agent_memory';
|
|
36
|
+
const DEFAULT_GROUP_IDS = 'bdb_developer';
|
|
37
|
+
const PROJECT_ROW_CAP = 5;
|
|
38
|
+
const ROW_CHARS = 180;
|
|
30
39
|
const failOpen = () => process.exit(0);
|
|
31
40
|
|
|
32
41
|
// `deja wip --json` run in the project root, rendered as context lines.
|
|
@@ -51,6 +60,14 @@ export function dejaWip(cwd, run = execFileSync) {
|
|
|
51
60
|
}
|
|
52
61
|
}
|
|
53
62
|
|
|
63
|
+
// Rows are read for the user plus the configured group ids; nothing is
|
|
64
|
+
// hard-coded beyond the documented default group.
|
|
65
|
+
export function resolveReaderIds({ userId, env = process.env } = {}) {
|
|
66
|
+
const user = env.MEMB_USER_ID || userId || env.USER || env.LOGNAME || '';
|
|
67
|
+
const groups = String(env.MEMB_GROUP_IDS ?? DEFAULT_GROUP_IDS).split(',').map((g) => g.trim());
|
|
68
|
+
return Array.from(new Set([user, ...groups].filter(Boolean)));
|
|
69
|
+
}
|
|
70
|
+
|
|
54
71
|
// Filler words (German + English) that must never become FTS query terms —
|
|
55
72
|
// they match virtually any document and would inject unrelated projects.
|
|
56
73
|
const STOPWORDS = new Set([
|
|
@@ -160,14 +177,7 @@ export async function buildMemoryBlock({ event = '', prompt = '', cwd, userId }
|
|
|
160
177
|
const projectRoot = findProjectRoot(rawCandidateDir, home);
|
|
161
178
|
const candidateProjectIds = resolveProjectIdentifiers(projectRoot, home);
|
|
162
179
|
|
|
163
|
-
|
|
164
|
-
const activeUser =
|
|
165
|
-
process.env.MEMB_USER_ID ||
|
|
166
|
-
userId ||
|
|
167
|
-
process.env.USER ||
|
|
168
|
-
process.env.LOGNAME ||
|
|
169
|
-
'bdb_developer';
|
|
170
|
-
const candidateUsers = Array.from(new Set([activeUser, 'bdb_developer'])).filter(Boolean);
|
|
180
|
+
const candidateUsers = resolveReaderIds({ userId });
|
|
171
181
|
|
|
172
182
|
const contextItems = [];
|
|
173
183
|
|
|
@@ -259,12 +269,10 @@ export async function buildMemoryBlock({ event = '', prompt = '', cwd, userId }
|
|
|
259
269
|
OR json_extract(payload, '$.user_id') IN (${uPlaceholders})
|
|
260
270
|
OR json_extract(payload, '$.metadata.user_id') IN (${uPlaceholders})
|
|
261
271
|
)
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
ORDER BY rowid DESC
|
|
267
|
-
LIMIT 5
|
|
272
|
+
ORDER BY (COALESCE(json_extract(payload, '$.category'),
|
|
273
|
+
json_extract(payload, '$.metadata.category')) = 'project_card') DESC,
|
|
274
|
+
rowid DESC
|
|
275
|
+
LIMIT ${PROJECT_ROW_CAP * 4}
|
|
268
276
|
`;
|
|
269
277
|
const params = [
|
|
270
278
|
COLLECTION,
|
|
@@ -276,11 +284,14 @@ export async function buildMemoryBlock({ event = '', prompt = '', cwd, userId }
|
|
|
276
284
|
...candidateUsers,
|
|
277
285
|
];
|
|
278
286
|
const rows = db.prepare(sql).all(...params);
|
|
287
|
+
let taken = 0;
|
|
279
288
|
for (const r of rows) {
|
|
289
|
+
if (taken >= PROJECT_ROW_CAP) break;
|
|
280
290
|
const text = textOf(r.payload);
|
|
281
|
-
if (text.length
|
|
282
|
-
|
|
283
|
-
}
|
|
291
|
+
if (text.length <= 10 || /^\[[^\]|]+\|[^\]|]+\|/.test(text)) continue; // too short / imported file chunk
|
|
292
|
+
if (contextItems.some((e) => e.includes(text.slice(0, 50)))) continue;
|
|
293
|
+
contextItems.push(`- Project [${candidateProjectIds[0]}]: ${text.slice(0, ROW_CHARS)}`);
|
|
294
|
+
taken++;
|
|
284
295
|
}
|
|
285
296
|
} catch { /* project query is best-effort */ }
|
|
286
297
|
}
|
|
@@ -316,7 +327,7 @@ export async function buildMemoryBlock({ event = '', prompt = '', cwd, userId }
|
|
|
316
327
|
const hitProject = projectOf(r.payload);
|
|
317
328
|
if (hitProject && !candidateProjectIds.includes(hitProject)) continue;
|
|
318
329
|
const cat = categoryOf(r.payload);
|
|
319
|
-
if (cat !== 'project_card' && cat !== 'godmode') continue;
|
|
330
|
+
if (!hitProject && cat !== 'project_card' && cat !== 'godmode') continue;
|
|
320
331
|
if (!contextItems.some((e) => e.includes(text.slice(0, 50)))) {
|
|
321
332
|
contextItems.push(`- Domain memory: ${text.slice(0, 180)}`);
|
|
322
333
|
}
|
|
@@ -338,6 +349,19 @@ export async function buildMemoryBlock({ event = '', prompt = '', cwd, userId }
|
|
|
338
349
|
}
|
|
339
350
|
}
|
|
340
351
|
|
|
352
|
+
// Antigravity has no session hook: remember per conversation that identity and
|
|
353
|
+
// project rows were already sent, so later invocations do only the FTS recall
|
|
354
|
+
// and skip `deja wip`. Stamps under ~/.aos/cache are disposable.
|
|
355
|
+
export function agyIdentitySent(conversationId, base = path.join(os.homedir(), '.aos', 'cache')) {
|
|
356
|
+
const id = String(conversationId || '').replace(/[^\w.-]/g, '_').slice(0, 80);
|
|
357
|
+
if (!id) return false;
|
|
358
|
+
const dir = path.join(base, 'memb-agy');
|
|
359
|
+
const stamp = path.join(dir, id);
|
|
360
|
+
if (existsSync(stamp)) return true;
|
|
361
|
+
try { mkdirSync(dir, { recursive: true }); writeFileSync(stamp, ''); } catch {}
|
|
362
|
+
return false;
|
|
363
|
+
}
|
|
364
|
+
|
|
341
365
|
// Main logic runs only when the file is executed directly as a hook; importing
|
|
342
366
|
// the module (e.g. from tests) must stay side-effect free.
|
|
343
367
|
async function main() {
|
|
@@ -351,26 +375,26 @@ async function main() {
|
|
|
351
375
|
|
|
352
376
|
// Discover candidate directory across harnesses:
|
|
353
377
|
// Claude / Codex: eventData.cwd; Antigravity: eventData.workspacePaths[0] or eventData.cwd
|
|
378
|
+
const isAgy = !eventData.hook_event_name && (Array.isArray(eventData.workspacePaths) || !!eventData.conversationId);
|
|
379
|
+
const event = isAgy && agyIdentitySent(eventData.conversationId)
|
|
380
|
+
? 'UserPromptSubmit'
|
|
381
|
+
: (eventData.hook_event_name || '');
|
|
354
382
|
const memoryBlock = await buildMemoryBlock({
|
|
355
|
-
event
|
|
383
|
+
event,
|
|
356
384
|
prompt: eventData.prompt || eventData.userPrompt || '',
|
|
357
385
|
cwd: (Array.isArray(eventData.workspacePaths) && eventData.workspacePaths[0]) || eventData.cwd,
|
|
358
386
|
userId: eventData.user_id || eventData.userId,
|
|
359
387
|
});
|
|
360
388
|
|
|
361
389
|
if (memoryBlock) {
|
|
362
|
-
process.stdout.write(JSON.stringify(
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
}
|
|
371
|
-
],
|
|
372
|
-
systemMessage: memoryBlock,
|
|
373
|
-
}) + '\n');
|
|
390
|
+
process.stdout.write(JSON.stringify(isAgy
|
|
391
|
+
? { injectSteps: [{ ephemeralMessage: memoryBlock }] }
|
|
392
|
+
: {
|
|
393
|
+
hookSpecificOutput: {
|
|
394
|
+
hookEventName: eventData.hook_event_name || 'UserPromptSubmit',
|
|
395
|
+
additionalContext: memoryBlock,
|
|
396
|
+
},
|
|
397
|
+
}) + '\n');
|
|
374
398
|
}
|
|
375
399
|
process.exit(0);
|
|
376
400
|
} catch {
|
package/.claude/settings.json
CHANGED
|
@@ -1,8 +1,38 @@
|
|
|
1
1
|
{
|
|
2
|
-
"name": "bdb-
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "BDB
|
|
5
|
-
"author":
|
|
6
|
-
|
|
7
|
-
|
|
2
|
+
"name": "bdb-aos",
|
|
3
|
+
"version": "4.18.0",
|
|
4
|
+
"description": "Full BDB Agent OS suite for Codex: command entry points ($bdb-aos:setup, $bdb-aos:init, ...) generated from plugin-commands.json.",
|
|
5
|
+
"author": {
|
|
6
|
+
"name": "Tim Rennings / Hybridlabor Global LLC",
|
|
7
|
+
"email": "hybridlabor@gmail.com"
|
|
8
|
+
},
|
|
9
|
+
"homepage": "https://github.com/hybridlabor-api/aos",
|
|
10
|
+
"repository": "https://github.com/hybridlabor-api/aos",
|
|
11
|
+
"license": "Apache-2.0",
|
|
12
|
+
"keywords": [
|
|
13
|
+
"skills",
|
|
14
|
+
"agent-os",
|
|
15
|
+
"cicd",
|
|
16
|
+
"multiagent",
|
|
17
|
+
"startcycle",
|
|
18
|
+
"bdb"
|
|
19
|
+
],
|
|
20
|
+
"skills": "./plugins/bdb-aos-codex/skills/",
|
|
21
|
+
"interface": {
|
|
22
|
+
"displayName": "BDB Agent OS",
|
|
23
|
+
"shortDescription": "AOS commands for setup, planning and pipelines",
|
|
24
|
+
"longDescription": "Entry-point skills for the BDB Agent OS suite: invoke $bdb-aos:<command> to run setup, project init, planning and the startcycle pipelines.",
|
|
25
|
+
"developerName": "Hybridlabor Global LLC",
|
|
26
|
+
"category": "Developer Tools",
|
|
27
|
+
"capabilities": [
|
|
28
|
+
"Interactive",
|
|
29
|
+
"Read",
|
|
30
|
+
"Write"
|
|
31
|
+
],
|
|
32
|
+
"websiteURL": "https://github.com/hybridlabor-api/aos",
|
|
33
|
+
"defaultPrompt": [
|
|
34
|
+
"$bdb-aos:setup",
|
|
35
|
+
"$bdb-aos:doctor"
|
|
36
|
+
]
|
|
37
|
+
}
|
|
8
38
|
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "Brainstorm a topic with the matching skill: bdbrainstorm, bdbmediastorm for event tech, grill-me for a stress test."
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Pick by topic: `bdbmediastorm` for live event technology and show control, `grill-me` when the human wants an existing idea stress-tested, `bdbrainstorm` otherwise. Say which one you chose. Topic: $ARGUMENTS
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "Check the machine and the current project, and print suggested permissions.allow entries without writing any settings."
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Run `aos-doctor` (machine check) and report the result. If the current folder is an AOS project, also run the project check `node <aos-project-init skill dir>/scripts/aos-project-doctor.mjs` (it covers `.aos/project.json`, AGENTS.md and the wiki). Print suggested `permissions.allow` entries as text for the human to copy. Never write to settings.json or settings.local.json. Arguments: $ARGUMENTS
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "Set up the current project folder for AOS: slug, wiki, memory, Synapse map, AGENTS.md."
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Run the `aos-project-init` skill for the current project folder. This is project setup, not machine setup (that is `/bdb-aos-setup`). Arguments: $ARGUMENTS
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "Run a prompt repeatedly on an interval, using the harness built-in plus loop templates."
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
OpenCode has no built-in loop. Use `opencode-loop`, the opt-in package (AOS_OPENCODE_OPTIONAL=loop, see docs/opencode-setup.md); without it, say so and stop. Do not schedule gated commands through its shell loop. Offer a `loop-templates` template when the human has no prompt yet. Safety: a loop prompt never issues a GO, never types or runs `gogate`, never sets a mode or grant, and never merges, pushes or publishes unless a valid grant covers the action. Act on a guarded step only if the human's immediately preceding message is a literal GO or a valid grant covers it; a loop iteration never satisfies the first condition, so it must STOP and report instead of continuing a blocked guarded step. Templates (CI until green, follow a PR to merge, review rounds until no blockers, daily session summary) live in the `loop-templates` skill with run and duration limits and a stop condition each. Arguments: $ARGUMENTS
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "Supervise other Claude Code sessions on this machine: roster, status requests, GO board, idle notices."
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Act as the master session with the `master-session` skill (ACP bridge: `bin/aos-acp.mjs`, see docs/master-session-acp.md). Keep the overview, relay the human's decisions, never decide for the human. Arguments: $ARGUMENTS
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "Coordinate parallel coding agents across repositories through the AO daemon."
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Use the `ao-orchestrator` skill. It needs the AO daemon; check that it is running first and stop with a clear message if not. Do not confuse it with `agent-orchestrator`. Arguments: $ARGUMENTS
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "Plan end to end: draft, render in plan-canvas or Plan Builder, annotate, await approval, then hand off."
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Run the full planning pipeline: 1) draft the plan with `concise-planning`; 2) always offer the choice between plan-canvas and Plan Builder (`aos-plan-canvas open <dir> --mode bdb-plan-builder`) for rendering; 3) collect annotations and wait for the human's approval; 4) only after approval continue with `writing-plans` or `/bdb-aos-graph`. Topic: $ARGUMENTS
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "List all pb-* playbooks with duration, difficulty and requirements, and start one."
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Run `node <bdb-aos skill dir>/scripts/list-playbooks.mjs` and show its output (name, est_time, difficulty, requires of every `pb-*` skill). If the human names a playbook in the arguments or picks one, start that `pb-*` skill; start nothing otherwise. Each playbook keeps its own go-gate points. Arguments: $ARGUMENTS
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "Bring this machine to a complete, verified AOS installation (skills, MCP servers, gate hooks, memB, OpenWiki, Synapse)."
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Run the `aos-setup` skill for this machine. Report what is installed, what was repaired and what is still missing. Arguments: $ARGUMENTS
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "Pre-ship framing and the technical release gate, with approvals under the go-gate rules."
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Use `bdb-shipping-skill` for the pre-flight and `godmode-shipping` for the gate. The playbook `pb-ship` can drive the whole flow. Push, merge and publish need the human's GO under the go-gate rules; never request one on the human's behalf. Arguments: $ARGUMENTS
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "Start a new composition: project init, brainstorm, then ask whether graph or startcycle follows."
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Sequence: 1) `aos-project-init`; 2) `bdbrainstorm`; 3) stop and ask the human whether `/bdb-aos-graph` (startcycle-graph) or `startcycle` follows. Do not start a pipeline on your own. Idea: $ARGUMENTS
|
|
@@ -23,8 +23,11 @@ import path from 'node:path';
|
|
|
23
23
|
// so a broken installed hook fails loudly instead of silently falling back.
|
|
24
24
|
const HOOKS = existsSync(new URL('./aos-hooks/go-gate.mjs', import.meta.url)) ? './aos-hooks/' : '../../.claude/hooks/';
|
|
25
25
|
const hook = (f) => import(new URL(HOOKS + f, import.meta.url).href);
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
// `opencode run "..."` is scriptable by an agent, so it never sets gogate modes or grants
|
|
27
|
+
const OPENCODE_RUN = process.argv.slice(1, 4).includes('run');
|
|
28
|
+
const [gate, { issueGoToken }, { checkConventionalCommit }, { envFileReason }, { buildMemoryBlock }, bus, { applyGogate }] =
|
|
29
|
+
await Promise.all(['go-gate.mjs', 'go-token.mjs', 'conventional-commits.mjs', 'env-file-protection.mjs', 'memb-inject.mjs', 'aos-bus.mjs', 'go-grant.mjs'].map(hook));
|
|
30
|
+
const { GUARDED_PATTERNS, tokenGrantsGo, isHumanPart, parseGoText, goAllows, isGuardedCommand, gateStoreReason, effectiveGate, opencodeGogateCommands, grantsCover, sessionKey, gateLog } = gate;
|
|
28
31
|
|
|
29
32
|
// ---------------------------------------------------------------------------
|
|
30
33
|
// Graph gate (W-5, W-6)
|
|
@@ -131,9 +134,26 @@ async function ownSessionName(client, sessionID) {
|
|
|
131
134
|
}
|
|
132
135
|
|
|
133
136
|
// Only plain text parts are human turns: synthetic = model-only, ignored = display-only,
|
|
134
|
-
// aos_bus
|
|
135
|
-
|
|
136
|
-
const
|
|
137
|
+
// aos_bus / aos_loop (any loop|aos_ metadata key) = plugin-injected. Each excluded on its own,
|
|
138
|
+
// so safety never hangs on one flag.
|
|
139
|
+
const isHumanText = isHumanPart;
|
|
140
|
+
const isNonHuman = (p) => !!p && !!(p.synthetic || p.ignored || (p.metadata && typeof p.metadata === 'object' && Object.keys(p.metadata).some((k) => /loop|aos_/i.test(k))));
|
|
141
|
+
const ocKey = (id) => sessionKey(`oc-${id}`);
|
|
142
|
+
|
|
143
|
+
// Root of a session tree (grants live on the root, subagents may use them). null when unknown.
|
|
144
|
+
async function rootSessionId(client, id, parentID) {
|
|
145
|
+
for (let i = 0; i < 10 && id; i++) {
|
|
146
|
+
if (parentID === null) return id;
|
|
147
|
+
try {
|
|
148
|
+
const res = await client?.session?.get?.({ path: { id } });
|
|
149
|
+
if (!res?.data) return null;
|
|
150
|
+
if (!res.data.parentID) return id;
|
|
151
|
+
id = res.data.parentID;
|
|
152
|
+
parentID = undefined;
|
|
153
|
+
} catch { return null; }
|
|
154
|
+
}
|
|
155
|
+
return null;
|
|
156
|
+
}
|
|
137
157
|
|
|
138
158
|
// A plugin reload (SIGUSR2) re-runs init on the cached module in the same process:
|
|
139
159
|
// stop the previous instance's timers and keep its bus names alive. Keyed by directory.
|
|
@@ -336,9 +356,10 @@ export default async function bdbAosPlugin(input) {
|
|
|
336
356
|
if (nudges >= MAX_NUDGES) return;
|
|
337
357
|
|
|
338
358
|
nudgeState.set(sessionID, { signature: gate.signature, nudges: nudges + 1 });
|
|
359
|
+
// Synthetic + aos_loop: the nudge is plugin-written and must never count as a human turn (GO, gogate).
|
|
339
360
|
await input.client.session.prompt({
|
|
340
361
|
path: { id: sessionID },
|
|
341
|
-
body: { parts: [{ type: 'text', text: buildGraphNudge(gate) }] },
|
|
362
|
+
body: { parts: [{ type: 'text', text: buildGraphNudge(gate), synthetic: true, metadata: { aos_loop: { source: 'graph-gate', nudge: nudges + 1 } } }] },
|
|
342
363
|
query: directory ? { directory } : undefined,
|
|
343
364
|
});
|
|
344
365
|
} catch {
|
|
@@ -361,6 +382,12 @@ export default async function bdbAosPlugin(input) {
|
|
|
361
382
|
if (!s.parentID) issueGoToken(fullText, { session_id: msgInput.sessionID, message_id: msgInput.messageID || msgOutput.message?.id });
|
|
362
383
|
} catch {}
|
|
363
384
|
|
|
385
|
+
// plain `gogate ...` message from the human in a root session: record it; the gate verifies it against opencode.db at use.
|
|
386
|
+
try {
|
|
387
|
+
const reply = s.parentID || OPENCODE_RUN ? null : applyGogate(fullText, { key: ocKey(msgInput.sessionID), source: `opencode:${msgInput.sessionID}`, uuid: msgInput.messageID || msgOutput.message?.id || null, opencode: true });
|
|
388
|
+
if (reply) msgOutput.parts.unshift({ id: `gogate-${Date.now()}`, sessionID: msgInput.sessionID, messageID: msgInput.messageID || '', type: 'text', text: reply, synthetic: true });
|
|
389
|
+
} catch {}
|
|
390
|
+
|
|
364
391
|
try {
|
|
365
392
|
const event = s.identitySent || s.parentID ? 'UserPromptSubmit' : 'SessionStart';
|
|
366
393
|
s.identitySent = true;
|
|
@@ -415,7 +442,9 @@ export default async function bdbAosPlugin(input) {
|
|
|
415
442
|
// Intercept bash, terminal, or command execution tools
|
|
416
443
|
if (toolName === 'bash' || toolName === 'terminal' || toolName === 'shell' || toolName === 'exec' || toolName === 'run_command') {
|
|
417
444
|
const cmd = toolOutput?.args?.command || toolOutput?.args?.cmd || toolOutput?.args?.script || '';
|
|
418
|
-
|
|
445
|
+
const storeReason = gateStoreReason(cmd);
|
|
446
|
+
if (storeReason) throw new Error(storeReason);
|
|
447
|
+
if (typeof cmd === 'string' && (GUARDED_PATTERNS.some((re) => re.test(cmd)) || isGuardedCommand(cmd))) {
|
|
419
448
|
const s = sess(toolInput.sessionID);
|
|
420
449
|
// An unanswered lookup is not proof of a root session: token-only for this call, not cached.
|
|
421
450
|
let tokenOnly = !!s.parentID;
|
|
@@ -427,8 +456,9 @@ export default async function bdbAosPlugin(input) {
|
|
|
427
456
|
} catch { tokenOnly = true; }
|
|
428
457
|
tokenOnly = tokenOnly || !!s.parentID;
|
|
429
458
|
}
|
|
430
|
-
// Subagent prompts are agent-written, so only a token can open their gate.
|
|
431
|
-
|
|
459
|
+
// Subagent prompts are agent-written, so only a token or a grant can open their gate.
|
|
460
|
+
const goOk = (text) => goAllows(parseGoText(text), cmd);
|
|
461
|
+
let authorized = !tokenOnly && goOk(s.prompt);
|
|
432
462
|
|
|
433
463
|
// If this session's cached prompt wasn't GO, query recent session messages via OpenCode client as fallback
|
|
434
464
|
if (!authorized && !tokenOnly && input.client && toolInput.sessionID) {
|
|
@@ -440,13 +470,27 @@ export default async function bdbAosPlugin(input) {
|
|
|
440
470
|
if ((m.info?.role ?? m.role) === 'user') {
|
|
441
471
|
const parts = m.parts || [];
|
|
442
472
|
const text = parts.filter(isHumanText).map((p) => p.text).join('\n').trim();
|
|
443
|
-
authorized = text
|
|
473
|
+
authorized = goOk(text);
|
|
444
474
|
break;
|
|
445
475
|
}
|
|
446
476
|
}
|
|
447
477
|
} catch {}
|
|
448
478
|
}
|
|
449
479
|
|
|
480
|
+
// Modes and grants of the root session (verified against opencode.db); usable by its subagents.
|
|
481
|
+
if (!authorized) {
|
|
482
|
+
const root = await rootSessionId(input.client, toolInput.sessionID, tokenOnly ? undefined : s.parentID);
|
|
483
|
+
if (root) {
|
|
484
|
+
const key = ocKey(root);
|
|
485
|
+
const eff = effectiveGate(key, { source: `opencode:${root}`, cmds: opencodeGogateCommands(root), opencode: true });
|
|
486
|
+
for (const r of eff.rejected) gateLog(key, `rejected: ${r}`);
|
|
487
|
+
if (eff.mode === 'soft' && grantsCover(cmd, eff.grants)) { // `off` is never honoured on OpenCode
|
|
488
|
+
gateLog(key, `grant: allowed ${JSON.stringify(cmd.slice(0, 200))}`);
|
|
489
|
+
authorized = true;
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
|
|
450
494
|
if (!authorized) {
|
|
451
495
|
authorized = tokenGrantsGo(await ownSessionName(input.client, toolInput.sessionID)).ok;
|
|
452
496
|
}
|
package/README.md
CHANGED
|
@@ -110,14 +110,15 @@ What the installer writes for each target. Paths are the defaults; the installer
|
|
|
110
110
|
| Harness | Skills | Subagents | Hooks | Plugin / rules |
|
|
111
111
|
|---|---|---|---|---|
|
|
112
112
|
| Claude Code / Claude Desktop | `~/.claude/skills` | `~/.claude/agents` | `~/.claude/hooks` + `settings.json` (GO gate, graph gate, env-file protection, Conventional Commits, memB inject, trail relay) | `.claude-plugin/` manifest ships in the repo (see Contributing) |
|
|
113
|
-
| Google Antigravity | `~/.gemini/config/skills` | `~/.gemini/config/agents` | `~/.gemini/config/hooks.json` and `~/.gemini/antigravity-cli/hooks.json` |
|
|
114
|
-
| Codex CLI | `~/.codex/skills` | `~/.codex/agents` | `~/.codex/hooks` + `config.toml` | `.codex-plugin/` |
|
|
115
|
-
| OpenCode | `~/.config/opencode/skills` | `~/.opencode/agents` | via plugin | `bdb-aos.js` plugin + `/startcycle-graph` command, registered in `opencode.jsonc`; keeps a `/startcycle-graph` run moving on `session.idle
|
|
113
|
+
| Google Antigravity | `~/.gemini/config/skills` | `~/.gemini/config/agents` | `~/.gemini/config/hooks.json` and `~/.gemini/antigravity-cli/hooks.json` | root `plugin.json` / `plugins/bdb-aos/plugin.json`, commands `/bdb-aos:<cmd>`, see [docs/codex-agy-setup.md](docs/codex-agy-setup.md) |
|
|
114
|
+
| Codex CLI | `~/.codex/skills` | `~/.codex/agents` | `~/.codex/hooks` + `config.toml` | `.codex-plugin/` + `.agents/plugins/marketplace.json`, commands `$bdb-aos:<cmd>`, see [docs/codex-agy-setup.md](docs/codex-agy-setup.md) |
|
|
115
|
+
| OpenCode | `~/.config/opencode/skills` | `~/.opencode/agents` | via plugin | `bdb-aos.js` plugin + `/startcycle-graph` command, registered in `opencode.jsonc`; keeps a `/startcycle-graph` run moving on `session.idle`; generated `/bdb-aos-<cmd>` commands; opt-in extras, see [docs/opencode-setup.md](docs/opencode-setup.md) |
|
|
116
116
|
| Cursor | `~/.cursor/skills` | — | — | `.cursor/rules` (project) |
|
|
117
117
|
| Windsurf | `~/.windsurf/bdb-skills` | — | — | `mcp.json` |
|
|
118
118
|
| Roo Code / Cline | `~/.roo/skills` | — | — | `.roomodes` (project) |
|
|
119
119
|
| Aider | `~/.aider/bdb-skills` | — | — | — |
|
|
120
120
|
| AOS CLI (`pi`) | reads `~/.agents/skills` | `~/.agents/AGENTS.md` as system prompt | — | no MCP; separate install, Node >= 22.19 — see [packages/aos-cli](packages/aos-cli/README.md) |
|
|
121
|
+
| BDB AO Codenotch (macOS app, Windows installer) | macOS `/Applications` or `~/Applications`; Windows per-user NSIS install (`/S`, no admin) | — | — | installed by default on macOS and Windows (never Linux); opt out with `--no-codenotch` or `AOS_CODENOTCH=0`; failures only warn; DMG from the public releases repo created by Tim, SHA-256 verified, ad-hoc signed with quarantine removed, see [docs/codenotch.md](docs/codenotch.md) |
|
|
121
122
|
|
|
122
123
|
Every install also writes the universal copy to `~/.agents/skills`, which is what the AOS CLI and the `skills` CLI read.
|
|
123
124
|
|
|
@@ -431,7 +432,7 @@ aos-uninstall --purge # also removes ~/.MemBDB, ~/.openwiki, ~/.synapse, ~/
|
|
|
431
432
|
aos-uninstall --dry-run # list everything, delete nothing
|
|
432
433
|
```
|
|
433
434
|
|
|
434
|
-
The uninstaller works from the install manifest: a file that still matches the hash AOS wrote is removed, a file you edited is backed up instead, a file AOS never wrote is not touched. The same action is in the installer menu.
|
|
435
|
+
The uninstaller works from the install manifest: a file that still matches the hash AOS wrote is removed, a file you edited is backed up instead, a file AOS never wrote is not touched. The same action is in the installer menu. `aos-uninstall --restore-plugin-backup` restores the loose skill copies the installer removed when it registered the plugin; see [docs/plugin-migration.md](docs/plugin-migration.md).
|
|
435
436
|
|
|
436
437
|
---
|
|
437
438
|
|