@dotdrelle/wiki-manager 0.15.66 → 0.15.70

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 (50) hide show
  1. package/.env.example +10 -3
  2. package/README.md +54 -0
  3. package/agent-runtimes.example.json +68 -0
  4. package/agents.docker-compose.yml +35 -1
  5. package/docker-compose.yml +3 -3
  6. package/package.json +3 -2
  7. package/src/agent/graph.js +12 -11
  8. package/src/agent/skillRecursion.test.js +13 -12
  9. package/src/cli/wiki-manager.js +124 -36
  10. package/src/commands/slash.js +38 -3
  11. package/src/contracts/schemas.js +67 -0
  12. package/src/core/activity.js +5 -0
  13. package/src/core/agentEvents.js +18 -1
  14. package/src/core/buildInfo.json +2 -2
  15. package/src/core/dockerCompose.test.js +8 -40
  16. package/src/core/env.js +14 -0
  17. package/src/core/env.test.js +19 -0
  18. package/src/core/googleGrants.test.js +1 -1
  19. package/src/core/mcp.js +1 -1
  20. package/src/core/runtimeEventAdapter.js +81 -0
  21. package/src/core/runtimeEventAdapter.test.js +61 -0
  22. package/src/core/skillChainView.test.js +2 -2
  23. package/src/core/skillCompiler.test.js +1 -1
  24. package/src/core/skillInvocation.js +13 -8
  25. package/src/core/startupCheck.js +58 -0
  26. package/src/core/startupCheck.test.js +29 -1
  27. package/src/orchestrator/agentRegistry.js +1 -22
  28. package/src/orchestrator/assignmentManager.js +16 -4
  29. package/src/orchestrator/capabilityRegistry.js +8 -1
  30. package/src/orchestrator/dispatcher.js +361 -2
  31. package/src/orchestrator/dispatcher.test.js +112 -1
  32. package/src/orchestrator/objectiveResolver.js +10 -6
  33. package/src/orchestrator/objectiveResolver.test.js +26 -27
  34. package/src/orchestrator/providers/deepAgentsProvider.js +168 -0
  35. package/src/orchestrator/providers/deepAgentsProvider.test.js +178 -0
  36. package/src/orchestrator/providers/dispatcherExternalRuntime.test.js +409 -0
  37. package/src/orchestrator/providers/fakeRuntimeProvider.js +164 -0
  38. package/src/orchestrator/providers/fakeRuntimeProvider.test.js +201 -0
  39. package/src/orchestrator/providers/runtimeProvider.js +101 -0
  40. package/src/orchestrator/providers/runtimeProviders.js +325 -0
  41. package/src/orchestrator/providers/runtimeProviders.test.js +361 -0
  42. package/src/orchestrator/resultAggregator.js +35 -2
  43. package/src/orchestrator/resultAggregator.test.js +62 -0
  44. package/src/runtime/recoveryManager.js +70 -5
  45. package/src/runtime/skillChain.e2e.test.js +2 -2
  46. package/src/runtime/supervisor.js +5 -10
  47. package/src/shell/RightPane.tsx +9 -1
  48. package/src/shell/StartupScreen.tsx +44 -7
  49. package/src/shell/repl.test.js +13 -0
  50. package/wiki-workspace +19 -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,59 @@ 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
