@hybridlabor-api/aos 4.13.2 → 4.14.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.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/hooks/trail-relay.mjs +1 -0
- package/.claude/settings.json +22 -4
- 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 +314 -42
- 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/THIRD_PARTY_NOTICES.md
CHANGED
|
@@ -309,7 +309,7 @@ dependency.
|
|
|
309
309
|
|
|
310
310
|
<https://github.com/BuilderIO/skills> — MIT. Copyright (c) 2026 Builder.io.
|
|
311
311
|
|
|
312
|
-
|
|
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
|
|
322
|
-
(`
|
|
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
|
package/bin/aos-acp.mjs
ADDED
|
@@ -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
|
+
}
|
package/bin/aos-doctor.mjs
CHANGED
|
@@ -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':
|
|
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;
|
package/bin/aos-uninstall.mjs
CHANGED
|
@@ -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', 'conventional-commits.mjs', 'env-file-protection.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.
|