@hybridlabor-api/aos 4.13.1 → 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.
Files changed (151) hide show
  1. package/.agents/AGENTS.md +8 -0
  2. package/.agents/nodes.json +5 -2
  3. package/.claude/hooks/conventional-commits.mjs +14 -15
  4. package/.claude/hooks/env-file-protection.mjs +14 -15
  5. package/.claude/hooks/go-gate.mjs +157 -13
  6. package/.claude/hooks/go-token.mjs +55 -0
  7. package/.claude/hooks/memb-inject.mjs +75 -62
  8. package/.claude/hooks/trail-autostart.mjs +27 -0
  9. package/.claude/settings.json +18 -0
  10. package/.claude/workflows/startcycle-dispatch.mjs +11 -4
  11. package/.opencode/plugins/bdb-aos.js +98 -121
  12. package/.opencode/plugins/lib/trail-autostart.js +38 -0
  13. package/CLAUDE.md +1 -1
  14. package/README.de.md +6 -10
  15. package/README.md +6 -10
  16. package/README.pt.md +6 -10
  17. package/THIRD_PARTY_NOTICES.md +19 -3
  18. package/assets/header-v5.png +0 -0
  19. package/bin/aos-acp.mjs +211 -0
  20. package/bin/aos-doctor.mjs +1 -1
  21. package/bin/aos-uninstall.mjs +2 -2
  22. package/docs/master-session-acp.md +51 -0
  23. package/installer.js +398 -65
  24. package/mcps/mcsc/packages/mcp/server.js +6 -7
  25. package/package.json +4 -3
  26. package/scripts/validate-skills.mjs +76 -0
  27. package/skills/basic/bdbmediastorm/SKILL.md +1 -1
  28. package/skills/basic/godmode-shipping/SKILL.md +3 -0
  29. package/skills/basic/master-session/SKILL.md +89 -0
  30. package/skills/basic/startcycle/SKILL.md +1 -1
  31. package/skills/basic/startcycle-graph/SKILL.md +2 -2
  32. package/skills/basic/startcycle-graph-user/SKILL.md +1 -1
  33. package/skills/basic/teamwork-preview/SKILL.md +1 -1
  34. package/skills/bdbrainstorm/SKILL.md +7 -1
  35. package/skills/global_config/agentic-harness-patterns/SKILL.md +257 -0
  36. package/skills/global_config/agentic-harness-patterns/metadata.json +10 -0
  37. package/skills/global_config/agentic-harness-patterns/references/agent-orchestration-pattern.md +97 -0
  38. package/skills/global_config/agentic-harness-patterns/references/bootstrap-sequence-pattern.md +106 -0
  39. package/skills/global_config/agentic-harness-patterns/references/context-engineering/compress-pattern.md +78 -0
  40. package/skills/global_config/agentic-harness-patterns/references/context-engineering/isolate-pattern.md +82 -0
  41. package/skills/global_config/agentic-harness-patterns/references/context-engineering/select-pattern.md +86 -0
  42. package/skills/global_config/agentic-harness-patterns/references/context-engineering-pattern.md +29 -0
  43. package/skills/global_config/agentic-harness-patterns/references/hook-lifecycle-pattern.md +111 -0
  44. package/skills/global_config/agentic-harness-patterns/references/memory-persistence-pattern.md +109 -0
  45. package/skills/global_config/agentic-harness-patterns/references/permission-gate-pattern.md +111 -0
  46. package/skills/global_config/agentic-harness-patterns/references/skill-runtime-pattern.md +104 -0
  47. package/skills/global_config/agentic-harness-patterns/references/task-decomposition-pattern.md +92 -0
  48. package/skills/global_config/agentic-harness-patterns/references/tool-registry-pattern.md +101 -0
  49. package/skills/global_config/agenttrail/SKILL.md +8 -0
  50. package/skills/global_config/agenttrail/bin/agenttrail.mjs +14 -0
  51. package/skills/global_config/agenttrail/bin/ensure.mjs +118 -0
  52. package/skills/global_config/aos-setup/scripts/aos-doctor.mjs +1 -1
  53. package/skills/global_config/bdb-memb-mcp/SKILL.md +4 -5
  54. package/skills/global_config/bdb-visual-edit/SKILL.md +51 -0
  55. package/skills/global_config/bdb-visual-edit/references/vite-react-source-attr.md +59 -0
  56. package/skills/global_config/bdb-visual-edit/scripts/pick-snippet.js +27 -0
  57. package/skills/global_config/bdb-visual-edit/scripts/sanitize-element.mjs +123 -0
  58. package/skills/global_config/factory-collect/SKILL.md +74 -0
  59. package/skills/global_config/factory-human-digest/SKILL.md +92 -0
  60. package/skills/global_config/factory-lookback/SKILL.md +95 -0
  61. package/skills/global_config/factory-review-prs/SKILL.md +63 -0
  62. package/skills/global_config/git-pr-review/SKILL.md +3 -0
  63. package/skills/global_config/grilling/SKILL.md +2 -0
  64. package/skills/global_config/mcsc/SKILL.md +1 -1
  65. package/skills/global_config/plan-arbiter/SKILL.md +125 -0
  66. package/skills/global_config/plan-canvas/SKILL.md +63 -9
  67. package/skills/global_config/plan-canvas/scripts/lib/loopback-guard.js +19 -3
  68. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/README.md +285 -0
  69. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/agent-trail.js +129 -0
  70. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/board-client.js +124 -0
  71. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/examples/demo-plan/canvas.mdx +19 -0
  72. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/examples/demo-plan/plan.mdx +18 -0
  73. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/examples/recap-demo/plan.mdx +72 -0
  74. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/examples/showcase/README.md +29 -0
  75. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/examples/showcase/architecture.json +30 -0
  76. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/examples/showcase/builder/00_architecture.html +14950 -0
  77. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/examples/showcase/builder/canvas.mdx +511 -0
  78. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/examples/showcase/builder/plan.mdx +208 -0
  79. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/examples/showcase/recap/plan.mdx +102 -0
  80. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/examples/showcase/standard/plan.md +136 -0
  81. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/examples/signup-storyboard/canvas.mdx +124 -0
  82. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/examples/signup-storyboard/plan.mdx +37 -0
  83. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/index.js +188 -0
  84. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/kit.js +123 -0
  85. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/mdx.js +411 -0
  86. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/render.js +1291 -0
  87. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/architecture/meta.json +1 -0
  88. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/architecture/plan.mdx +195 -0
  89. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/architecture/standard.md +95 -0
  90. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/bugfix/meta.json +1 -0
  91. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/bugfix/plan.mdx +105 -0
  92. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/bugfix/standard.md +76 -0
  93. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/feature/canvas.mdx +81 -0
  94. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/feature/meta.json +1 -0
  95. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/feature/plan.mdx +145 -0
  96. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/feature/standard.md +76 -0
  97. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/migration/meta.json +1 -0
  98. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/migration/plan.mdx +172 -0
  99. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/migration/standard.md +100 -0
  100. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/recap/meta.json +1 -0
  101. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/recap/plan.mdx +67 -0
  102. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/recap/standard.md +49 -0
  103. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/recap-board/canvas.mdx +63 -0
  104. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/recap-board/meta.json +1 -0
  105. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/recap-board/plan.mdx +49 -0
  106. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/recap-board/standard.md +39 -0
  107. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/recap-review/meta.json +1 -0
  108. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/recap-review/plan.mdx +118 -0
  109. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/recap-review/standard.md +57 -0
  110. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/release/meta.json +1 -0
  111. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/release/plan.mdx +173 -0
  112. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/release/standard.md +96 -0
  113. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/research/meta.json +1 -0
  114. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/research/plan.mdx +91 -0
  115. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/research/standard.md +54 -0
  116. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/show-control/canvas.mdx +53 -0
  117. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/show-control/meta.json +1 -0
  118. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/show-control/plan.mdx +225 -0
  119. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/templates/show-control/standard.md +111 -0
  120. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/theme.css +472 -0
  121. package/skills/global_config/plan-canvas/scripts/lib/plan-builder/trail.js +216 -0
  122. package/skills/global_config/plan-canvas/scripts/lib/plan-canvas/markdown.js +1 -1
  123. package/skills/global_config/plan-canvas/scripts/lib/plan-canvas/server.js +37 -4
  124. package/skills/global_config/plan-canvas/scripts/lib/plan-canvas/ui.js +125 -29
  125. package/skills/global_config/plan-canvas/scripts/plan-canvas.js +196 -8
  126. package/skills/global_config/pr-recap/SKILL.md +47 -0
  127. package/skills/global_config/pr-recap/scripts/pr-recap.mjs +200 -0
  128. package/skills/global_config/quick-recap/SKILL.md +55 -0
  129. package/skills/global_config/stay-within-limits/SKILL.md +85 -0
  130. package/skills/global_config/triage/SKILL.md +3 -0
  131. package/skills/global_config/visual-edit/README.md +96 -0
  132. package/skills/global_config/visual-edit/SKILL.md +615 -0
  133. package/skills/global_config/visual-plan/README.md +93 -0
  134. package/skills/global_config/visual-plan/SKILL.md +544 -0
  135. package/skills/global_config/visual-plan/references/canvas.md +139 -0
  136. package/skills/global_config/visual-plan/references/connection.md +51 -0
  137. package/skills/global_config/visual-plan/references/document-quality.md +186 -0
  138. package/skills/global_config/visual-plan/references/exemplar.md +62 -0
  139. package/skills/global_config/visual-plan/references/local-files.md +99 -0
  140. package/skills/global_config/visual-plan/references/wireframe.md +319 -0
  141. package/skills/global_config/visual-recap/README.md +103 -0
  142. package/skills/global_config/visual-recap/SKILL.md +560 -0
  143. package/skills/global_config/visual-recap/references/connection.md +51 -0
  144. package/skills/global_config/visual-recap/references/local-files.md +99 -0
  145. package/skills/global_config/visual-recap/references/wireframe.md +319 -0
  146. package/skills/playbooks/pb-ci-fix/SKILL.md +49 -0
  147. package/skills/playbooks/pb-event-tracker/SKILL.md +45 -0
  148. package/skills/playbooks/pb-meeting-actions/SKILL.md +42 -0
  149. package/skills/playbooks/pb-project-new/SKILL.md +48 -0
  150. package/skills/playbooks/pb-week-plan/SKILL.md +45 -0
  151. package/assets/header-v4.jpg +0 -0
