@hybridlabor-api/aos 4.7.0 → 4.7.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 -3
- package/.agents/nodes.json +2 -1
- package/.agents/state.schema.json +24 -0
- package/.agents/vendor-manifest.json +6 -0
- package/.agents/workflows/startcycle-graph.md +2 -2
- package/.claude/agents/architect.md +5 -4
- package/.claude/agents/techlead.md +2 -0
- package/.claude/workflows/startcycle-dispatch.mjs +175 -17
- package/.opencode/agents/architect.md +5 -4
- package/.opencode/agents/techlead.md +2 -0
- package/THIRD_PARTY_NOTICES.md +9 -1
- package/bin/aos-doctor.mjs +366 -0
- package/bin/aos-store.mjs +167 -0
- package/docs/AUDIT_BRIEF_ECC_STORE.md +122 -0
- package/docs/PLAN_AOS_STORE_PHASE1.md +190 -0
- package/installer.js +41 -1
- package/lib/aos-archify-contract.mjs +277 -0
- package/lib/ecc-store-index.json +1 -0
- package/mcp_config.json +4 -0
- package/mcps/mcsc/packages/core/src/adapters/codex.js +160 -37
- package/package.json +6 -2
- package/scripts/build-ecc-store-index.mjs +147 -0
- package/skills/basic/startcycle-graph/SKILL.md +13 -0
- package/skills/global_config/agenttrail/bin/agenttrail.mjs +153 -42
- package/skills/global_config/agenttrail/public/index.html +5 -4
- package/skills/global_config/archify/examples/dataflow-product-analytics.html +15048 -0
- package/skills/global_config/archify/examples/lifecycle-agent-run.html +14983 -0
- package/skills/global_config/archify/examples/sequence-cache-miss-request.html +15063 -0
- package/skills/global_config/archify/examples/web-app-rendered.html +15012 -0
- package/skills/global_config/archify/examples/workflow-agent-tool-call-rendered.html +15054 -0
- package/skills/global_config/ask-tim/SKILL.md +10 -0
- package/skills/global_config/mcsc/SKILL.md +60 -0
- package/skills/global_config/plan-canvas/scripts/lib/plan-canvas/server.js +31 -6
- package/skills/global_config/plan-canvas/scripts/plan-canvas.js +4 -2
|
@@ -41,6 +41,16 @@ Reach for `test-driven-development` or `tdd-workflow` on their own when you want
|
|
|
41
41
|
|
|
42
42
|
**Forcing a specific skill into a run:** `--skill=<name>` on any startcycle variant makes it a hard requirement — for a private skill of your own no node would otherwise reach for. Validated before the run starts; a name that does not resolve halts rather than proceeding without it.
|
|
43
43
|
|
|
44
|
+
## Outside the core: the ECC store
|
|
45
|
+
|
|
46
|
+
When no native AOS skill fits, search the markdown-only ECC store before starting a pipeline:
|
|
47
|
+
|
|
48
|
+
- `aos store search <query>` finds available fallback skills and agents.
|
|
49
|
+
- `aos store install <name>` installs a verified item after explicit user action.
|
|
50
|
+
- `aos store list --type=skills` and `aos store list --type=agents` show the catalogue.
|
|
51
|
+
- The core remains the trusted AOS skill set; the store is a fallback, not a reason to bypass the startcycle validation.
|
|
52
|
+
- A missing `--skill` is reported by the dispatcher with the exact install command. It never downloads during a run.
|
|
53
|
+
|
|
44
54
|
---
|
|
45
55
|
|
|
46
56
|
## On-ramps
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: mcsc
|
|
3
|
+
description: Delegate a task to another installed CLI harness (Antigravity/agy, OpenCode, Codex) from inside an AOS repo. Use this instead of shelling out to that CLI directly whenever one is installed — it wraps the wrapper flags for you and streams live tool-call telemetry to agenttrail, which is why the board updates in real time. Reach for it any time you're about to delegate work to another harness.
|
|
4
|
+
category: bdb-core
|
|
5
|
+
metadata:
|
|
6
|
+
version: "0.1.0"
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# mcsc — Multi-CLI Subagent Configurator
|
|
10
|
+
|
|
11
|
+
mcsc (`mcps/mcsc/`) is AOS's own cross-harness delegation engine. It is the
|
|
12
|
+
mandatory path for delegating work to another CLI harness inside an
|
|
13
|
+
AOS-installed repo — not a Claude-Code-only convenience.
|
|
14
|
+
|
|
15
|
+
## Why this exists
|
|
16
|
+
|
|
17
|
+
Three separate, harness-specific delegation paths already exist (the Claude
|
|
18
|
+
Code plugins `antigravity:antigravity-delegate`, `opencode:opencode-rescue`,
|
|
19
|
+
`codex:codex-rescue` — see AGENTS.md's "Delegating to an external CLI"). Those
|
|
20
|
+
are fine for interactive delegation *from a Claude Code session*, but they are
|
|
21
|
+
Claude-Code-only, and none of them tell agenttrail's live board what is
|
|
22
|
+
happening. mcsc's adapters
|
|
23
|
+
(`mcps/mcsc/packages/core/src/adapters/{agy,codex,opencode}.js`) wrap each CLI
|
|
24
|
+
once, work from any harness, and call `emitTrail()` around every delegated run
|
|
25
|
+
— `SessionStart`/`SessionEnd`, plus live `PreToolUse`/`PostToolUse` where the
|
|
26
|
+
underlying CLI supports structured/streaming output — so a delegated run shows
|
|
27
|
+
up on the board the moment it starts, without any extra setup.
|
|
28
|
+
|
|
29
|
+
Skipping mcsc doesn't just lose convenience — it makes the delegated agent
|
|
30
|
+
invisible to anyone watching the live map, and to anyone in this repo who asks
|
|
31
|
+
"what are the other agents doing right now."
|
|
32
|
+
|
|
33
|
+
## How to use it
|
|
34
|
+
|
|
35
|
+
Once installed (`mcsc` in `mcp_config.json`, entry point
|
|
36
|
+
`mcps/mcsc/server.js`), it registers up to four MCP tools — one per
|
|
37
|
+
installed CLI, only exposed when that CLI is detected as `ready` in the local
|
|
38
|
+
inventory, and never offered back to a caller that's already running as that
|
|
39
|
+
same CLI (`MCSC_CALLER` env var, avoids self-delegation loops):
|
|
40
|
+
|
|
41
|
+
- `delegate_agy` — `{ prompt, model? }` → Antigravity / Gemini
|
|
42
|
+
- `delegate_opencode` — `{ prompt, model?, variant? }` → OpenCode
|
|
43
|
+
- `delegate_codex` — `{ prompt, model? }` → Codex
|
|
44
|
+
- `delegate_smart` — `{ task_type, prompt }` → reads `rulebook.yaml` (or the
|
|
45
|
+
bundled default) and picks the best CLI for that task type automatically
|
|
46
|
+
|
|
47
|
+
Call the tool that matches the harness you want, with a complete,
|
|
48
|
+
self-contained `prompt` — the adapter underneath handles the CLI's actual
|
|
49
|
+
flags, streams tool-call telemetry to agenttrail as it runs, and returns the
|
|
50
|
+
final output. `variant` (OpenCode only) maps to `--variant` (reasoning
|
|
51
|
+
effort).
|
|
52
|
+
|
|
53
|
+
## What it is not
|
|
54
|
+
|
|
55
|
+
- Not a replacement for the Claude Code delegation plugins for a quick,
|
|
56
|
+
interactive, single-turn ask inside a Claude Code session — those remain
|
|
57
|
+
fine for that case.
|
|
58
|
+
- Not itself a review/QA step — verify a delegated result the same way
|
|
59
|
+
AGENTS.md already says to: read the actual diff, never trust the returned
|
|
60
|
+
status field alone.
|
|
@@ -97,6 +97,23 @@ function readJsonBody(req) {
|
|
|
97
97
|
});
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
+
function isWithin(root, candidate) {
|
|
101
|
+
const relativePath = path.relative(root, candidate);
|
|
102
|
+
return relativePath === '' || (relativePath !== '..' && !relativePath.startsWith(`..${path.sep}`) && !path.isAbsolute(relativePath));
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function confinedArtifactPath(file, workspaceRoot) {
|
|
106
|
+
if (typeof file !== 'string' || file.length === 0 || /^[a-z][a-z0-9+.-]*:\/\//i.test(file)) return null;
|
|
107
|
+
try {
|
|
108
|
+
const root = fs.realpathSync(path.resolve(workspaceRoot));
|
|
109
|
+
const candidate = fs.realpathSync(path.isAbsolute(file) ? file : path.resolve(root, file));
|
|
110
|
+
if (!isWithin(root, candidate) || !fs.statSync(candidate).isFile()) return null;
|
|
111
|
+
return candidate;
|
|
112
|
+
} catch {
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
100
117
|
function sendJson(res, statusCode, payload) {
|
|
101
118
|
const body = JSON.stringify(payload);
|
|
102
119
|
res.writeHead(statusCode, { 'content-type': 'application/json; charset=utf-8', 'cache-control': 'no-store' });
|
|
@@ -120,6 +137,7 @@ function createPlanCanvasServer({
|
|
|
120
137
|
idleTimeoutMs = DEFAULT_IDLE_TIMEOUT_MS,
|
|
121
138
|
heartbeatMs = 15000,
|
|
122
139
|
thinkingStaleMs = DEFAULT_THINKING_STALE_MS,
|
|
140
|
+
workspaceRoot = process.cwd(),
|
|
123
141
|
typingExpiryMs = DEFAULT_TYPING_EXPIRY_MS,
|
|
124
142
|
presenceSweepMs = DEFAULT_PRESENCE_SWEEP_MS,
|
|
125
143
|
onIdleShutdown = null,
|
|
@@ -287,10 +305,11 @@ function createPlanCanvasServer({
|
|
|
287
305
|
if (!body.file || typeof body.file !== 'string') {
|
|
288
306
|
return sendJson(res, 400, { error: 'file is required' });
|
|
289
307
|
}
|
|
290
|
-
|
|
291
|
-
|
|
308
|
+
const artifactPath = confinedArtifactPath(body.file, workspaceRoot);
|
|
309
|
+
if (!artifactPath) {
|
|
310
|
+
return sendJson(res, 403, { error: 'artifact path is outside the workspace' });
|
|
292
311
|
}
|
|
293
|
-
const { session, refused } = store.open(
|
|
312
|
+
const { session, refused } = store.open(artifactPath, { reopen: Boolean(body.reopen) });
|
|
294
313
|
if (refused) {
|
|
295
314
|
return sendJson(res, 409, {
|
|
296
315
|
status: 'user-ended',
|
|
@@ -514,9 +533,15 @@ function createPlanCanvasServer({
|
|
|
514
533
|
|
|
515
534
|
// Sibling assets resolve relative to the artifact's directory and must
|
|
516
535
|
// stay confined to it.
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
536
|
+
let baseDir;
|
|
537
|
+
let resolved;
|
|
538
|
+
try {
|
|
539
|
+
baseDir = fs.realpathSync(path.dirname(session.file));
|
|
540
|
+
resolved = fs.realpathSync(path.resolve(baseDir, assetPath));
|
|
541
|
+
} catch {
|
|
542
|
+
return sendJson(res, 404, { error: 'asset not found' });
|
|
543
|
+
}
|
|
544
|
+
if (!isWithin(baseDir, resolved)) {
|
|
520
545
|
return sendJson(res, 403, { error: 'asset path escapes artifact directory' });
|
|
521
546
|
}
|
|
522
547
|
let data;
|
|
@@ -186,7 +186,8 @@ async function ensureServer({ stateDir, port }) {
|
|
|
186
186
|
const child = spawn(process.execPath, [__filename, 'server', '--port', String(port)], {
|
|
187
187
|
detached: true,
|
|
188
188
|
stdio: ['ignore', logFd, logFd],
|
|
189
|
-
env: { ...process.env, AOS_PLAN_CANVAS_STATE_DIR: stateDir }
|
|
189
|
+
env: { ...process.env, AOS_PLAN_CANVAS_STATE_DIR: stateDir },
|
|
190
|
+
shell: false
|
|
190
191
|
});
|
|
191
192
|
child.unref();
|
|
192
193
|
fs.closeSync(logFd);
|
|
@@ -204,7 +205,7 @@ function openBrowser(url) {
|
|
|
204
205
|
: platform === 'win32' ? ['cmd', ['/c', 'start', '', url]]
|
|
205
206
|
: ['xdg-open', [url]];
|
|
206
207
|
try {
|
|
207
|
-
spawn(cmd, args, { detached: true, stdio: 'ignore' }).unref();
|
|
208
|
+
spawn(cmd, args, { detached: true, stdio: 'ignore', shell: false }).unref();
|
|
208
209
|
return true;
|
|
209
210
|
} catch {
|
|
210
211
|
return false;
|
|
@@ -357,6 +358,7 @@ async function cmdServer(args, { stateDir, port }) {
|
|
|
357
358
|
};
|
|
358
359
|
const canvas = createPlanCanvasServer({
|
|
359
360
|
store,
|
|
361
|
+
workspaceRoot: process.cwd(),
|
|
360
362
|
host: hostArg || DEFAULT_HOST,
|
|
361
363
|
version: VERSION,
|
|
362
364
|
idleTimeoutMs: resolveIdleTimeoutMs(),
|