@dotdrelle/wiki-manager 0.15.66 → 0.15.71

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 (72) hide show
  1. package/.env.example +10 -3
  2. package/README.md +57 -0
  3. package/agent-runtimes.example.json +68 -0
  4. package/agents.docker-compose.yml +39 -1
  5. package/docker-compose.yml +3 -3
  6. package/package.json +3 -2
  7. package/src/activity/activityAggregator.test.js +2 -2
  8. package/src/agent/graph.js +13 -11
  9. package/src/agent/skillRecursion.test.js +13 -12
  10. package/src/cli/wiki-manager.js +125 -37
  11. package/src/cli/wiki-manager.test.js +16 -16
  12. package/src/commands/slash.js +59 -5
  13. package/src/contracts/schemas.js +67 -0
  14. package/src/core/activity.js +5 -0
  15. package/src/core/agentEvents.js +139 -25
  16. package/src/core/agentEvents.test.js +26 -1
  17. package/src/core/buildInfo.json +2 -2
  18. package/src/core/commandFailure.test.js +2 -2
  19. package/src/core/currentArtifact.test.js +5 -5
  20. package/src/core/dockerCompose.test.js +8 -40
  21. package/src/core/env.js +14 -0
  22. package/src/core/env.test.js +19 -0
  23. package/src/core/googleGrants.test.js +1 -1
  24. package/src/core/mcp.js +1 -1
  25. package/src/core/mcp.test.js +1 -1
  26. package/src/core/otherWorkspacesRunning.test.js +6 -6
  27. package/src/core/runtimeEventAdapter.js +81 -0
  28. package/src/core/runtimeEventAdapter.test.js +61 -0
  29. package/src/core/runtimeLog.js +35 -1
  30. package/src/core/runtimeLog.test.js +27 -2
  31. package/src/core/skillChainView.test.js +2 -2
  32. package/src/core/skillCompiler.test.js +1 -1
  33. package/src/core/skillInvocation.js +13 -8
  34. package/src/core/skillInvocation.test.js +1 -1
  35. package/src/core/startupCheck.js +58 -0
  36. package/src/core/startupCheck.test.js +29 -1
  37. package/src/core/wikiSetup.js +25 -0
  38. package/src/core/wikiSetup.test.js +35 -0
  39. package/src/core/wikirc.test.js +6 -6
  40. package/src/core/workspaceInherit.test.js +14 -14
  41. package/src/orchestrator/agentRegistry.js +1 -22
  42. package/src/orchestrator/agentRegistry.test.js +6 -6
  43. package/src/orchestrator/assignmentManager.js +16 -4
  44. package/src/orchestrator/capabilityRegistry.js +8 -1
  45. package/src/orchestrator/dispatcher.js +405 -2
  46. package/src/orchestrator/dispatcher.test.js +158 -4
  47. package/src/orchestrator/objectiveResolver.js +10 -6
  48. package/src/orchestrator/objectiveResolver.test.js +26 -27
  49. package/src/orchestrator/providers/deepAgentsProvider.js +168 -0
  50. package/src/orchestrator/providers/deepAgentsProvider.test.js +178 -0
  51. package/src/orchestrator/providers/dispatcherExternalRuntime.test.js +409 -0
  52. package/src/orchestrator/providers/fakeRuntimeProvider.js +164 -0
  53. package/src/orchestrator/providers/fakeRuntimeProvider.test.js +201 -0
  54. package/src/orchestrator/providers/runtimeProvider.js +101 -0
  55. package/src/orchestrator/providers/runtimeProviders.js +378 -0
  56. package/src/orchestrator/providers/runtimeProviders.test.js +384 -0
  57. package/src/orchestrator/resultAggregator.js +35 -2
  58. package/src/orchestrator/resultAggregator.test.js +62 -0
  59. package/src/orchestrator/scheduler.test.js +4 -4
  60. package/src/runtime/delegation.test.js +11 -11
  61. package/src/runtime/recoveryManager.js +70 -5
  62. package/src/runtime/runner.test.js +1 -1
  63. package/src/runtime/server.test.js +2 -2
  64. package/src/runtime/skillChain.e2e.test.js +2 -2
  65. package/src/runtime/store.test.js +8 -5
  66. package/src/runtime/supervisor.js +5 -10
  67. package/src/runtime/workspaceIsolation.test.js +26 -26
  68. package/src/shell/RightPane.tsx +23 -3
  69. package/src/shell/StartupScreen.tsx +44 -7
  70. package/src/shell/repl.js +24 -2
  71. package/src/shell/repl.test.js +13 -0
  72. package/wiki-workspace +53 -3
package/.env.example CHANGED
@@ -39,11 +39,8 @@ WORKSPACES_ROOT=/path/to/workspaces
39
39
  # "documents": { "headers": { "Authorization": "Bearer <DOCUMENTS_MCP_AUTH_TOKEN>" } }
40
40
  #
41
41
  # Leave empty to disable authentication on that agent (not recommended in production).
42
-
43
42
  CME_MCP_AUTH_TOKEN=
44
43
  DOCUMENTS_MCP_AUTH_TOKEN=
45
- # Generated by `wiki-workspace agents up` when missing.
46
- CONNECTORS_MCP_AUTH_TOKEN=
47
44
 
48
45
  # ── Agent ports (optional, change only if defaults conflict) ───────────────────
49
46
 
@@ -55,6 +52,16 @@ CONNECTORS_MCP_AUTH_TOKEN=
55
52
  #
56
53
  # Enable the opt-in agent-connectors service:
57
54
  CONNECTORS_ENABLED=false
55
+ CONNECTORS_MCP_AUTH_TOKEN=
56
+
57
+ # Agentic runtime gateway (Deep Agents) — enabled by default, started by
58
+ # `agents up`. The manager never starts it, only discovers it via
59
+ # agent-runtimes.json; set GATEWAY_ENABLED=false to opt out.
60
+ GATEWAY_ENABLED=true
61
+ # GATEWAY_PORT=7789
62
+ # Generated by `agents up` if empty, like the other agent tokens; the manager
63
+ # sends it as the Bearer header on every gateway call.
64
+ GATEWAY_AUTH_TOKEN=
58
65
  #
59
66
  # The wikiLLM Google OAuth application is baked into the agent-connectors image
60
67
  # at build time, from agent-external/agent-connectors/.env.build.local. Neither
package/README.md CHANGED
@@ -120,6 +120,62 @@ in isolated workspaces.
120
120
 
121
121
  ![wikiLLM functional diagram — inputs, MCP calls and outputs around the agentic orchestrator and workspaces](https://raw.githubusercontent.com/dotdrelle/llm-wiki-manager/main/docs/architecture.png)
122
122
 
123
+ ## How wikiLLM compares
124
+
125
+ Several open projects now build a Markdown wiki with an LLM. They target
126
+ **different problems** — the useful questions are *what goes in, what comes out,
127
+ and who operates it*. Snapshot as of 2026; all of these move quickly.
128
+
129
+ ✅ first-class · 🟡 partial or indirect · ❌ not a goal
130
+
131
+ Projects compared: [OpenWiki](https://github.com/langchain-ai/openwiki),
132
+ [DeepWiki-Open](https://github.com/asyncfuncai/deepwiki-open),
133
+ [GraphRAG](https://github.com/microsoft/graphrag).
134
+
135
+ <table>
136
+ <thead>
137
+ <tr><th><small>Need</small></th><th><small><strong>wikiLLM</strong></small></th><th><small><strong>OpenWiki</strong></small></th><th><small><strong>DeepWiki-Open</strong></small></th><th><small><strong>GraphRAG</strong></small></th></tr>
138
+ </thead>
139
+ <tbody>
140
+ <tr><td><small>Input</small></td><td><small>✅ Business docs — Confluence, PDF, Office, SaaS</small></td><td><small>✅ Codebase (code mode)</small></td><td><small>✅ Code repo → diagrams</small></td><td><small>🟡 Plain-text corpus only</small></td></tr>
141
+ <tr><td><small>Output</small></td><td><small>✅ Maintained wiki <strong>+ deliverables</strong> from your templates</small></td><td><small>🟡 Wiki about the code, for agents</small></td><td><small>🟡 Interactive wiki + diagrams</small></td><td><small>❌ Entity graph + summaries — no wiki</small></td></tr>
142
+ <tr><td><small>Keep current</small></td><td><small>✅ Re-ingest / scheduled</small></td><td><small>✅ <code>--update</code>, CI action</small></td><td><small>🟡 Regenerated per run</small></td><td><small>✅ <code>graphrag update</code> (delta)</small></td></tr>
143
+ <tr><td><small>Evidence &amp; citations</small></td><td><small>🟡 Cites retrieved context</small></td><td><small>✅ Claims tied to versioned source</small></td><td><small>🟡 RAG-cited answers</small></td><td><small>✅ Citations to text units</small></td></tr>
144
+ <tr><td><small>Corpus-wide Q&amp;A</small></td><td><small>🟡 BM25 + vector feeding generation</small></td><td><small>❌</small></td><td><small>🟡 Repo-scoped RAG chat</small></td><td><small>✅ Local/global community search</small></td></tr>
145
+ <tr><td><small>Team UI</small></td><td><small>✅ Web console — wiki, graph, chat, runs (single-user today)</small></td><td><small>🟡 Local viewer + CLI chat</small></td><td><small>✅ Self-hosted web app + RAG</small></td><td><small>❌ Library / CLI</small></td></tr>
146
+ <tr><td><small>Multi-project isolation</small></td><td><small>✅ Workspaces, own services, ports, secrets</small></td><td><small>❌ One wiki per run</small></td><td><small>❌ One wiki per repo</small></td><td><small>❌ One index per corpus</small></td></tr>
147
+ <tr><td><small>Orchestration &amp; governance</small></td><td><small>✅ Approval-gated dispatcher, budgets, idempotent writes, crash recovery</small></td><td><small>❌ One agent loop</small></td><td><small>❌ One generation pipeline</small></td><td><small>❌ Indexing pipeline</small></td></tr>
148
+ <tr><td><small>Connectors as services</small></td><td><small>✅ Independent MCP agents (Confluence, docs, e-mail…)</small></td><td><small>🟡 Built-in connector set</small></td><td><small>❌</small></td><td><small>❌</small></td></tr>
149
+ <tr><td><small>Offline / local models</small></td><td><small>✅ Per-workspace OpenAI-compatible or gateway (Ollama, vLLM, MLX…)</small></td><td><small>✅ 13+ providers</small></td><td><small>✅ Ollama</small></td><td><small>✅ Any OpenAI-compatible</small></td></tr>
150
+ <tr><td><small>License</small></td><td><small>❌ PolyForm <strong>Noncommercial</strong></small></td><td><small>✅ MIT</small></td><td><small>✅ MIT</small></td><td><small>✅ MIT</small></td></tr>
151
+ </tbody>
152
+ </table>
153
+
154
+ **The short version:**
155
+
156
+ - **OpenWiki** and **DeepWiki-Open** document *source code*. Point wikiLLM at a
157
+ repository and there is nothing for it to ingest; point either of them at a
158
+ stack of Confluence pages and a Word document and that is not their job.
159
+ - **GraphRAG** builds *retrieval structure*, not a wiki you read or deliverables
160
+ you ship — it is a strong back end for corpus-wide Q&A, and complementary
161
+ rather than competing.
162
+ - **wikiLLM** is the only one of the four whose output is *both* a browsable wiki
163
+ *and* regenerated business documents, and the only one with the operational
164
+ layer — isolated projects, bounded approvals, automatic recovery, a web
165
+ console — that a shared internal tool needs.
166
+
167
+ **What wikiLLM does *not* try to do (today):**
168
+
169
+ - Document a codebase for coding agents — that is OpenWiki / DeepWiki-Open
170
+ territory.
171
+ - Serve a true multi-user instance with per-user identity and an attributed
172
+ audit trail. This is a single-user deployment baseline (see the scope note
173
+ above); multi-user is specified and planned next.
174
+ - Expose a graph-query API over the corpus the way GraphRAG does; retrieval is
175
+ BM25 plus a vector index feeding generation.
176
+ - Ship or host the multi-provider AI gateway — routing to several providers is
177
+ supported, the gateway itself is infrastructure you bring.
178
+
123
179
  ## Quick start — your first wiki in ~5 minutes
124
180
 
125
181
  The fastest way in: a **browsable wiki, its dependency graph, and a grounded
@@ -402,6 +458,7 @@ answer "what is this and how do I start it", and stop there.
402
458
  | [`docs/configuration.md`](docs/configuration.md) | Every configuration key: root `.env`, Compose overrides, `mcp.endpoints.json`, workspace `.env`, `.wikirc.yaml`, parallelism |
403
459
  | [`docs/technical-reference.md`](docs/technical-reference.md) | Workspace model, services, the `donna` shell, agent tooling, orchestration and activity contracts, security model |
404
460
  | [`docs/authoring-skills.md`](docs/authoring-skills.md) | Writing a workspace skill: what splits a body into runs, chains, concurrency, parameters, and the interpretation rules |
461
+ | [`docs/agentic-runtime.md`](docs/agentic-runtime.md) | The external agentic runtime: `agent-runtimes.json`, the `RuntimeProvider` contract, the gateway, and governance |
405
462
  | [`docs/claude-desktop.md`](docs/claude-desktop.md) | Using a workspace from Claude Desktop |
406
463
  | [`CLAUDE.md`](CLAUDE.md) | Repository guidance: invariants to preserve when changing this code |
407
464
 
@@ -0,0 +1,68 @@
1
+ {
2
+ "_comment": "Agentic runtimes for this manager (RFC § 37), seeded to agent-runtimes.json on first scaffold — enabled by default, matching the scaffold's GATEWAY_ENABLED=true (set GATEWAY_ENABLED=false in .env, or enabled:false here, to opt out). Rules: (1) a capability is read-only unless it declares mutationClass or defaultRequiresApproval; (2) the 'plan' operation is always a dry-run and never pauses for approval; (3) read/write pairs are TWO capabilities, not two operations, so the approval class stays per-capability; (4) the runtime has eyes (read tools), ideas (free reasoning) and a mouth (gated side-effects), but no hands on the workspace — the hands are the DAG. See llm-wiki-manager/docs/agentic-runtime.md.",
3
+ "runtimes": [
4
+ {
5
+ "id": "deepagents",
6
+ "type": "deepagents",
7
+ "endpoint": "http://localhost:7789",
8
+ "enabled": true,
9
+ "capabilities": [
10
+ {
11
+ "name": "agent.review",
12
+ "operations": ["run"],
13
+ "description": "Read-only audit of a wiki workspace: compare source documents against the existing concept pages, identify missing or under-covered classes, and produce a structured gap report. No mutation.",
14
+ "aliases": ["audit", "review", "analyze", "compare", "check"]
15
+ },
16
+ {
17
+ "name": "agent.consistency",
18
+ "operations": ["run"],
19
+ "description": "Read-only detection of contradictions and inconsistencies between wiki pages and their sources, citing the conflicting passages. No mutation.",
20
+ "aliases": ["consistency", "coherence", "contradictions", "conflicts"]
21
+ },
22
+ {
23
+ "name": "agent.synthesize",
24
+ "operations": ["run"],
25
+ "description": "Read-only cross-source synthesis: build a structured summary of several documents on one subject, using web search tools when available to complement the sources. No mutation.",
26
+ "aliases": ["synthesize", "summarize", "synthesis"]
27
+ },
28
+ {
29
+ "_comment": "operations: 'plan' reports the proposal only (no pause, dry-run); 'run' integrates it and waits for human approval (defaultRequiresApproval).",
30
+ "name": "agent.plan",
31
+ "operations": ["plan", "run"],
32
+ "description": "Given an analysis, propose a deterministic DAG plan (ingest, build, sync) as a validated fragment. The 'plan' operation only reports the proposal; 'run' integrates it and waits for human approval.",
33
+ "aliases": ["plan", "propose"],
34
+ "aliasOperations": { "plan": "plan", "propose": "plan", "apply": "run", "execute": "run" },
35
+ "defaultRequiresApproval": true
36
+ },
37
+ {
38
+ "name": "agent.answer",
39
+ "operations": ["run"],
40
+ "description": "Read-only research answer: investigate a question using the wiki sources and web search, and reply with a grounded answer. No mutation.",
41
+ "aliases": ["answer", "question", "explain"]
42
+ },
43
+ {
44
+ "_comment": "mutationClass 'ingest': writes the findings into the workspace inbox, approval required.",
45
+ "name": "agent.research",
46
+ "operations": ["run"],
47
+ "description": "Web research grounded in the wiki: answer a complex question using wiki sources and web search, then write the findings into the workspace inbox. Mutation, approval required.",
48
+ "aliases": ["research", "investigate"],
49
+ "mutationClass": "ingest"
50
+ },
51
+ {
52
+ "name": "agent.preview",
53
+ "operations": ["run"],
54
+ "description": "Compose the notification report from the workspace profile and show it, without sending. No mutation.",
55
+ "aliases": ["preview", "draft", "compose"]
56
+ },
57
+ {
58
+ "_comment": "defaultRequiresApproval: sending the mail pauses for human approval.",
59
+ "name": "agent.notify",
60
+ "operations": ["run"],
61
+ "description": "Read the workspace profile for the notification recipient, then send the report by email. Mutation, approval required.",
62
+ "aliases": ["notify", "send", "email", "report"],
63
+ "defaultRequiresApproval": true
64
+ }
65
+ ]
66
+ }
67
+ ]
68
+ }
@@ -25,6 +25,12 @@
25
25
  # DOCUMENT_LLM_MODEL — lightonai/LightOnOCR-2-1B
26
26
  # DOCUMENT_LLM_API_KEY — OpenAI/OpenAI-compatible API key for document OCR
27
27
  # DOCUMENT_LLM_TIMEOUT_SECONDS — 120
28
+ # GATEWAY_PORT — 7789
29
+ # GATEWAY_ENABLED — false; true to start the agentic runtime gateway
30
+ # GATEWAY_AUTH_TOKEN — bearer token for the gateway (generated if empty);
31
+ # the manager sends it on every call. The model is
32
+ # NOT configured here: the manager sends its active
33
+ # profile model with every run.
28
34
  #
29
35
  # Set these variables in a .env file at the directory where you run wiki-workspace,
30
36
  # or export them in your shell before running wiki-workspace agents up.
@@ -62,7 +68,7 @@ services:
62
68
  restart: unless-stopped
63
69
 
64
70
  documents:
65
- image: dotdrelle/agent-wiki-documents:latest
71
+ image: dotdrelle/agent-documents:latest
66
72
  user: "${UID:-1000}:${GID:-1000}"
67
73
  ports:
68
74
  - "${DOCUMENTS_MCP_PORT:-3337}:8080"
@@ -134,3 +140,35 @@ services:
134
140
  - ${AGENTS_DATA_DIR:-./.agents-data}/connectors:/data
135
141
  - ${WORKSPACES_ROOT:?Set WORKSPACES_ROOT to the directory containing all workspace folders}:/workspaces
136
142
  restart: unless-stopped
143
+
144
+ # Agentic runtime gateway — the external Deep Agents service the manager
145
+ # routes open-ended analysis to (agent-runtimes.json, endpoint 7789).
146
+ # Opt-in like connectors: set GATEWAY_ENABLED=true. The manager never starts
147
+ # this service, only discovers it; its failure leaves every DAG untouched.
148
+ gateway:
149
+ profiles: [gateway]
150
+ image: dotdrelle/wiki-agentic-gateway:latest
151
+ user: "${UID:-1000}:${GID:-1000}"
152
+ ports:
153
+ - "${GATEWAY_PORT:-7789}:7789"
154
+ environment:
155
+ - GATEWAY_CONFIG_DIR=/config
156
+ - GATEWAY_AUTH_TOKEN=${GATEWAY_AUTH_TOKEN:-}
157
+ - NODE_USE_ENV_PROXY=${NODE_USE_ENV_PROXY:-}
158
+ - HTTPS_PROXY=${HTTPS_PROXY:-}
159
+ - HTTP_PROXY=${HTTP_PROXY:-}
160
+ - NO_PROXY=${NO_PROXY:-localhost,127.0.0.1,host.docker.internal}
161
+ extra_hosts:
162
+ - host.docker.internal:host-gateway
163
+ volumes:
164
+ # One file, two readers: the manager routes on agent-runtimes.json, the
165
+ # gateway serves the capabilities of its own entry from the same file.
166
+ # Absolute path, computed by wiki-workspace from the manager state dir.
167
+ # Declared AFTER the /config data mount: for overlapping bind mounts the
168
+ # child mount wins, and the reverse order silently hid the file under
169
+ # the directory — the gateway degraded to its built-in default
170
+ # capabilities on every start.
171
+ - ${AGENTS_DATA_DIR:-./.agents-data}/gateway:/config
172
+ - ${AGENT_RUNTIMES_FILE:?Set AGENT_RUNTIMES_FILE}:/config/agent-runtimes.json:ro
173
+ - ${WORKSPACES_ROOT:?Set WORKSPACES_ROOT to the directory containing all workspace folders}:/workspaces
174
+ restart: unless-stopped
@@ -110,10 +110,10 @@ services:
110
110
  - host.docker.internal:host-gateway
111
111
  restart: unless-stopped
112
112
 
113
- # ── agent-wiki-production ─────────────────────────────────────────────────
113
+ # ── agent-production ─────────────────────────────────────────────────
114
114
 
115
115
  production-mcp:
116
- image: dotdrelle/agent-wiki-production:latest
116
+ image: dotdrelle/agent-production:latest
117
117
  user: "${UID:-1000}:${GID:-1000}"
118
118
  labels:
119
119
  wiki-manager.description: "Production MCP server for ingest/build/export jobs."
@@ -130,7 +130,7 @@ services:
130
130
  # error. Every compose-deployed ingest then ran without the Lot 4 barrier
131
131
  # and left the published map stale — the very defect that work fixed.
132
132
  # `copy` stays out on purpose: it is the legacy step, opt-in only.
133
- - PRODUCTION_ALLOWED_STEPS=${PRODUCTION_ALLOWED_STEPS:-doctor,ingest,ingest_plan,ingest_apply,concepts,reclassify-concepts,taxonomy,build,export,polish,restore,pipeline}
133
+ - PRODUCTION_ALLOWED_STEPS=${PRODUCTION_ALLOWED_STEPS:-doctor,ingest,ingest_plan,ingest_apply,build,export,polish,restore,pipeline}
134
134
  - PRODUCTION_REQUIRE_CONFIRMATION=${PRODUCTION_REQUIRE_CONFIRMATION:-false}
135
135
  # Parallelism levers — effective concurrency ≈ recommendedConcurrency.
136
136
  # Intermediate defaults (4/8). Low profile 2/4, high profile 8/16.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dotdrelle/wiki-manager",
3
- "version": "0.15.66",
3
+ "version": "0.15.71",
4
4
  "description": "Agentic shell and orchestration cockpit for llm-wiki workspaces.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -19,7 +19,7 @@
19
19
  },
20
20
  "scripts": {
21
21
  "start": "bun ./bin/wiki-manager.js",
22
- "test": "node --test src/core/skillInvocation.test.js src/core/skillCompiler.test.js src/runtime/skillRun.test.js src/runtime/controlDrain.test.js src/runtime/controlCancellation.test.js src/cli/runtimeStartup.test.js src/cli/wiki-manager.test.js src/agent/graph.test.js src/agent/skillRecursion.test.js src/contracts/schemas.test.js src/core/activity.test.js src/core/env.test.js src/core/agentsCompose.test.js src/core/profileServiceStatus.test.js src/core/workspaceProfile.test.js src/core/buildInfo.test.js src/core/agentEvents.test.js src/core/skillChainView.test.js src/core/runtimeLog.test.js src/activity/activityAggregator.test.js src/graph/runGraphProjector.test.js src/core/workflow.test.js src/core/planPatch.test.js src/core/agentLoop.test.js src/core/plan.test.js src/core/mcp.test.js src/core/toolLoop.test.js src/core/documentIntake.test.js src/core/dockerCompose.test.js src/core/otherWorkspacesRunning.test.js src/core/wikiSetup.test.js src/core/wikiWorkspace.test.js src/core/wikirc.test.js src/core/workspaceInherit.test.js src/core/cacert.test.js src/core/composeOverrides.test.js src/core/setEnvValue.test.js src/core/commandFailure.test.js src/core/currentArtifact.test.js src/core/googleGrants.test.js src/core/modelFetch.test.js src/core/startupCheck.test.js src/core/queueStore.test.js src/orchestrator/agentRegistry.test.js src/orchestrator/capabilityRegistry.test.js src/orchestrator/capabilityResolver.test.js src/orchestrator/planValidator.test.js src/orchestrator/planIntegrator.test.js src/orchestrator/taskStatuses.test.js src/orchestrator/scheduler.test.js src/orchestrator/attemptManager.test.js src/orchestrator/resultAggregator.test.js src/orchestrator/approvalPolicy.test.js src/orchestrator/dispatcher.test.js src/orchestrator/objectiveResolver.test.js src/commands/slash.test.js src/shell/repl.test.js src/shell/setupWizardModality.test.js src/shell/setupWizardPlaceholders.test.js src/shell/setupWizardSuggestions.test.js src/shell/setupWizardDiscovery.test.js src/shell/wrapText.test.js src/runtime/lifecycle.test.js src/runtime/store.test.js src/runtime/workspaceIsolation.test.js src/runtime/controlMessages.test.js src/runtime/recoveryManager.test.js src/runtime/server.test.js src/runtime/supervisor.test.js src/runtime/delegation.test.js src/runtime/runner.test.js src/runtime/runner.e2e.test.js src/runtime/skillChain.e2e.test.js src/runtime/donna-contract.test.js src/runtime/approvals.test.js src/runtime/auth.test.js",
22
+ "test": "node --test src/core/skillInvocation.test.js src/core/skillCompiler.test.js src/runtime/skillRun.test.js src/runtime/controlDrain.test.js src/runtime/controlCancellation.test.js src/cli/runtimeStartup.test.js src/cli/wiki-manager.test.js src/agent/graph.test.js src/agent/skillRecursion.test.js src/contracts/schemas.test.js src/core/activity.test.js src/core/env.test.js src/core/agentsCompose.test.js src/core/profileServiceStatus.test.js src/core/workspaceProfile.test.js src/core/buildInfo.test.js src/core/agentEvents.test.js src/core/skillChainView.test.js src/core/runtimeLog.test.js src/core/runtimeEventAdapter.test.js src/activity/activityAggregator.test.js src/graph/runGraphProjector.test.js src/core/workflow.test.js src/core/planPatch.test.js src/core/agentLoop.test.js src/core/plan.test.js src/core/mcp.test.js src/core/toolLoop.test.js src/core/documentIntake.test.js src/core/dockerCompose.test.js src/core/otherWorkspacesRunning.test.js src/core/wikiSetup.test.js src/core/wikiWorkspace.test.js src/core/wikirc.test.js src/core/workspaceInherit.test.js src/core/cacert.test.js src/core/composeOverrides.test.js src/core/setEnvValue.test.js src/core/commandFailure.test.js src/core/currentArtifact.test.js src/core/googleGrants.test.js src/core/modelFetch.test.js src/core/startupCheck.test.js src/core/queueStore.test.js src/orchestrator/agentRegistry.test.js src/orchestrator/capabilityRegistry.test.js src/orchestrator/capabilityResolver.test.js src/orchestrator/planValidator.test.js src/orchestrator/planIntegrator.test.js src/orchestrator/taskStatuses.test.js src/orchestrator/scheduler.test.js src/orchestrator/attemptManager.test.js src/orchestrator/resultAggregator.test.js src/orchestrator/approvalPolicy.test.js src/orchestrator/dispatcher.test.js src/orchestrator/objectiveResolver.test.js src/orchestrator/providers/fakeRuntimeProvider.test.js src/orchestrator/providers/runtimeProviders.test.js src/orchestrator/providers/dispatcherExternalRuntime.test.js src/orchestrator/providers/deepAgentsProvider.test.js src/commands/slash.test.js src/shell/repl.test.js src/shell/setupWizardModality.test.js src/shell/setupWizardPlaceholders.test.js src/shell/setupWizardSuggestions.test.js src/shell/setupWizardDiscovery.test.js src/shell/wrapText.test.js src/runtime/lifecycle.test.js src/runtime/store.test.js src/runtime/workspaceIsolation.test.js src/runtime/controlMessages.test.js src/runtime/recoveryManager.test.js src/runtime/server.test.js src/runtime/supervisor.test.js src/runtime/delegation.test.js src/runtime/runner.test.js src/runtime/runner.e2e.test.js src/runtime/skillChain.e2e.test.js src/runtime/donna-contract.test.js src/runtime/approvals.test.js src/runtime/auth.test.js",
23
23
  "check-versions": "node scripts/check-versions.js",
24
24
  "prepack": "node scripts/check-versions.js",
25
25
  "prepublishOnly": "node scripts/check-versions.js",
@@ -38,6 +38,7 @@
38
38
  "docker-compose.override.example.yml",
39
39
  "agents.docker-compose.override.example.yml",
40
40
  "mcp.endpoints.example.json",
41
+ "agent-runtimes.example.json",
41
42
  ".env.example",
42
43
  "tsconfig.json",
43
44
  "bunfig.toml",
@@ -144,12 +144,12 @@ test('aggregateActivity keeps a healthy active task out of the error color when
144
144
  key: 'activity-b',
145
145
  status: 'running',
146
146
  terminal: false,
147
- progress: { percent: 35, stepId: 'running-b', label: 'Ingest application-orea.md', detail: 'LLM running' },
147
+ progress: { percent: 35, stepId: 'running-b', label: 'Ingest sample-application.md', detail: 'LLM running' },
148
148
  }],
149
149
  }, []);
150
150
 
151
151
  const line = aggregated.lines[0];
152
152
  assert.equal(line.status, '35 %');
153
153
  assert.match(line.label, /^\[\.\.\.\]/);
154
- assert.equal(line.progress.label, 'Ingest application-orea.md');
154
+ assert.equal(line.progress.label, 'Ingest sample-application.md');
155
155
  });