@@ -309,7 +309,7 @@ dependency.
309
309
 
310
310
  <https://github.com/BuilderIO/skills> — MIT. Copyright (c) 2026 Builder.io.
311
311
 
312
- One skill adapted into `skills/global_config/read-the-damn-docs/SKILL.md`:
312
+ Eleven skills are adapted under `skills/global_config/`: `read-the-damn-docs`, `stay-within-limits`, `quick-recap`, `plan-arbiter`, `factory-human-digest`, `factory-collect`, `factory-lookback`, `factory-review-prs`, `visual-plan`, `visual-recap`, and `visual-edit`. The four Factory skills and `plan-arbiter` have `installer-group` dropped and `category`/`source` added; in `factory-collect`, `factory-lookback` and `factory-review-prs` reply, close, approve, merge and publish actions are reduced to drafts or readiness reports that need the user's GO, and all of them carry an "AOS safety rules" section. `plan-arbiter` drops `agents/openai.yaml` and adds an AOS section on double plans. `stay-within-limits` and `quick-recap` are carried over with `category:` and `source:` added; `stay-within-limits` pins `ccusage` to 20.0.26 instead of `@latest`, and `quick-recap` no longer asks the installer to inject a managed `AGENTS.md` / `CLAUDE.md` block. The three visual skills (`visual-plan`, `visual-recap`, `visual-edit`) are optional and drive the Agent-Native Plan/Design services through MCP connectors (`plan` and `design`) that AOS does NOT register; you connect them yourself if needed. Each carries an "AOS notes" section. `read-the-damn-docs` is described below:
313
313
  the docs-first trigger list, the source hierarchy, the required workflow, the
