@voybio/ace-swarm 2.4.3 → 2.4.6
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/CHANGELOG.md +78 -0
- package/README.md +72 -532
- package/assets/agent-state/INTERFACE_REGISTRY.md +2 -2
- package/assets/agent-state/MODULES/gates/gate-autonomy.json +4 -2
- package/assets/agent-state/MODULES/gates/gate-completeness.json +4 -2
- package/assets/agent-state/MODULES/gates/gate-operability.json +4 -2
- package/assets/agent-state/MODULES/gates/gate-security.json +3 -1
- package/assets/agent-state/MODULES/registry.json +1 -4
- package/assets/agent-state/MODULES/roles/capability-build.json +1 -2
- package/assets/agent-state/MODULES/roles/capability-eval.json +1 -1
- package/assets/agent-state/MODULES/roles/capability-qa.json +1 -2
- package/assets/agent-state/QUALITY_GATES.md +25 -9
- package/assets/agent-state/TEAL_CONFIG.md +2 -11
- package/assets/eval-battery/battery.json +85 -0
- package/assets/eval-battery/fixtures/edit-target.js +3 -0
- package/assets/scripts/render-mcp-configs.sh +12 -0
- package/dist/ace-context.d.ts +18 -0
- package/dist/ace-context.js +161 -16
- package/dist/ace-server-instructions.js +36 -9
- package/dist/astgrep-index.d.ts +7 -1
- package/dist/astgrep-index.js +66 -39
- package/dist/bridge-trace.d.ts +17 -0
- package/dist/bridge-trace.js +23 -0
- package/dist/cli.d.ts +9 -1
- package/dist/cli.js +619 -10
- package/dist/discovery-runtime-wrappers.d.ts +16 -1
- package/dist/discovery-runtime-wrappers.js +65 -9
- package/dist/eval-harness.d.ts +110 -0
- package/dist/eval-harness.js +254 -0
- package/dist/experience-reflector.d.ts +13 -0
- package/dist/experience-reflector.js +62 -0
- package/dist/gate-contract.d.ts +63 -0
- package/dist/gate-contract.js +178 -0
- package/dist/goal-engine.d.ts +155 -0
- package/dist/goal-engine.js +795 -0
- package/dist/helpers/store-resolution.js +40 -39
- package/dist/hermes/session-manager.d.ts +10 -0
- package/dist/hermes/session-manager.js +130 -27
- package/dist/job-scheduler.d.ts +58 -0
- package/dist/job-scheduler.js +202 -2
- package/dist/job-worker.d.ts +87 -0
- package/dist/job-worker.js +182 -0
- package/dist/local-model-policy.d.ts +8 -2
- package/dist/local-model-policy.js +31 -17
- package/dist/local-model-runtime.d.ts +6 -0
- package/dist/local-model-runtime.js +130 -2
- package/dist/measured-classing.d.ts +66 -0
- package/dist/measured-classing.js +165 -0
- package/dist/model-bridge.d.ts +45 -0
- package/dist/model-bridge.js +502 -44
- package/dist/orchestrator-supervisor.js +1 -1
- package/dist/plan-proposal.d.ts +7 -0
- package/dist/plan-proposal.js +74 -4
- package/dist/playbook-adaptation.d.ts +37 -0
- package/dist/playbook-adaptation.js +159 -0
- package/dist/playbook-curator.d.ts +16 -0
- package/dist/playbook-curator.js +106 -0
- package/dist/playbook-llm-reflector.d.ts +26 -0
- package/dist/playbook-llm-reflector.js +157 -0
- package/dist/public-surface.d.ts +2 -0
- package/dist/public-surface.js +26 -14
- package/dist/runtime-executor.js +45 -2
- package/dist/runtime-tool-specs.d.ts +8 -1
- package/dist/runtime-tool-specs.js +19 -1
- package/dist/safe-edit.d.ts +20 -0
- package/dist/safe-edit.js +355 -78
- package/dist/schemas.js +16 -15
- package/dist/server.d.ts +11 -2
- package/dist/server.js +55 -5
- package/dist/shared.d.ts +12 -0
- package/dist/shared.js +13 -1
- package/dist/source-mutation-coordinator.d.ts +54 -0
- package/dist/source-mutation-coordinator.js +259 -0
- package/dist/status-events.d.ts +4 -1
- package/dist/status-events.js +41 -6
- package/dist/store/ace-packed-store.d.ts +28 -9
- package/dist/store/ace-packed-store.js +324 -57
- package/dist/store/bgzf.d.ts +4 -0
- package/dist/store/bgzf.js +94 -0
- package/dist/store/bootstrap-store.d.ts +4 -1
- package/dist/store/bootstrap-store.js +87 -9
- package/dist/store/cache-workspace.d.ts +8 -0
- package/dist/store/cache-workspace.js +67 -1
- package/dist/store/crc32.d.ts +2 -0
- package/dist/store/crc32.js +16 -0
- package/dist/store/fsck.d.ts +16 -0
- package/dist/store/fsck.js +240 -0
- package/dist/store/gate-contract-migration.d.ts +10 -0
- package/dist/store/gate-contract-migration.js +413 -0
- package/dist/store/materializers/context-snapshot-materializer.d.ts +1 -0
- package/dist/store/materializers/context-snapshot-materializer.js +4 -1
- package/dist/store/materializers/projection-manager.d.ts +7 -0
- package/dist/store/materializers/projection-manager.js +37 -0
- package/dist/store/materializers/scheduler-projection-materializer.js +10 -3
- package/dist/store/repositories/goal-repository.d.ts +112 -0
- package/dist/store/repositories/goal-repository.js +157 -0
- package/dist/store/repositories/playbook-repository.d.ts +107 -0
- package/dist/store/repositories/playbook-repository.js +314 -0
- package/dist/store/store-artifacts.js +44 -2
- package/dist/store/store-authority-audit.js +1 -0
- package/dist/store/store-cli.d.ts +30 -0
- package/dist/store/store-cli.js +242 -0
- package/dist/store/store-snapshot.d.ts +12 -0
- package/dist/store/store-snapshot.js +74 -11
- package/dist/store/types.d.ts +1 -0
- package/dist/store/write-coordinator.d.ts +7 -0
- package/dist/store/write-coordinator.js +11 -0
- package/dist/todo-state.d.ts +21 -0
- package/dist/todo-state.js +150 -53
- package/dist/tools-agent.js +86 -22
- package/dist/tools-discovery.js +5 -3
- package/dist/tools-files.js +107 -23
- package/dist/tools-framework.js +146 -40
- package/dist/tools-goal.d.ts +11 -0
- package/dist/tools-goal.js +108 -0
- package/dist/tools-handoff.js +7 -11
- package/dist/tools-lifecycle.js +2 -0
- package/dist/tools-scheduler.js +44 -1
- package/dist/tools-skills.js +3 -2
- package/dist/tools-todo.js +64 -3
- package/dist/tools.js +2 -0
- package/dist/tui/chat.js +4 -0
- package/dist/tui/index.js +4 -1
- package/dist/tui/ollama.d.ts +2 -0
- package/dist/tui/openai-compatible.d.ts +14 -0
- package/dist/tui/openai-compatible.js +15 -2
- package/dist/tui/provider-discovery.d.ts +1 -0
- package/dist/tui/provider-discovery.js +2 -2
- package/docs/cli-reference.md +125 -0
- package/docs/development.md +46 -0
- package/docs/evaluation-safety.md +27 -0
- package/docs/experience-playbook.md +35 -0
- package/docs/hermes.md +129 -0
- package/docs/library-api.md +31 -0
- package/docs/mcp-tool-reference.md +290 -0
- package/docs/provider-security.md +85 -0
- package/docs/state-model.md +113 -0
- package/docs/troubleshooting.md +95 -0
- package/docs/tui-operator-guide.md +75 -0
- package/package.json +5 -1
- package/scripts/dev/run_hermes_crispr_live.mjs +212 -0
- package/assets/agent-state/MODULES/gates/gate-correctness.json +0 -7
- package/assets/agent-state/MODULES/gates/gate-evaluation.json +0 -7
- package/assets/agent-state/MODULES/gates/gate-typescript-public-surface.json +0 -7
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# Troubleshooting
|
|
2
|
+
|
|
3
|
+
Start with the smallest command that distinguishes configuration, packed-state, provider, and model failures:
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
ace paths
|
|
7
|
+
ace fsck
|
|
8
|
+
ace doctor --scan
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Store and bootstrap
|
|
12
|
+
|
|
13
|
+
### No ACE store found
|
|
14
|
+
|
|
15
|
+
Run `ace init` or `ace turnkey` in the intended workspace. Confirm `ace paths` reports that directory as `WORKSPACE_ROOT`.
|
|
16
|
+
|
|
17
|
+
### Canonical and legacy stores both exist
|
|
18
|
+
|
|
19
|
+
`ace fsck` reports `store:legacy-dual-store`. Do not delete either file reflexively. Back up both, inspect their logical state with `ace ls`/`ace read`, migrate deliberately, verify the canonical store, then archive the legacy copy.
|
|
20
|
+
|
|
21
|
+
### Store/disk copies differ
|
|
22
|
+
|
|
23
|
+
Use full values, not abbreviations:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
ace read agent-state/STATUS.md --source
|
|
27
|
+
ace read agent-state/STATUS.md --prefer store
|
|
28
|
+
ace read agent-state/STATUS.md --prefer disk
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Store-first is normal. `ACE_STORE_FIRST=0` is a legacy diagnostic escape hatch.
|
|
32
|
+
|
|
33
|
+
### Corruption or quarantine
|
|
34
|
+
|
|
35
|
+
Run `ace fsck --json`. A `.corrupt-*` file is a preserved copy, not disposable litter. `ace repair` re-bakes known assets and projections; it does not reconstruct arbitrary corrupt bytes. Restore from a verified backup when structural checks cannot be repaired safely.
|
|
36
|
+
|
|
37
|
+
## Providers
|
|
38
|
+
|
|
39
|
+
### Ollama unreachable or model missing
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
ollama serve
|
|
43
|
+
ollama pull <model>
|
|
44
|
+
ace doctor --llm ollama --model <model> --base-url http://127.0.0.1:11434
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
`--repair-ollama` pulls a missing model and re-probes availability. Treat a nonzero doctor result as unresolved.
|
|
48
|
+
|
|
49
|
+
### llama.cpp endpoint mismatch
|
|
50
|
+
|
|
51
|
+
Use the OpenAI-compatible base, normally `http://127.0.0.1:8080/v1`, and check its model list before starting ACE.
|
|
52
|
+
|
|
53
|
+
### Hosted provider is discovered but chat fails
|
|
54
|
+
|
|
55
|
+
Discovery does not prove credentials. Confirm the provider's API key/base URL and run a provider-specific `ace doctor` command.
|
|
56
|
+
|
|
57
|
+
## Hermes
|
|
58
|
+
|
|
59
|
+
### Missing Python or Hermes checkout
|
|
60
|
+
|
|
61
|
+
Set `ACE_HERMES_ROOT` and either `HERMES_PYTHON`, `ACE_HERMES_UV_PROJECT`, or the advanced `ACE_HERMES_COMMAND_JSON`. Run `ace doctor ... --hermes` before the TUI or live driver.
|
|
62
|
+
|
|
63
|
+
### Live driver writes a report but no artifact
|
|
64
|
+
|
|
65
|
+
Inspect each report row's `status`, `job_done`, `protocol_done`, and `tool_write_done`. Any failed selected row makes the driver exit nonzero. A report path alone is not success.
|
|
66
|
+
|
|
67
|
+
### Hung turn
|
|
68
|
+
|
|
69
|
+
Interrupt the TUI with `Ctrl+C`. Hermes-local has an executor-owned turn timeout and child termination path; if the process survives, capture diagnostics and stop the session rather than launching a second concurrent mutation.
|
|
70
|
+
|
|
71
|
+
## Goals
|
|
72
|
+
|
|
73
|
+
### Goal remains planning or reports `contract_uncheckable`
|
|
74
|
+
|
|
75
|
+
Declare a required artifact or verification command:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
ace goal start "Implement the change" --verify "npm test"
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Detached goal failure
|
|
82
|
+
|
|
83
|
+
Use `ace goal status <goal_id>` and inspect `agent-state/goals/<goal_id>.log`. Active goal files are authoritative loose state and must be included in backups.
|
|
84
|
+
|
|
85
|
+
## Evaluation
|
|
86
|
+
|
|
87
|
+
The packaged battery is mutating. `ace eval` creates isolated per-run workspaces and records provenance; do not point an explicit unsafe-workspace option at a valuable checkout. See [Evaluation Safety and Reproducibility](evaluation-safety.md).
|
|
88
|
+
|
|
89
|
+
## Package and development
|
|
90
|
+
|
|
91
|
+
If `npm pack` fails under `~/.npm/_cacache` with ownership errors, use a writable temporary npm cache for diagnosis. Do not change ownership or delete a shared cache without understanding the host policy.
|
|
92
|
+
|
|
93
|
+
## Escalation evidence
|
|
94
|
+
|
|
95
|
+
Include the exact command, exit code, relevant doctor/fsck checks, provider/model/base URL with secrets removed, and the logical artifact paths retrievable with `ace read`.
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# TUI Operator Guide
|
|
2
|
+
|
|
3
|
+
The ACE terminal UI is an interactive operator surface over the same workspace state used by the MCP server.
|
|
4
|
+
|
|
5
|
+
## Start and preflight
|
|
6
|
+
|
|
7
|
+
Run doctor first so provider failures are separated from display or session failures:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
ace doctor --scan
|
|
11
|
+
ace tui
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Pin a provider when auto-discovery is ambiguous:
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
ace tui --provider ollama --model qwen3:8b --base-url http://127.0.0.1:11434
|
|
18
|
+
ace tui --provider llama.cpp --model local-model --base-url http://127.0.0.1:8080/v1
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
For Codex, Claude, Gemini, and Copilot credentials, endpoints, default models, and provider-specific doctor commands, follow the [hosted provider quick setup](provider-security.md#hosted-provider-quick-setup) before starting a chat.
|
|
22
|
+
|
|
23
|
+
Hermes-local is opt-in and has additional prerequisites; see [Hermes Companion Engine](hermes.md).
|
|
24
|
+
|
|
25
|
+
## Input modes
|
|
26
|
+
|
|
27
|
+
- In normal mode, typing a printable character enters chat mode and preserves that character.
|
|
28
|
+
- `/` enters command mode.
|
|
29
|
+
- `Esc` returns to normal mode.
|
|
30
|
+
- In chat mode, a leading `/command` is routed to the command registry. Prefix with `//` to send a literal slash to the model.
|
|
31
|
+
- `Tab` and `Shift+Tab` cycle tabs.
|
|
32
|
+
- `Alt+1` through `Alt+9` switch directly to a tab.
|
|
33
|
+
|
|
34
|
+
Dashboard controls use Up/Down to select, Left/Right to change a value, and Enter to apply.
|
|
35
|
+
|
|
36
|
+
## Global shortcuts
|
|
37
|
+
|
|
38
|
+
| Shortcut | Action |
|
|
39
|
+
|---|---|
|
|
40
|
+
| `Ctrl+C` | Interrupt the active stream; it does not quit an idle TUI |
|
|
41
|
+
| `Ctrl+D` | Quit |
|
|
42
|
+
| `Ctrl+N` | Open a chat tab |
|
|
43
|
+
| `Ctrl+R` | Refresh |
|
|
44
|
+
| `Ctrl+L` | Clear the current view |
|
|
45
|
+
| `Ctrl+W` | Close the current tab |
|
|
46
|
+
| `Ctrl+Z` | Suspend; resume with the shell's foreground command |
|
|
47
|
+
|
|
48
|
+
## Commands
|
|
49
|
+
|
|
50
|
+
Run `/help` for the authoritative command list. Current command families include:
|
|
51
|
+
|
|
52
|
+
- Provider/model: `/provider`, `/providers`, `/model`, `/models`, `/pull`, `/ollama`
|
|
53
|
+
- Agents/tasks: `/agent`, `/agents`, `/kill`, `/task`, `/tasks`, `/handoff`
|
|
54
|
+
- Approval/config: `/approve`, `/reject`, `/trust`, `/config`, `/theme`
|
|
55
|
+
- Skills: `/skill`, `/skills`
|
|
56
|
+
- Tabs/display: `/chat`, `/logs`, `/close`, `/archive`, `/clear`
|
|
57
|
+
- Lifecycle: `/status`, `/help`, `/quit`
|
|
58
|
+
|
|
59
|
+
Command completion is available while typing a slash command.
|
|
60
|
+
|
|
61
|
+
## Provider switching
|
|
62
|
+
|
|
63
|
+
`/provider <name>` changes the active provider and `/model <name>` changes the active model. A provider shown by discovery is not necessarily authenticated or reachable. Run `ace doctor` for the selected provider after changing credentials or endpoints.
|
|
64
|
+
|
|
65
|
+
## Failure and recovery
|
|
66
|
+
|
|
67
|
+
- If chat is rejected before a request, read the on-screen configuration diagnosis and run its suggested `ace doctor` command.
|
|
68
|
+
- If a direct stream stalls, `Ctrl+C` requests interruption. Confirm that the UI leaves streaming state before sending another task.
|
|
69
|
+
- Hermes-local owns a subprocess and uses its own timeout/abort path; a terminal result must contain a valid final frame and pass completion evidence checks.
|
|
70
|
+
- If the UI display is stale, use `Ctrl+R`; if the underlying state is suspect, exit and run `ace fsck`.
|
|
71
|
+
- Session state survives in ACEPACK, but an unverified model response is not executable authority.
|
|
72
|
+
|
|
73
|
+
## Non-interactive alternative
|
|
74
|
+
|
|
75
|
+
Use the CLI or MCP tools for automation. The TUI is interactive and should not be used as a CI success signal.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@voybio/ace-swarm",
|
|
3
|
-
"version": "2.4.
|
|
3
|
+
"version": "2.4.6",
|
|
4
4
|
"description": "ACE Framework MCP server and CLI — single-file ACEPACK state, local-model serving, agent orchestration, and host compliance enforcement.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -22,7 +22,9 @@
|
|
|
22
22
|
"dist/**/*.js",
|
|
23
23
|
"dist/**/*.d.ts",
|
|
24
24
|
"scripts/hermes_bridge_worker.py",
|
|
25
|
+
"scripts/dev/run_hermes_crispr_live.mjs",
|
|
25
26
|
"assets",
|
|
27
|
+
"docs",
|
|
26
28
|
"README.md",
|
|
27
29
|
"CHANGELOG.md"
|
|
28
30
|
],
|
|
@@ -37,6 +39,7 @@
|
|
|
37
39
|
"scripts": {
|
|
38
40
|
"build": "tsc",
|
|
39
41
|
"test": "npm run build && node --test 'test/*.test.mjs' 'test/**/*.test.mjs'",
|
|
42
|
+
"test:real-astgrep": "npm run build && ACE_TEST_REAL_ASTGREP=1 node --test test/astgrep-real-cli.test.mjs",
|
|
40
43
|
"start": "node dist/cli.js mcp",
|
|
41
44
|
"dev": "tsc && node dist/cli.js mcp",
|
|
42
45
|
"init": "node dist/cli.js init",
|
|
@@ -70,6 +73,7 @@
|
|
|
70
73
|
"dependencies": {
|
|
71
74
|
"@modelcontextprotocol/sdk": "^1.26.0",
|
|
72
75
|
"typescript": "^5.9.3",
|
|
76
|
+
"yaml": "^2.9.0",
|
|
73
77
|
"zod": "^4.3.6"
|
|
74
78
|
},
|
|
75
79
|
"devDependencies": {
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
4
|
+
import { resolve } from "node:path";
|
|
5
|
+
import { pathToFileURL } from "node:url";
|
|
6
|
+
|
|
7
|
+
const workspaceRoot = process.env.ACE_WORKSPACE_ROOT || resolve(process.cwd(), "..");
|
|
8
|
+
const packageRoot = process.cwd();
|
|
9
|
+
const distRoot = resolve(packageRoot, "dist");
|
|
10
|
+
const reportDir = resolve(workspaceRoot, "agent-state", "hermes-crispr-live");
|
|
11
|
+
mkdirSync(reportDir, { recursive: true });
|
|
12
|
+
|
|
13
|
+
const timestamp = new Date().toISOString().replace(/[-:]/g, "").replace(/\..+$/, "Z");
|
|
14
|
+
const reportPath = resolve(reportDir, `${timestamp}.json`);
|
|
15
|
+
const ollamaArtifact = "agent-state/hermes-crispr-live/crispr-ollama.html";
|
|
16
|
+
const llamaArtifact = "agent-state/hermes-crispr-live/crispr-llama-cpp.html";
|
|
17
|
+
const pythonCommand =
|
|
18
|
+
process.env.HERMES_PYTHON;
|
|
19
|
+
if (!pythonCommand) {
|
|
20
|
+
console.error("HERMES_PYTHON is required; point it at the Python environment containing the operator-supplied Hermes checkout.");
|
|
21
|
+
process.exit(2);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const { runLocalModelTask } = await import(pathToFileURL(resolve(distRoot, "local-model-runtime.js")).href);
|
|
25
|
+
const { HermesSubprocessExecutor } = await import(pathToFileURL(resolve(distRoot, "hermes", "session-manager.js")).href);
|
|
26
|
+
|
|
27
|
+
function htmlTask({ provider, model, artifact }) {
|
|
28
|
+
if (process.env.ACE_LIVE_OUTPUT_ONLY === "1") {
|
|
29
|
+
return [
|
|
30
|
+
"Output only a complete self-contained HTML document about CRISPR.",
|
|
31
|
+
"Start with <!DOCTYPE html> and end with </html>.",
|
|
32
|
+
"No markdown fences. No explanation. No tool code.",
|
|
33
|
+
`Runtime label to include visibly: ${provider} / ${model}`,
|
|
34
|
+
"Include inline CSS in <style> and inline JavaScript in <script>.",
|
|
35
|
+
"Include short sections: mechanism, applications, risks/ethics.",
|
|
36
|
+
"Include a small interactive quiz or toggle implemented in JavaScript.",
|
|
37
|
+
"No external assets, CDNs, or network URLs.",
|
|
38
|
+
"Keep it concise.",
|
|
39
|
+
`ACE will save your output to ${artifact}.`,
|
|
40
|
+
].join("\n");
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return [
|
|
44
|
+
"You are running as an ACE coder in Hermes-local mode.",
|
|
45
|
+
`Provider: ${provider}`,
|
|
46
|
+
`Model: ${model}`,
|
|
47
|
+
"",
|
|
48
|
+
"Create a concise, complete, self-contained HTML file about CRISPR.",
|
|
49
|
+
`Use the ACE MCP tool write_workspace_file to write exactly this workspace path: ${artifact}`,
|
|
50
|
+
"",
|
|
51
|
+
"Hard requirements for the file:",
|
|
52
|
+
"- It must be a single .html document with inline CSS and inline JavaScript.",
|
|
53
|
+
"- It must include sections on mechanism, applications, risks/ethics, and a short interactive quiz or toggle implemented in JavaScript.",
|
|
54
|
+
"- It must visibly identify which runtime produced it.",
|
|
55
|
+
"- It must not reference external assets, CDNs, or network resources.",
|
|
56
|
+
"- Keep it under 180 lines.",
|
|
57
|
+
"- Return completed only after write_workspace_file succeeds, and cite the tool evidence.",
|
|
58
|
+
"- If the tool is unavailable, output only the full HTML document starting with <!DOCTYPE html> and ending with </html> so ACE can materialize it for inspection.",
|
|
59
|
+
].join("\n");
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function artifactStats(relativePath) {
|
|
63
|
+
const absolutePath = resolve(workspaceRoot, relativePath);
|
|
64
|
+
if (!existsSync(absolutePath)) {
|
|
65
|
+
return { path: relativePath, exists: false };
|
|
66
|
+
}
|
|
67
|
+
const content = readFileSync(absolutePath, "utf-8");
|
|
68
|
+
return {
|
|
69
|
+
path: relativePath,
|
|
70
|
+
exists: true,
|
|
71
|
+
bytes: Buffer.byteLength(content),
|
|
72
|
+
hasHtml: /<html[\s>]/i.test(content),
|
|
73
|
+
hasCss: /<style[\s>]/i.test(content),
|
|
74
|
+
hasJs: /<script[\s>]/i.test(content),
|
|
75
|
+
mentionsCrispr: /crispr/i.test(content),
|
|
76
|
+
externalRefs: [...content.matchAll(/\b(?:https?:)?\/\//gi)].length,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function extractHtml(text) {
|
|
81
|
+
if (typeof text !== "string") return "";
|
|
82
|
+
const start = text.search(/<!doctype html|<html[\s>]/i);
|
|
83
|
+
const end = text.search(/<\/html>/i);
|
|
84
|
+
if (start === -1 || end === -1 || end <= start) return "";
|
|
85
|
+
return text.slice(start, end + "</html>".length);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function materializeHermesHtmlIfNeeded(row, relativePath) {
|
|
89
|
+
const stats = artifactStats(relativePath);
|
|
90
|
+
if (stats.exists && !row.artifact_preexisting) return stats;
|
|
91
|
+
const html = extractHtml(row.summary);
|
|
92
|
+
if (!html) return { ...stats, stale: Boolean(row.artifact_preexisting) };
|
|
93
|
+
writeFileSync(resolve(workspaceRoot, relativePath), html, "utf-8");
|
|
94
|
+
row.materialized_from_hermes_final = true;
|
|
95
|
+
row.materialization_note =
|
|
96
|
+
"Hermes/local model produced a complete HTML payload but did not execute the ACE write tool; the live driver materialized the final payload so the job artifact can be inspected separately from tool-call success.";
|
|
97
|
+
return artifactStats(relativePath);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const selectedProviders = String(process.env.ACE_LIVE_PROVIDERS || "ollama,llama.cpp")
|
|
101
|
+
.split(",")
|
|
102
|
+
.map((entry) => entry.trim())
|
|
103
|
+
.filter(Boolean);
|
|
104
|
+
|
|
105
|
+
const runs = [
|
|
106
|
+
{
|
|
107
|
+
label: "ollama",
|
|
108
|
+
provider: "ollama",
|
|
109
|
+
model:
|
|
110
|
+
process.env.ACE_LIVE_OLLAMA_MODEL ||
|
|
111
|
+
"hf.co/Qwen/Qwen2.5-Coder-1.5B-Instruct-GGUF:Q2_K",
|
|
112
|
+
baseUrl: process.env.OLLAMA_HOST || "http://127.0.0.1:11434",
|
|
113
|
+
artifact: ollamaArtifact,
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
label: "llama.cpp",
|
|
117
|
+
provider: "llama.cpp",
|
|
118
|
+
model: process.env.ACE_LIVE_LLAMA_CPP_MODEL || "gemma-4-E2B-it-UD-Q2_K_XL.gguf",
|
|
119
|
+
baseUrl: process.env.ACE_LIVE_LLAMA_CPP_BASE_URL || "http://127.0.0.1:8080/v1",
|
|
120
|
+
artifact: llamaArtifact,
|
|
121
|
+
},
|
|
122
|
+
].filter((run) => selectedProviders.includes(run.provider) || selectedProviders.includes(run.label));
|
|
123
|
+
|
|
124
|
+
const report = {
|
|
125
|
+
schema: "ace-hermes-crispr-live@1",
|
|
126
|
+
generated_at: new Date().toISOString(),
|
|
127
|
+
workspace_root: workspaceRoot,
|
|
128
|
+
package_root: packageRoot,
|
|
129
|
+
python_command: pythonCommand,
|
|
130
|
+
rows: [],
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
function persist() {
|
|
134
|
+
writeFileSync(reportPath, JSON.stringify(report, null, 2), "utf-8");
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
for (const run of runs) {
|
|
138
|
+
const started = Date.now();
|
|
139
|
+
const row = {
|
|
140
|
+
...run,
|
|
141
|
+
engine: "hermes_local",
|
|
142
|
+
status: "not_run",
|
|
143
|
+
started_at: new Date(started).toISOString(),
|
|
144
|
+
artifact_preexisting: artifactStats(run.artifact).exists,
|
|
145
|
+
};
|
|
146
|
+
report.rows.push(row);
|
|
147
|
+
persist();
|
|
148
|
+
|
|
149
|
+
try {
|
|
150
|
+
const result = await runLocalModelTask({
|
|
151
|
+
workspaceRoot,
|
|
152
|
+
provider: run.provider,
|
|
153
|
+
model: run.model,
|
|
154
|
+
baseUrl: run.baseUrl,
|
|
155
|
+
engine: "hermes_local",
|
|
156
|
+
modelClass: "small_local",
|
|
157
|
+
role: "coders",
|
|
158
|
+
maxTurns: Number(process.env.ACE_LIVE_HERMES_MAX_TURNS || 8),
|
|
159
|
+
tier: "brief",
|
|
160
|
+
toolScope: ["write_workspace_file"],
|
|
161
|
+
task: htmlTask(run),
|
|
162
|
+
hermesExecutor: new HermesSubprocessExecutor({ pythonCommand }),
|
|
163
|
+
});
|
|
164
|
+
row.status = result.result.status;
|
|
165
|
+
row.summary = result.result.summary;
|
|
166
|
+
row.turns = result.result.turns;
|
|
167
|
+
row.tool_calls = result.result.tool_calls;
|
|
168
|
+
row.evidence_refs = result.result.evidence_refs || [];
|
|
169
|
+
row.policy = result.policy;
|
|
170
|
+
row.runtime = result.runtime;
|
|
171
|
+
row.hermes = {
|
|
172
|
+
bridge_protocol_version: result.hermes?.bridge_protocol_version,
|
|
173
|
+
hermes_session_id: result.hermes?.hermes_session_id,
|
|
174
|
+
shadow_mcp_session_id: result.hermes?.shadow_mcp_session_id,
|
|
175
|
+
execution_engine: result.hermes?.execution_engine,
|
|
176
|
+
provider: result.hermes?.provider,
|
|
177
|
+
model: result.hermes?.model,
|
|
178
|
+
event_count: result.hermes?.events?.length || 0,
|
|
179
|
+
event_types: [...new Set((result.hermes?.events || []).map((event) => event.type))],
|
|
180
|
+
};
|
|
181
|
+
} catch (error) {
|
|
182
|
+
row.status = "error";
|
|
183
|
+
row.summary = error instanceof Error ? error.stack || error.message : String(error);
|
|
184
|
+
} finally {
|
|
185
|
+
row.duration_ms = Date.now() - started;
|
|
186
|
+
row.finished_at = new Date().toISOString();
|
|
187
|
+
row.artifact = materializeHermesHtmlIfNeeded(row, run.artifact);
|
|
188
|
+
row.job_done = Boolean(
|
|
189
|
+
row.artifact?.exists &&
|
|
190
|
+
!row.artifact?.stale &&
|
|
191
|
+
row.artifact.hasHtml &&
|
|
192
|
+
row.artifact.hasCss &&
|
|
193
|
+
row.artifact.hasJs &&
|
|
194
|
+
row.artifact.mentionsCrispr &&
|
|
195
|
+
row.artifact.externalRefs === 0
|
|
196
|
+
);
|
|
197
|
+
row.protocol_done = Boolean(
|
|
198
|
+
row.hermes?.event_count > 0 &&
|
|
199
|
+
row.hermes.event_types?.includes("session_open") &&
|
|
200
|
+
row.hermes.event_types?.includes("session_close")
|
|
201
|
+
);
|
|
202
|
+
row.tool_write_done = Boolean(
|
|
203
|
+
row.tool_calls?.some((tool) => tool.tool === "write_workspace_file" && tool.ok)
|
|
204
|
+
);
|
|
205
|
+
persist();
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
console.log(reportPath);
|
|
210
|
+
if (report.rows.length === 0 || report.rows.some((row) => row.status === "error" || !row.job_done || !row.protocol_done)) {
|
|
211
|
+
process.exitCode = 1;
|
|
212
|
+
}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"id": "gate-correctness",
|
|
3
|
-
"type": "executable",
|
|
4
|
-
"invariant": "All required tests pass",
|
|
5
|
-
"command": "if [ -f ace-mcp-server/package.json ]; then cd ace-mcp-server && npm test --silent; elif [ -f package.json ]; then npm test --silent; else echo 'package.json not found for gate-correctness' && exit 1; fi",
|
|
6
|
-
"evidence_requirement": "Command output snippet with exit code 0"
|
|
7
|
-
}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"id": "gate-typescript-public-surface",
|
|
3
|
-
"type": "executable",
|
|
4
|
-
"invariant": "Exported MCP tools, resources, prompts, and public status events stay registered, described, schema-backed where required, and covered by the audit gate",
|
|
5
|
-
"command": "node --input-type=module -e \"import('./dist/public-surface.js').then(async (m) => { const result = await m.auditPublicSurface({ write_artifact: false }); if (!result.ok) { console.error(result.failures.join('\\n')); process.exit(1); } console.log(JSON.stringify(result.summary)); })\"",
|
|
6
|
-
"evidence_requirement": "PUBLIC_SURFACE_REPORT.md + passing public-surface audit"
|
|
7
|
-
}
|