@@ -891,7 +891,7 @@ export async function handleRuntimeControlTool(session, tool, args = {}) {
891
891
  delegated: true,
892
892
  runId: inRun.runId,
893
893
  summary: inRun.summary ?? null,
894
- message: `Action lancée (${String(inRun.runId).slice(0, 8)}) après validation du plan réel : ${inRun.summary?.tasks ?? 0} tâche(s), ${inRun.summary?.agent ?? 'agent résolu'}. Exécution en cours.`,
894
+ message: `Action started (${String(inRun.runId).slice(0, 8)}) after real-plan validation: ${inRun.summary?.tasks ?? 0} task(s), ${inRun.summary?.agent ?? 'resolved agent'}. Execution in progress.`,
895
895
  });
896
896
  }
897
897
  const result = await postRuntimeDelegate(objective, { url, workspace });
@@ -900,9 +900,9 @@ export async function handleRuntimeControlTool(session, tool, args = {}) {
900
900
  delegated: true,
901
901
  runId: result.runId,
902
902
  summary: result.delegation ?? null,
903
- message: `Action lancée (${String(result.runId).slice(0, 8)}) après validation du plan réel : ${result.delegation?.tasks ?? 0} tâche(s), ${result.delegation?.agent ?? 'agent résolu'}. Exécution en cours.`,
903
+ message: `Action started (${String(result.runId).slice(0, 8)}) after real-plan validation: ${result.delegation?.tasks ?? 0} task(s), ${result.delegation?.agent ?? 'resolved agent'}. Execution in progress.`,
904
904
  })