314
314
  must-trigger examples, and the "if docs are unavailable" rule. AOS additionally
315
315
  adds a Verification section, a `category:` key (Builder's own validator forbids
@@ -318,8 +318,8 @@ guesswork* rule, and a pointer to the installed `firecrawl-search` /
318
318
  `firecrawl-scrape` tools. Prose only — the upstream `agents/openai.yaml` and
319
319
  README were not carried over, and no executable from the repo is referenced.
320
320
 
321
- The other 22 skills in that repo are **not** vendored. Six of them
322
- (`visual-plan`, `visual-recap`, `visual-edit`, `an`, `turn-into-app`, `rewind`)
321
+ In the three visual skills, five path-like mentions (`/sign-in`, `/live-edit-bridge`, `/read-file`, `/write-file`, `/visualize-repo`) were reworded so the AOS validator does not read them as skill references. The other 13 skills in that repo (as of commit 0dba9ef) are **not** vendored. Three of them
322
+ (`an`, `turn-into-app`, `rewind`) plus three others
323
323
  are build artefacts synced from a different upstream by
324
324
  `scripts/sync-agent-native-skills.mjs`, and the repo's own documentation says
325
325
  not to treat them as standalone. Its `.mcp.json` and plugin manifests register
@@ -511,3 +511,19 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
511
511
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
512
512
  SOFTWARE.
513
513
  ```
514
+
515
+ ---
516
+
517
+ ## keli-wen/agentic-harness-patterns-skill
518
+
519
+ - **Upstream:** <https://github.com/keli-wen/agentic-harness-patterns-skill> (commit 17549f5)
520
+ - **License:** MIT
521
+ - **Copyright:** Copyright (c) 2026
522
+
523
+ Ported to `skills/global_config/agentic-harness-patterns/` (English variant only; the `-zh` variant is not shipped):
524
+
525
+ | File | Upstream source |
526
+ |---|---|
527
+ | `skills/global_config/agentic-harness-patterns/SKILL.md` | `skills/agentic-harness-patterns/SKILL.md` (frontmatter: added `category` and `metadata`) |
528
+ | `skills/global_config/agentic-harness-patterns/metadata.json` | `skills/agentic-harness-patterns/metadata.json` |
529
+ | `skills/global_config/agentic-harness-patterns/references/**` | `skills/agentic-harness-patterns/references/**` (unchanged) |
Binary file
@@ -0,0 +1,211 @@
1
+ #!/usr/bin/env node
2
+ // aos-acp — minimal ACP (Agent Client Protocol) client for the master-session
3
+ // skill. Spawns one ACP agent over stdio JSON-RPC, runs one prompt, streams the
4
+ // agent's text to stdout and a JSONL run log, and maps session/request_permission
5
+ // onto the AOS GO gate: guarded commands (same list as go-gate.mjs) are approved
6
+ // only with a valid GO token (~/.aos/go/<name>.token), everything else follows
7
+ // --allow-default (deny unless told otherwise). No AO daemon, no dependencies.
8
+ //
9
+ // aos-acp <claude|codex|opencode|agy> --name <worker> [--cwd <dir>]
10
+ // (--prompt "<text>" | --prompt-file <f>) [--allow-default deny|allow]
11
+ // [--go-wait <sec>] [--consume|--no-consume] [--log <file>]
12
+ // [--timeout <sec>] [--cmd "<custom agent command>"]
13
+
14
+ import { spawn } from "node:child_process";
15
+ import { appendFileSync, mkdirSync, readFileSync, realpathSync } from "node:fs";
16
+ import { homedir } from "node:os";
17
+ import { dirname, join } from "node:path";
18
+ import { fileURLToPath } from "node:url";
19
+ import { createInterface } from "node:readline";
20
+ import { GUARDED_PATTERNS, slug, tokenGrantsGo } from "../.claude/hooks/go-gate.mjs";
21
+
22
+ export const ADAPTERS = {
23
+ claude: { cmd: ["npx", "-y", "@agentclientprotocol/claude-agent-acp"], consume: false },
24
+ codex: { cmd: ["npx", "-y", "@agentclientprotocol/codex-acp"], consume: true },
25
+ opencode: { cmd: ["opencode", "acp"], consume: false, cwdFlag: "--cwd" },
26
+ // antigravity-acp (MIT) is third-party; its README states that driving agy
27
+ // through it breaches Google's Antigravity terms. Not shipped: use mcsc.
28
+ agy: null,
29
+ };
30
+
31
+ export function commandOf(toolCall = {}) {
32
+ const r = toolCall.rawInput || {};
33
+ const c = r.command ?? r.cmd ?? r.script ?? r.CommandLine ?? "";
34
+ return Array.isArray(c) ? c.join(" ") : typeof c === "string" ? c : "";
35
+ }
36
+
37
+ export function isGuarded(cmd) {
38
+ return GUARDED_PATTERNS.some((re) => re.test(cmd));
39
+ }
40
+
41
+ function pickOption(options, kinds) {
42
+ for (const k of kinds) {
43
+ const o = options.find((x) => x.kind === k);
44
+ if (o) return o.optionId;
45
+ }
46
+ return null;
47
+ }
48
+
49
+ // Returns the JSON-RPC result for a session/request_permission.
50
+ export async function decidePermission(params, opts, log = () => {}) {
51
+ const options = params.options || [];
52
+ const cmd = commandOf(params.toolCall);
53
+ const guarded = !!cmd && isGuarded(cmd);
54
+ let allow = opts.allowDefault === "allow";
55
+ let reason = `default ${opts.allowDefault}`;
56
+ if (guarded) {
57
+ const deadline = Date.now() + (opts.goWait || 0) * 1000;
58
+ let r = tokenGrantsGo(opts.name, { consume: opts.consume });
59
+ if (!r.ok && opts.goWait) log("permission_pending", { command: cmd, waiting_s: opts.goWait });
60
+ while (!r.ok && Date.now() < deadline) {
61
+ await new Promise((res) => setTimeout(res, 1000));
62
+ r = tokenGrantsGo(opts.name, { consume: opts.consume });
63
+ }
64
+ allow = r.ok;
65
+ reason = r.ok ? "GO token" : r.reason;
66
+ }
67
+ const optionId = allow
68
+ ? pickOption(options, ["allow_once", "allow_always"])
69
+ : pickOption(options, ["reject_once", "reject_always"]);
70
+ log("permission", { command: cmd || null, title: params.toolCall?.title, guarded, allow, reason, optionId });
71
+ return optionId ? { outcome: { outcome: "selected", optionId } } : { outcome: { outcome: "cancelled" } };
72
+ }
73
+
74
+ export class AcpClient {
75
+ constructor(cmd, { cwd, env, onNotify, onRequest, log }) {
76
+ this.pending = new Map();
77
+ this.nextId = 1;
78
+ this.log = log;
79
+ this.child = spawn(cmd[0], cmd.slice(1), { cwd, env, stdio: ["pipe", "pipe", "pipe"] });
80
+ this.child.stderr.on("data", (d) => log("agent_stderr", { text: String(d).trimEnd() }));
81
+ this.exited = new Promise((res) => this.child.on("exit", (code, sig) => {
82
+ for (const p of this.pending.values()) p.reject(new Error(`agent exited (${code ?? sig})`));
83
+ res(code);
84
+ }));
85
+ createInterface({ input: this.child.stdout }).on("line", async (line) => {
86
+ let msg;
87
+ try { msg = JSON.parse(line); } catch { return log("agent_stdout", { text: line }); }
88
+ if (msg.method && msg.id !== undefined) {
89
+ try {
90
+ const result = await onRequest(msg.method, msg.params || {});
91
+ this.write({ jsonrpc: "2.0", id: msg.id, result });
92
+ } catch (e) {
93
+ this.write({ jsonrpc: "2.0", id: msg.id, error: { code: -32601, message: e.message } });
94
+ }
95
+ } else if (msg.method) {
96
+ onNotify(msg.method, msg.params || {});
97
+ } else if (this.pending.has(msg.id)) {
98
+ const p = this.pending.get(msg.id);
99
+ this.pending.delete(msg.id);
100
+ msg.error ? p.reject(new Error(`${msg.error.code}: ${msg.error.message}`)) : p.resolve(msg.result);
101
+ }
102
+ });
103
+ }
104
+ write(obj) { this.child.stdin.write(JSON.stringify(obj) + "\n"); }
105
+ request(method, params) {
106
+ const id = this.nextId++;
107
+ this.log("send", { method, params });
108
+ return new Promise((resolve, reject) => {
109
+ this.pending.set(id, { resolve, reject });
110
+ this.write({ jsonrpc: "2.0", id, method, params });
111
+ });
112
+ }
113
+ notify(method, params) { this.write({ jsonrpc: "2.0", method, params }); }
114
+ }
115
+
116
+ function textOf(block) {
117
+ return block && block.type === "text" ? block.text : "";
118
+ }
119
+
120
+ export async function run(opts) {
121
+ const logFile = opts.log || join(homedir(), ".aos", "acp", `${slug(opts.name)}.jsonl`);
122
+ mkdirSync(dirname(logFile), { recursive: true });
123
+ const log = (event, data = {}) => {
124
+ try { appendFileSync(logFile, JSON.stringify({ ts: new Date().toISOString(), name: opts.name, event, ...data }) + "\n"); } catch { /* best effort */ }
125
+ };
126
+
127
+ const adapter = ADAPTERS[opts.adapter];
128
+ const cmd = opts.cmd ? ["sh", "-c", opts.cmd] : adapter?.cmd;
129
+ if (!cmd) throw new Error(opts.adapter === "agy"
130
+ ? "agy has no sanctioned ACP adapter (antigravity-acp breaches Google's Antigravity terms); delegate via the mcsc skill instead"
131
+ : `unknown adapter "${opts.adapter}" (claude|codex|opencode)`);
132
+ if (adapter?.cwdFlag && !opts.cmd) cmd.push(adapter.cwdFlag, opts.cwd);
133
+ const consume = opts.consume ?? adapter?.consume ?? true;
134
+ log("start", { adapter: opts.adapter, cmd: cmd.join(" "), cwd: opts.cwd, allow_default: opts.allowDefault, consume });
135
+
136
+ let sessionId;
137
+ const out = opts.stdout || process.stdout;
138
+ const client = new AcpClient(cmd, {
139
+ cwd: opts.cwd,
140
+ env: { ...process.env, AOS_SESSION_NAME: opts.name, AOS_ACP_CLIENT: "1" },
141
+ log,
142
+ onNotify: (method, p) => {
143
+ if (method !== "session/update") return log("notify", { method, params: p });
144
+ const u = p.update || {};
145
+ if (u.sessionUpdate === "agent_message_chunk") {
146
+ const t = textOf(u.content);
147
+ if (t) { out.write(t); log("text", { text: t }); }
148
+ } else if (u.sessionUpdate === "tool_call" || u.sessionUpdate === "tool_call_update") {
149
+ log(u.sessionUpdate, { id: u.toolCallId, title: u.title, kind: u.kind, status: u.status, command: commandOf(u) || undefined });
150
+ } else log("update", { kind: u.sessionUpdate });
151
+ },
152
+ onRequest: (method, p) => {
153
+ if (method === "session/request_permission") return decidePermission(p, { ...opts, consume }, log);
154
+ throw new Error(`client does not implement ${method}`);
155
+ },
156
+ });
157
+
158
+ const cancel = () => { if (sessionId) client.notify("session/cancel", { sessionId }); setTimeout(() => client.child.kill("SIGKILL"), 5000).unref(); };
159
+ process.once("SIGINT", cancel);
160
+ process.once("SIGTERM", cancel);
161
+ const timer = opts.timeout ? setTimeout(() => { log("timeout", {}); cancel(); }, opts.timeout * 1000) : null;
162
+
163
+ try {
164
+ const init = await client.request("initialize", {
165
+ protocolVersion: 1,
166
+ clientCapabilities: { fs: { readTextFile: false, writeTextFile: false }, terminal: false },
167
+ clientInfo: { name: "aos-acp", version: "0.1.0" },
168
+ });
169
+ log("initialized", { agent: init?.agentInfo, auth: init?.authMethods });
170
+ ({ sessionId } = await client.request("session/new", { cwd: opts.cwd, mcpServers: [] }));
171
+ log("session", { sessionId });
172
+ const res = await client.request("session/prompt", { sessionId, prompt: [{ type: "text", text: opts.prompt }] });
173
+ out.write("\n");
174
+ log("done", { stopReason: res?.stopReason });
175
+ return res?.stopReason === "end_turn" ? 0 : 1;
176
+ } catch (e) {
177
+ log("error", { message: e.message });
178
+ throw e;
179
+ } finally {
180
+ if (timer) clearTimeout(timer);
181
+ client.child.kill();
182
+ }
183
+ }
184
+
185
+ export function parseArgs(argv) {
186
+ const o = { adapter: argv[0], cwd: process.cwd(), allowDefault: "deny", goWait: 0 };
187
+ for (let i = 1; i < argv.length; i++) {
188
+ const a = argv[i], v = argv[i + 1];
189
+ if (a === "--name") o.name = v, i++;
190
+ else if (a === "--cwd") o.cwd = v, i++;
191
+ else if (a === "--prompt") o.prompt = v, i++;
192
+ else if (a === "--prompt-file") o.prompt = readFileSync(v, "utf8"), i++;
193
+ else if (a === "--allow-default") o.allowDefault = v, i++;
194
+ else if (a === "--go-wait") o.goWait = Number(v), i++;
195
+ else if (a === "--timeout") o.timeout = Number(v), i++;
196
+ else if (a === "--log") o.log = v, i++;
197
+ else if (a === "--cmd") o.cmd = v, i++;
198
+ else if (a === "--consume") o.consume = true;
199
+ else if (a === "--no-consume") o.consume = false;
200
+ else throw new Error(`unknown argument ${a}`);
201
+ }
202
+ if (!o.adapter || !o.name || !o.prompt) throw new Error("usage: aos-acp <claude|codex|opencode> --name <worker> --prompt <text> [--cwd <dir>] [--allow-default deny|allow] [--go-wait <sec>] [--no-consume] [--log <file>] [--timeout <sec>]");
203
+ if (!["deny", "allow"].includes(o.allowDefault)) throw new Error("--allow-default must be deny or allow");
204
+ return o;
205
+ }
206
+
207
+ const invokedAs = (() => { try { return realpathSync(process.argv[1] || ""); } catch { return ""; } })();
208
+ if (invokedAs === fileURLToPath(import.meta.url)) {
209
+ Promise.resolve().then(() => run(parseArgs(process.argv.slice(2))))
210
+ .then((code) => process.exit(code), (e) => { console.error(`aos-acp: ${e.message}`); process.exit(2); });
211
+ }
@@ -201,7 +201,7 @@ function checkHarnesses() {
201
201
  // ---------------------------------------------------------------- 4. Hooks & Security Gates
202
202
  function checkHooks() {
203
203
  const claudeHooksDir = h('.claude', 'hooks');
204
- const EXPECTED_VERSION = { 'memb-inject.mjs': 6 };
204
+ const EXPECTED_VERSION = { 'memb-inject.mjs': 7 };
205
205
  const versionOf = (text) => {
206
206
  const m = /^\/\/\s*aos-hook-version:\s*(\d+)/m.exec(text);
207
207
  return m ? Number(m[1]) : null;
@@ -45,7 +45,7 @@ const DATA_PATHS = [
45
45
 
46
46
  const AGENTS = [
47
47
  'com.bdb.memb.webui', 'com.bdb.synapse', 'com.bdb.openwiki.daemon',
48
- 'com.bdb.ao.daemon', 'com.bdb.agent-workspace', 'com.hybridlabor.bdb-remote',
48
+ 'com.bdb.ao.daemon', 'com.bdb.agent-workspace', 'com.hybridlabor.bdb-remote', 'com.bdb.plan-canvas',
49
49
  ];
50
50
 
51
51
  const MODULE_DIRS = ['memB', 'bdb-synapse', 'bdb-os-remote', 'bdb-dev-creator-extension',
@@ -244,7 +244,7 @@ function execute(p) {
244
244
  if (existsSync(settings)) {
245
245
  try {
246
246
  const s = JSON.parse(readFileSync(settings, 'utf8'));
247
- const bdb = ['go-gate.mjs', 'graph-gate.mjs', 'memb-inject.mjs', 'trail-relay.mjs'];
247
+ const bdb = ['go-gate.mjs', 'graph-gate.mjs', 'memb-inject.mjs', 'trail-relay.mjs', 'trail-autostart.mjs', 'conventional-commits.mjs', 'env-file-protection.mjs'];
248
248
  let touched = false;
249
249
  for (const [event, entries] of Object.entries(s.hooks || {})) {
250
250
  const kept = entries.filter((e) => !(e.hooks || []).some((x) => bdb.some((n) => String(x.command).includes(n))));
@@ -0,0 +1,51 @@
1
+ # Master session over ACP — phase 2 (implemented)
2
+
3
+ Status: `bin/aos-acp.mjs` ships. Facts below are tagged **[verified]** (checked against the ACP v1 schema, the adapter repos, or a live run on 2026-10-01) or **[open]**.
4
+
5
+ ## Goal
6
+
7
+ Let a master session (`skills/basic/master-session/SKILL.md`) start and steer Codex, OpenCode and Claude workers **without the AO daemon**, by acting as an ACP client itself. The AO daemon stays optional.
8
+
9
+ ## Protocol facts used
10
+
11
+ From `schema/v1/schema.json` + `meta.json` of agentclientprotocol/agent-client-protocol **[verified]**:
12
+
13
+ - Agent methods: `initialize` (`protocolVersion: 1`, `clientCapabilities`), `session/new` (`cwd`, `mcpServers` — both required; result `sessionId`), `session/prompt` (`sessionId`, `prompt: ContentBlock[]`; result `stopReason` ∈ `end_turn | max_tokens | max_turn_requests | refusal | cancelled`), `session/cancel` (notification).
14
+ - Client methods: `session/update` (notification; `update.sessionUpdate` ∈ `agent_message_chunk | agent_thought_chunk | tool_call | tool_call_update | plan | available_commands_update | usage_update | ...`, text in `update.content.text`), `session/request_permission` (request; `toolCall {toolCallId,title,kind,rawInput}`, `options [{optionId,name,kind: allow_once|allow_always|reject_once|reject_always}]`; answer `{outcome:{outcome:'selected',optionId}}` or `{outcome:{outcome:'cancelled'}}`), plus `fs/*` and `terminal/*`, which `aos-acp` does not advertise and answers with `-32601`.
15
+
16
+ ## Adapters
17
+
18
+ | Harness | Command | Live smoke (`reply with OK`, temp dir) | Inner AOS gate | Token consumed by |
19
+ |---|---|---|---|---|
20
+ | opencode | `opencode acp --cwd <dir>` (opencode 1.18.30) | **[verified]** `OK`, `end_turn` | OpenCode plugin `bdb-aos.js` (loads in ACP mode; `--pure` would disable it) | plugin (`aos-acp` verifies only) |
21
+ | claude | `npx -y @agentclientprotocol/claude-agent-acp` (Apache-2.0) | **[verified]** `OK`, `end_turn` | the user's Claude Code hooks run inside the SDK session — `go-gate` blocked a `git push` **[verified]** | hook (`aos-acp` verifies only) |
22
+ | codex | `npx -y @agentclientprotocol/codex-acp` (Apache-2.0, v2.1.0) | handshake **[verified]**; `session/new` → `-32000 Authentication required` (no `OPENAI_API_KEY`/ChatGPT login on this machine) **[open]** | none | `aos-acp` |
23
+ | agy | — | — | go-gate via `hooks.json` (name from `AOS_SESSION_NAME`) | — |
24
+
25
+ agy: the only adapter is third-party `shubzkothekar/antigravity-acp` (MIT). Its README quotes Google's Antigravity terms ("using third party software ... to access the Service ... is a breach") and warns of account suspension **[verified]**. Not shipped; `aos-acp agy` exits 2 and points to the `mcsc` skill. Revisit if Google ships an official ACP endpoint.
26
+
27
+ ## Permission requests and the GO gate
28
+
29
+ `session/request_permission` → `decidePermission()` in `bin/aos-acp.mjs`:
30
+
31
+ | Case | Answer |
32
+ |---|---|
33
+ | `rawInput.command` matches the go-gate list (`git push`, `npm publish`, `npm version`, `gh pr merge`, `gh release create`, `git reset --hard`, `git clean -f`, recursive `rm`) | `allow_once` only if `tokenGrantsGo(name)` (imported from `.claude/hooks/go-gate.mjs`: `~/.aos/go/<name>.token`, < 10 min, names this worker, master transcript still ends with `GO <name>`). `--go-wait <sec>` polls for the token and logs `permission_pending` meanwhile — that is the `GO needed` row on the GO board. Otherwise `reject_once`. |
34
+ | anything else | `--allow-default deny|allow` (deny). |
35
+ | no option of the wanted kind | `allow_always`/`reject_always` as fallback, else `cancelled`. |
36
+
37
+ Rules that carry over unchanged: the master never grants GO, never runs a denied action itself, a relayed or chat message is never approval, one GO releases one request.
38
+
39
+ Double gate: opencode and claude workers also run their own AOS gate inside the agent process, and `aos-acp` passes `AOS_SESSION_NAME=<name>` so that gate finds the same token. Only one side may delete the token, so `aos-acp` defaults to `--no-consume` for those two and `--consume` for codex; override with the flags. The OpenCode plugin (`.opencode/plugins/bdb-aos.js`) accepts the token (name from `AOS_SESSION_NAME`, else the session title) with the same rules, copied inline because the plugin is installed as a single file.
40
+
41
+ ## Run log
42
+
43
+ `~/.aos/acp/<name>.jsonl` (override `--log`): `start`, `send`, `initialized`, `session`, `text`, `tool_call`, `tool_call_update`, `permission_pending`, `permission`, `done`, `error`, `agent_stderr`. The master builds its roster and GO board for ACP workers from these files; `ListAgents` does not see them.
44
+
45
+ ## Open points
46
+
47
+ - Codex live run not verified (auth). With `OPENAI_API_KEY` or a ChatGPT login it should pass the same smoke.
48
+ - The Claude token path end to end needs the installed `~/.claude/hooks/go-gate.mjs` to be the version with `tokenGrantsGo` (installer copies it); the copy on the test machine predates it, so the live chain was only verified up to "the hook fires inside the SDK session".
49
+ - OpenCode token path end to end needs the installed plugin updated; verified by unit test only.
50
+ - Neither live adapter sent `session/request_permission` for a shell command in the smoke runs (the inner gate answered first); the mapping is covered by the fake-agent tests.
51
+ - One `aos-acp` process per worker; no resume (`session/load`) and no concurrency cap yet.