+ Each cell keeps its detail and carries a score — ✅ first-class · 🟡 partial or
130
+ indirect · ❌ not a goal — and the last column names the project that **covers
131
+ that need best**.
132
+
133
+ | Dimension / need | **wikiLLM** (this project) | **OpenWiki** — `langchain-ai/openwiki` | **DeepWiki-Open** — `asyncfuncai/deepwiki-open` | **GraphRAG** — `microsoft/graphrag` | Best coverage |
134
+ | --- | --- | --- | --- | --- | --- |
135
+ | Built for | Turning scattered **business documents** into a team wiki, then regenerating deliverables from it | Giving **coding agents** a readable map of a codebase | Auto-documenting a **code repository** with diagrams | Answering **global questions** over a large text corpus | *depends on your goal* |
136
+ | Ingest arbitrary business documents (Confluence, PDF, Office, SaaS) | ✅ Confluence exports, PDF/Office files, notes, SaaS connectors | 🟡 personal-mode connectors only — Notion, Gmail, Slack | ❌ code repos only | 🟡 plain-text files only, and no wiki as output | **wikiLLM** |
137
+ | Document a source-code repository | ❌ nothing to ingest from a repo | ✅ *code mode*, with claims linked to source evidence (OKF) | ✅ repo → interactive wiki + Mermaid diagrams | ❌ not a goal | **OpenWiki / DeepWiki-Open** |
138
+ | Primary output | ✅ Maintained wiki **+ regenerated deliverables** from your templates (reports, pages, exports) | 🟡 A wiki about the codebase, for agents to read | 🟡 An interactive wiki + architecture diagrams | ❌ An entity graph + community summaries (Parquet), not a wiki | **wikiLLM** (only one producing deliverables) |
139
+ | Keep the wiki current over time | ✅ Re-ingest on demand or on a schedule | ✅ `--update` flag / CI action | 🟡 Regenerated per run | ✅ `graphrag update` (delta merge) | **wikiLLM / OpenWiki** |
140
+ | Knowledge structure | Deterministic concept folders + a derived community graph | Linked pages + evidence-grounded claims | LLM-generated pages + diagrams | Leiden communities over an entity/relationship graph | *task-dependent* |
141
+ | Browsable wiki UI for a team | ✅ Web UI: wiki browser, dependency graph, chat, run/execution view (single-user today) | 🟡 Local-only browser visualiser (127.0.0.1) + CLI chat | ✅ Self-hostable web app (Next.js + Python) with RAG chat | ❌ Library / CLI — no UI | **DeepWiki-Open / wikiLLM** |
142
+ | Evidence-grounded claims & citations | 🟡 Cites retrieved context, never invents facts | ✅ Grounded claims tied to versioned source | 🟡 RAG-cited answers | ✅ Citations to source text units | **OpenWiki / GraphRAG** |
143
+ | Corpus-wide graph Q&A over the knowledge | 🟡 BM25 + vector retrieval feeding generation | ❌ not a goal | 🟡 RAG chat scoped to one repo | ✅ Entity graph + local/global community search | **GraphRAG** |
144
+ | Multiple isolated projects on one install | ✅ Workspaces, each with its own services, ports and secrets | ❌ one wiki per run | ❌ one wiki per repo | ❌ one index per corpus | **wikiLLM** |
145
+ | Orchestration & governance | ✅ Capability-based dispatcher (**Donna**): human approval by default, per-run budgets, idempotent writes, crash recovery | ❌ One Deep Agent loop (LangGraph) | ❌ One generation pipeline | ❌ Deterministic indexing pipeline | **wikiLLM** |
146
+ | Durable runs — crash recovery, queued work | ✅ Boot-time re-attachment + extra runs queued | 🟡 Resumable page-job queue (`.run.json`) | ❌ regenerate from scratch | ❌ re-run the index | **wikiLLM** |
147
+ | Source connectors as separate services | ✅ Confluence, document conversion, e-mail — each an independent MCP agent | 🟡 Built-in connector set | ❌ | ❌ | **wikiLLM** |
148
+ | Run fully offline with local models | ✅ Per-workspace provider config, OpenAI-compatible or a gateway (Ollama, vLLM, MLX…) | ✅ 13+ providers incl. Ollama / LM Studio | ✅ incl. Ollama | ✅ any OpenAI-compatible endpoint | *any* |
149
+ | License | ❌ PolyForm **Noncommercial** | ✅ MIT | ✅ MIT | ✅ MIT | **OpenWiki / DeepWiki-Open / GraphRAG** |
150
+
151
+ **The short version:**
152
+
153
+ - **OpenWiki** and **DeepWiki-Open** document *source code*. Point wikiLLM at a
154
+ repository and there is nothing for it to ingest; point either of them at a
155
+ stack of Confluence pages and a Word document and that is not their job.
156
+ - **GraphRAG** builds *retrieval structure*, not a wiki you read or deliverables
157
+ you ship — it is a strong back end for corpus-wide Q&A, and complementary
158
+ rather than competing.
159
+ - **wikiLLM** is the only one of the four whose output is *both* a browsable wiki
160
+ *and* regenerated business documents, and the only one with the operational
161
+ layer — isolated projects, bounded approvals, automatic recovery, a web
162
+ console — that a shared internal tool needs.
163
+
164
+ **What wikiLLM does *not* try to do (today):**
165
+
166
+ - Document a codebase for coding agents — that is OpenWiki / DeepWiki-Open
167
+ territory.
168
+ - Serve a true multi-user instance with per-user identity and an attributed
169
+ audit trail. This is a single-user deployment baseline (see the scope note
170
+ above); multi-user is specified and planned next.
171
+ - Expose a graph-query API over the corpus the way GraphRAG does; retrieval is
172
+ BM25 plus a vector index feeding generation.
173
+ - Ship or host the multi-provider AI gateway — routing to several providers is
174
+ supported, the gateway itself is infrastructure you bring.
175
+
123
176
  ## Quick start — your first wiki in ~5 minutes