905
- : `Délégation refusée : ${result?.error ?? JSON.stringify(result)}`;
905
+ : `Delegation refused: ${result?.error ?? JSON.stringify(result)}`;
906
906
  }
907
907
  if (tool === 'run_skill') {
908
908
  const skillName = String(args.skillName ?? '').trim();
@@ -952,12 +952,13 @@ export async function handleRuntimeControlTool(session, tool, args = {}) {
952
952
  par ressemblance.
953
953
 
954
954
  La garde de cycle ci-dessus ne voit que les répétitions. Elle laissait
955
- donc passer la cascade réellement observée sur un `/wiki-ingest` :
956
- l'intention n°2 du corps est mot pour mot celui de
957
- `/wiki-rebuild-concepts`, dont l'intention décrit à son tour
958
- `/wiki-reclassify`, puis `/wiki-taxonomy`. Trois compétences distinctes,
959
- aucun cycle, et la grille de concepts comme la taxonomie reconstruites
960
- plusieurs fois pour une seule demande.
955
+ donc passer la cascade réellement observée sur un `/wiki-ingest` : une
956
+ intention compilée décrivait mot pour mot le corps d'une compétence
957
+ sœur, dont l'intention décrivait à son tour la suivante. Trois
958
+ compétences distinctes, aucun cycle, et la grille de concepts comme la
959
+ taxonomie reconstruites plusieurs fois pour une seule demande.
960
+ (Ces compétences sœurs ont disparu avec la simplification 0.15.66 ; la
961
+ garde, elle, reste.)
961
962
 
962
963
  Une intention compilée EST déjà le travail à faire : elle se délègue.
963
964
  La composition explicite reste ouverte — un corps qui nomme sa cible dit
@@ -1247,6 +1248,7 @@ export function buildAgentSystemPrompt(state) {
1247
1248
  'When an action fails or is refused for lack of an authorization grant or scope (rather than a missing capability), say exactly that and name the primitive that grants it. Do not describe the feature as unavailable.',
1248
1249
  'For an action with no matching direct tool, call runtime__delegate with the user objective only. The runtime chooses the capability, operation, agent and plan, including a validated single task for executor-only agents. Never choose those identifiers yourself. Never call <provider>__agent_plan, <provider>__agent_execute, legacy production__production_start_job, wiki__plan_set, or wiki__plan_done from interactive chat.',
1249
1250
  'Do not ask the user which sources, files, connectors, or templates to use for an ingest, build, or export: the specialized agent discovers them from the workspace. When the objective is clear (e.g. "lance une ingestion"), delegate it as stated, without a clarifying question.',
1251
+ 'The concept map is not a deliverable and has no build, rebuild, reclassify, group or taxonomy pass of its own. Concepts are the folders produced by ingestion itself (wiki/concepts/<concept>/<subject>.md — the concept IS the folder), and the /graph taxonomy derives from them. So "rebuild / refresh / redo the concepts" means run an ingestion (the wiki-ingest skill, or a delegated ingest objective) — never a build or export, and never a separate concept step. Do not offer "rebuild the concepts" alongside build/export as if it were the same family of action.',
1250
1252
  'Templates are instruction-only specs and deliverables are regenerated from them. When asked to change what a generated document says, edit the underlying wiki content (wiki_write_page) or the template\'s [[INSTRUCTION: ...]] sections — never write finished prose into a template, because a build copies it verbatim and it can no longer be refreshed from the wiki. template_write refuses prose outside an instruction block, so keep every sentence inside one.',
1251
1253
  'Promise only what the resolved capability actually exposes in its declared contract (the input schema the specialized agent publishes for that capability). When the user requests an execution parameter — a batch or chunk size, a count "N at a time", concurrency, ordering, priority, or any tuning knob — apply it only if that parameter exists in the target capability\'s published input schema. Otherwise do not confirm or promise it: delegate the objective, and if the user explicitly asked for that parameter, say plainly in one line that you started the work but do not control that aspect (the runtime and the specialized agent decide it). Never state or imply a parameter was applied when the agent contract cannot enforce it.',
1252
1254
  'If runtime__delegate returns a blocker or no specialized provider is available, report only that concrete blocker concisely. Never replace the missing execution path with a suggested slash command, skill, MCP tool name, manual file move, administrator escalation, or alternative workflow unless the user explicitly asks for alternatives.',
@@ -1266,7 +1268,7 @@ export function buildAgentSystemPrompt(state) {
1266
1268
  ? `Workspace profile (.wiki/profile.md) — durable user preferences, apply these to every reply (tone, tutoiement/vouvoiement, formatting, etc.):\n${workspaceProfile}`
1267
1269
  : null,
1268
1270
  currentArtifactPromptLine(currentArtifactFor(state.session)),
1269
- 'Runtime control: you have runtime__status, runtime__cancel, runtime__kill and runtime__enqueue. When the user asks to stop, remove, clean or kill the current run, its jobs or the queue ("supprime le job et la queue", "arr\u00eate tout"), call runtime__kill (or runtime__cancel for a soft stop of just the run) and confirm what was stopped. When the user explicitly asks to delete, reset, abandon or replace the current plan, call runtime__kill with purge=true; never set purge=true for a simple stop. For questions about what is running or queued, call runtime__status and answer from its data. You have no approval tool: a pending approval is granted only by the user through the approval button or the /approve command. Never grant, claim or report an approval yourself; when the user asks to proceed with pending mutations, tell them to use those controls. When the user asks for a NEW action while a run is active, do not execute it: propose runtime__enqueue (run it after) or, if they insist it replaces the current work, runtime__kill then the new action.',
1271
+ 'Runtime control: you have runtime__status, runtime__cancel, runtime__kill and runtime__enqueue. When the user asks to stop, remove, clean or kill the current run, its jobs or the queue ("supprime le job et la queue", "arr\u00eate tout"), call runtime__kill (or runtime__cancel for a soft stop of just the run) and confirm what was stopped. When the user explicitly asks to delete, reset, abandon or replace the current plan, call runtime__kill with purge=true; never set purge=true for a simple stop. For questions about what is running or queued, call runtime__status and answer from its data. You have no approval tool: a pending approval is granted only by the user through the approval button or the /approve command. Never grant, claim or report an approval yourself; when the user asks to proceed with pending mutations, tell them to use those controls. A request to approve, validate, confirm or accept a pending run is a human control action: NEVER call runtime__delegate (or any capability) for it — answer with the control to use and nothing else. When the user asks for a NEW action while a run is active, do not execute it: propose runtime__enqueue (run it after) or, if they insist it replaces the current work, runtime__kill then the new action.',
1270
1272
  'When the user asks to refresh, show, or update the displayed plan or status, call runtime__status. This is a state refresh request, not a new business capability, and must never be delegated.',
1271
1273
  'Report every runtime control outcome exactly as the tool returned it \u2014 never embellish. If runtime__kill reports 0 run(s)/0 task(s)/0 purged, say there was nothing active to stop or purge; do NOT claim a run, plan, pending approval or queue item was removed. If runtime__status returns an error or could not be read, say the runtime state could not be retrieved and do not describe a state you never obtained. Never assert that something was cleaned, cancelled, approved or purged unless that specific tool result confirms it.',
1272
1274
  'Durable profile updates are actions in this stabilized version: delegate them instead of writing directly.',
@@ -1751,7 +1753,7 @@ export function createAgentGraph(options = {}) {
1751
1753
  forceDelegation: canDelegate,
1752
1754
  };
1753
1755
  }
1754
- const failure = 'Réponse rejetée : Donna a exposé une instruction interne ou une procédure manuelle incorrecte.';
1756
+ const failure = 'Response rejected: Donna exposed an internal instruction or an incorrect manual procedure.';
1755
1757
  emitAgentEvent(state.session, 'assistant_message', 'agent_guard', { content: failure });
1756
1758
  return { response: failure, pendingToolCalls: null, readyToStream: false };
1757
1759
  }
@@ -98,21 +98,22 @@ test('borne la profondeur même sans cycle', async () => {
98
98
  });
99
99
 
100
100
  /*
101
- Cascade observée sur un `/wiki-ingest` : deux `/wiki-rebuild-concepts`, puis
102
- `/wiki-reclassify`, puis `/wiki-taxonomy`. Aucun cycle — trois compétences
103
- distinctes — mais la grille de concepts et la taxonomie reconstruites
104
- plusieurs fois pour une seule demande. La deuxième intention compilée de
105
- `/wiki-ingest` est mot pour mot le corps de `/wiki-rebuild-concepts` : le
106
- sélecteur par description la reconnaissait légitimement.
101
+ Cascade observée à l'époque des compétences concepts : un `/wiki-ingest`
102
+ relançait les compétences voisines plusieurs fois pour une seule demande,
103
+ parce que la deuxième intention compilée était mot pour mot le corps d'une
104
+ compétence sœur et que le sélecteur par description la reconnaissait
105
+ légitimement. Ces compétences (rebuild-concepts/reclassify/taxonomy) ont
106
+ disparu avec la simplification 0.15.66 ; la garde contre la récursion, elle,
107
+ reste — c'est elle que ces tests verrouillent.
107
108
  */
108
109
  const callWithObjective = (state, skillName, objective) =>
109
110
  handleRuntimeControlTool(state, 'run_skill', { skillName, _userInput: objective })
110
111
  .then((raw) => JSON.parse(raw));
111
112
 
112
113
  test('refuse une compétence voisine que l’intention décrit sans la nommer', async () => {
113
- const objective = 'Run the production pipeline steps concepts, reclassify-concepts and taxonomy, in that order.';
114
+ const objective = 'Run the production pipeline steps ingest, build, export and polish, in that order.';
114
115
  const ran = [];
115
- const result = await callWithObjective(session(['wiki-ingest'], ran), 'wiki-rebuild-concepts', objective);
116
+ const result = await callWithObjective(session(['wiki-ingest'], ran), 'wiki-build', objective);
116
117
 
117
118
  assert.equal(result.ok, false);
118
119
  assert.equal(result.code, 'nested_skill_match_blocked');
@@ -145,20 +146,20 @@ test('un chemin de fichier commençant par un nom de compétence ne vaut pas inv
145
146
  });
146
147
 
147
148
  test('hors de toute chaîne, la sélection par description reste permise', async () => {
148
- const result = await callWithObjective(session(undefined), 'wiki-taxonomy', 'republish the graph taxonomy');
149
+ const result = await callWithObjective(session(undefined), 'wiki-build', 'regenerate the deliverables from the templates');
149
150
 
150
151
  assert.equal(result.ok, true);
151
152
  });
152
153
 
153
154
  /*
154
155
  Le nom seul ne prouve rien. Plusieurs compétences du scaffold portent un nom
155
- qui est aussi un mot courant : « Run the production pipeline steps concepts,
156
- reclassify-concepts and taxonomy » nomme `pipeline`, dont le lancement rejoue
156
+ qui est aussi un mot courant : « Run the production pipeline steps ingest,
157
+ build, export and polish » nomme `pipeline`, dont le lancement rejoue
157
158
  ingest + build + export + polish. Une intention doit citer sa cible EN TANT QUE
158
159
  compétence, pas l'employer comme mot.
159
160
  */
160
161
  test('un nom employé comme mot courant ne vaut pas invocation', async () => {
161
- const objective = 'Run the production pipeline steps concepts, reclassify-concepts and taxonomy, in that order.';
162
+ const objective = 'Run the production pipeline steps ingest, build, export and polish, in that order.';
162
163
  const ran = [];
163
164
  const result = await callWithObjective(session(['wiki-ingest'], ran), 'pipeline', objective);
164
165