124
177
 
125
178
  The fastest way in: a **browsable wiki, its dependency graph, and a grounded
@@ -402,6 +455,7 @@ answer "what is this and how do I start it", and stop there.
402
455
  | [`docs/configuration.md`](docs/configuration.md) | Every configuration key: root `.env`, Compose overrides, `mcp.endpoints.json`, workspace `.env`, `.wikirc.yaml`, parallelism |
403
456
  | [`docs/technical-reference.md`](docs/technical-reference.md) | Workspace model, services, the `donna` shell, agent tooling, orchestration and activity contracts, security model |
404
457
  | [`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 |
458
+ | [`docs/agentic-runtime.md`](docs/agentic-runtime.md) | The external agentic runtime: `agent-runtimes.json`, the `RuntimeProvider` contract, the gateway, and governance |
405
459
  | [`docs/claude-desktop.md`](docs/claude-desktop.md) | Using a workspace from Claude Desktop |
406
460
  | [`CLAUDE.md`](CLAUDE.md) | Repository guidance: invariants to preserve when changing this code |
407
461
 
@@ -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,31 @@ 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
+ - ${AGENT_RUNTIMES_FILE:?Set AGENT_RUNTIMES_FILE}:/config/agent-runtimes.json:ro
168
+ - ${AGENTS_DATA_DIR:-./.agents-data}/gateway:/config
169
+ - ${WORKSPACES_ROOT:?Set WORKSPACES_ROOT to the directory containing all workspace folders}:/workspaces
170
+ 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.70",
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",
@@ -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
@@ -1266,7 +1267,7 @@ export function buildAgentSystemPrompt(state) {
1266
1267
  ? `Workspace profile (.wiki/profile.md) — durable user preferences, apply these to every reply (tone, tutoiement/vouvoiement, formatting, etc.):\n${workspaceProfile}`
1267
1268
  : null,
1268
1269
  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.',
1270
+ '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
1271
  '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
1272
  '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
1273
  'Durable profile updates are actions in this stabilized version: delegate them instead of writing directly.',
@@ -1751,7 +1752,7 @@ export function createAgentGraph(options = {}) {
1751
1752
  forceDelegation: canDelegate,
1752
1753
  };
1753
1754
  }
1754
- const failure = 'Réponse rejetée : Donna a exposé une instruction interne ou une procédure manuelle incorrecte.';
1755
+ const failure = 'Response rejected: Donna exposed an internal instruction or an incorrect manual procedure.';
1755
1756
  emitAgentEvent(state.session, 'assistant_message', 'agent_guard', { content: failure });
1756
1757
  return { response: failure, pendingToolCalls: null, readyToStream: false };
1757
1758
  }
@@ -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