@dotdrelle/wiki-manager 0.8.2 → 0.10.4
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/README.md +36 -6
- package/agents.docker-compose.yml +5 -0
- package/package.json +5 -2
- package/src/agent/graph.js +68 -9
- package/src/agent/graph.test.js +64 -0
- package/src/cli/wiki-manager.js +34 -2
- package/src/commands/slash.js +9 -25
- package/src/contracts/README.md +16 -0
- package/src/contracts/schemas.js +302 -0
- package/src/contracts/schemas.test.js +93 -0
- package/src/core/activity.js +14 -2
- package/src/core/activity.test.js +4 -2
- package/src/core/agentEvents.js +212 -24
- package/src/core/agentEvents.test.js +85 -12
- package/src/core/agentLoop.js +32 -7
- package/src/core/mcp.js +3 -1
- package/src/core/plan.js +4 -0
- package/src/core/planPatch.js +224 -0
- package/src/core/planPatch.test.js +63 -0
- package/src/core/sessionConfig.js +24 -0
- package/src/core/workflow.js +264 -0
- package/src/core/workflow.test.js +66 -0
- package/src/runtime/client.js +28 -1
- package/src/runtime/runner.js +432 -20
- package/src/runtime/runner.test.js +273 -1
- package/src/runtime/server.js +494 -24
- package/src/runtime/server.test.js +661 -0
- package/src/runtime/store.js +59 -7
- package/src/runtime/store.test.js +72 -1
- package/src/shell/RightPane.tsx +1 -7
- package/src/shell/StartupScreen.tsx +212 -0
- package/src/shell/repl.js +51 -7
- package/src/shell/repl.test.js +77 -1
- package/src/shell/textFit.ts +6 -0
- package/src/shell/tui.tsx +163 -0
- package/src/shell/useAgent.ts +17 -9
- package/src/shell/useSession.ts +34 -0
package/README.md
CHANGED
|
@@ -460,6 +460,21 @@ or the shell command `/approve item <id>`. The approval timeout defaults to 10
|
|
|
460
460
|
minutes and can be changed with `WIKI_MANAGER_APPROVAL_TIMEOUT_MS` or
|
|
461
461
|
`approvalTimeoutMs` in the `/run` body.
|
|
462
462
|
|
|
463
|
+
While a run is active, `GET`/`POST /control` still answers without waiting for
|
|
464
|
+
it to finish: `{"action":"status"}` returns the current run/plan/queue state,
|
|
465
|
+
`{"action":"explain"}` adds a one-line plain-language summary, and
|
|
466
|
+
`{"action":"enqueue","input":"..."}` accepts a new request without touching the
|
|
467
|
+
active plan. A queued request starts automatically as soon as the workspace
|
|
468
|
+
goes idle — either because the enqueue call itself found the workspace free,
|
|
469
|
+
or because the run in progress finished and drained the next queued item.
|
|
470
|
+
|
|
471
|
+
`GET /config/profiles` lists the `.wikirc` profiles for a workspace and
|
|
472
|
+
`POST /config/use {"profile":"..."}` switches the active one — the same
|
|
473
|
+
switch as the shell's `/config use`, rejected with 409 while a run is active.
|
|
474
|
+
The manager is the source of truth for which profile is active; `llm-wiki
|
|
475
|
+
serve`'s config-profile picker mirrors whatever the manager reports rather
|
|
476
|
+
than tracking its own state.
|
|
477
|
+
|
|
463
478
|
### Starting external agents
|
|
464
479
|
|
|
465
480
|
Start CME, documents, and mailer once for all workspaces:
|
|
@@ -512,13 +527,17 @@ The shared `docker-compose.yml` starts one workspace stack:
|
|
|
512
527
|
|
|
513
528
|
| Service | Role | Port variable |
|
|
514
529
|
| --- | --- | --- |
|
|
515
|
-
| `serve` | Wiki web UI and browser chat | `WIKI_SERVE_PORT` |
|
|
516
|
-
| `mcp-http` | llm-wiki MCP endpoint | `WIKI_MCP_PORT` |
|
|
517
|
-
| `production-mcp` | Production job MCP endpoint | `PRODUCTION_MCP_PORT` |
|
|
530
|
+
| `serve` | Wiki web UI and browser chat, container port `3000` | `WIKI_SERVE_PORT` |
|
|
531
|
+
| `mcp-http` | llm-wiki MCP endpoint, container port `3333` | `WIKI_MCP_PORT` |
|
|
532
|
+
| `production-mcp` | Production job MCP endpoint, container port `8080` | `PRODUCTION_MCP_PORT` |
|
|
518
533
|
|
|
519
534
|
Use `wiki-workspace` whenever possible so Compose receives the right project
|
|
520
535
|
name, env file, ports, and volume mounts.
|
|
521
536
|
|
|
537
|
+
Runtime split: the host manager/runtime uses Node.js 22+ for `node:sqlite`; the
|
|
538
|
+
interactive OpenTUI shell uses Bun 1.2+; workspace Docker services run from the
|
|
539
|
+
published images and do not depend on host `node_modules`.
|
|
540
|
+
|
|
522
541
|
```bash
|
|
523
542
|
wiki-workspace list
|
|
524
543
|
wiki-workspace agents up
|
|
@@ -784,12 +803,23 @@ Files matching `docker-compose*.local.yml` are ignored by Git.
|
|
|
784
803
|
```bash
|
|
785
804
|
pnpm install
|
|
786
805
|
pnpm start
|
|
806
|
+
pnpm run check-versions
|
|
787
807
|
pnpm run check
|
|
788
808
|
```
|
|
789
809
|
|
|
790
|
-
When bumping
|
|
791
|
-
|
|
792
|
-
|
|
810
|
+
When bumping a coordinated release, keep `llm-wiki`, `llm-wiki-manager`, Python
|
|
811
|
+
agent `_AGENT_VERSION` values, MCP `clientInfo.version` / server versions, Git
|
|
812
|
+
tags, and Docker image tags aligned. Run:
|
|
813
|
+
|
|
814
|
+
```bash
|
|
815
|
+
pnpm run check-versions
|
|
816
|
+
CHECK_GIT_TAG=1 pnpm run check-versions # pre-release tag check
|
|
817
|
+
CHECK_DOCKER_IMAGES=1 pnpm run check-versions # after local image build
|
|
818
|
+
```
|
|
819
|
+
|
|
820
|
+
`build-and-push.sh` synchronizes the coordinated version, runs
|
|
821
|
+
`pnpm run check-versions`, builds images tagged with that version, and can push
|
|
822
|
+
the matching `latest` tags.
|
|
793
823
|
|
|
794
824
|
`pnpm run check` verifies the CLI version, help output, and limited `--once` mode.
|
|
795
825
|
For headless changes, also test a controlled error path, for example:
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
# MAILERSEND_API_KEY
|
|
22
22
|
# MAILERSEND_FROM_EMAIL
|
|
23
23
|
# MAILERSEND_FROM_NAME
|
|
24
|
+
# MAILERSEND_CA_CERT — optional CA bundle path inside the container
|
|
24
25
|
#
|
|
25
26
|
# Set these variables in a .env file at the directory where you run wiki-workspace,
|
|
26
27
|
# or export them in your shell before running wiki-workspace agents up.
|
|
@@ -90,7 +91,11 @@ services:
|
|
|
90
91
|
- MAILERSEND_FROM_NAME=${MAILERSEND_FROM_NAME:-Mailer Agent}
|
|
91
92
|
- MAILERSEND_USER_AGENT=${MAILERSEND_USER_AGENT:-curl/8.7.1}
|
|
92
93
|
- MAILERSEND_VERIFY_SSL=${MAILERSEND_VERIFY_SSL:-true}
|
|
94
|
+
- MAILERSEND_CA_CERT=${MAILERSEND_CA_CERT:-}
|
|
93
95
|
- MAILER_REQUIRE_CONFIRMATION=${MAILER_REQUIRE_CONFIRMATION:-true}
|
|
94
96
|
- MAILER_DRY_RUN=${MAILER_DRY_RUN:-false}
|
|
95
97
|
- MCP_AUTH_TOKEN=${MAILER_MCP_AUTH_TOKEN:-}
|
|
98
|
+
volumes:
|
|
99
|
+
# Optional: mount a CA bundle and set MAILERSEND_CA_CERT to its container path.
|
|
100
|
+
#- ${AGENTS_DATA_DIR:-./.agents-data}/certs:/certs:ro
|
|
96
101
|
restart: unless-stopped
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dotdrelle/wiki-manager",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.4",
|
|
4
4
|
"description": "Agentic shell and orchestration cockpit for llm-wiki workspaces.",
|
|
5
5
|
"license": "PolyForm-Noncommercial-1.0.0",
|
|
6
6
|
"author": "dotrelle",
|
|
@@ -11,7 +11,10 @@
|
|
|
11
11
|
},
|
|
12
12
|
"scripts": {
|
|
13
13
|
"start": "bun ./bin/wiki-manager.js",
|
|
14
|
-
"test": "node --test src/agent/graph.test.js src/core/activity.test.js src/core/agentEvents.test.js src/core/agentLoop.test.js src/core/plan.test.js src/core/mcp.test.js src/core/documentIntake.test.js src/core/dockerCompose.test.js src/core/wikiWorkspace.test.js src/core/wikirc.test.js src/core/modelFetch.test.js src/core/startupCheck.test.js src/core/queueStore.test.js src/commands/slash.test.js src/shell/repl.test.js src/runtime/store.test.js src/runtime/server.test.js src/runtime/supervisor.test.js src/runtime/runner.test.js src/runtime/auth.test.js",
|
|
14
|
+
"test": "node --test src/agent/graph.test.js src/contracts/schemas.test.js src/core/activity.test.js src/core/agentEvents.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/documentIntake.test.js src/core/dockerCompose.test.js src/core/wikiWorkspace.test.js src/core/wikirc.test.js src/core/modelFetch.test.js src/core/startupCheck.test.js src/core/queueStore.test.js src/commands/slash.test.js src/shell/repl.test.js src/runtime/store.test.js src/runtime/server.test.js src/runtime/supervisor.test.js src/runtime/runner.test.js src/runtime/auth.test.js",
|
|
15
|
+
"check-versions": "node scripts/check-versions.js",
|
|
16
|
+
"prepack": "node scripts/check-versions.js",
|
|
17
|
+
"prepublishOnly": "node scripts/check-versions.js",
|
|
15
18
|
"check": "bun ./bin/wiki-manager.js --version && bun ./bin/wiki-manager.js --help && bun ./bin/wiki-manager.js --once \"verifie le mode agent\""
|
|
16
19
|
},
|
|
17
20
|
"engines": {
|
package/src/agent/graph.js
CHANGED
|
@@ -66,8 +66,26 @@ const WIKI_PLAN_SET_TOOL = {
|
|
|
66
66
|
properties: {
|
|
67
67
|
steps: {
|
|
68
68
|
type: 'array',
|
|
69
|
-
items: {
|
|
70
|
-
|
|
69
|
+
items: {
|
|
70
|
+
anyOf: [
|
|
71
|
+
{ type: 'string' },
|
|
72
|
+
{
|
|
73
|
+
type: 'object',
|
|
74
|
+
additionalProperties: false,
|
|
75
|
+
properties: {
|
|
76
|
+
id: { type: 'string' },
|
|
77
|
+
description: { type: 'string' },
|
|
78
|
+
status: { type: 'string', enum: ['pending', 'queued', 'running', 'waiting', 'pending_approval', 'done', 'failed', 'cancelled', 'stalled', 'added_during_run'] },
|
|
79
|
+
dependsOn: { type: 'array', items: { type: 'string' } },
|
|
80
|
+
executor: { type: ['string', 'null'] },
|
|
81
|
+
executorQuery: { type: ['object', 'null'], additionalProperties: true },
|
|
82
|
+
outputRefs: { type: 'array', items: { type: 'string' } },
|
|
83
|
+
},
|
|
84
|
+
required: ['description'],
|
|
85
|
+
},
|
|
86
|
+
],
|
|
87
|
+
},
|
|
88
|
+
description: 'Ordered steps. Backward-compatible strings are accepted; structured steps may include id, dependsOn, executor, executorQuery, outputRefs.',
|
|
71
89
|
},
|
|
72
90
|
},
|
|
73
91
|
required: ['steps'],
|
|
@@ -344,11 +362,7 @@ function handleWikiTool(session, tool, args) {
|
|
|
344
362
|
if (tool === 'plan_set') {
|
|
345
363
|
const steps = Array.isArray(args.steps) ? args.steps : [];
|
|
346
364
|
emitAgentEvent(session, 'plan_set', 'tool', {
|
|
347
|
-
steps: steps.map((
|
|
348
|
-
step: i + 1,
|
|
349
|
-
description: String(description),
|
|
350
|
-
status: 'pending',
|
|
351
|
-
})),
|
|
365
|
+
steps: steps.map((raw, i) => normalizeDeclaredPlanStep(raw, i, session)),
|
|
352
366
|
});
|
|
353
367
|
return `Plan registered: ${steps.length} step${steps.length !== 1 ? 's' : ''}.`;
|
|
354
368
|
}
|
|
@@ -364,6 +378,51 @@ function handleWikiTool(session, tool, args) {
|
|
|
364
378
|
return `Unknown wiki tool: ${tool}`;
|
|
365
379
|
}
|
|
366
380
|
|
|
381
|
+
function normalizeDeclaredPlanStep(raw, index, session) {
|
|
382
|
+
const item = raw && typeof raw === 'object' && !Array.isArray(raw)
|
|
383
|
+
? raw
|
|
384
|
+
: { description: String(raw) };
|
|
385
|
+
const description = String(item.description ?? item.label ?? item.name ?? item.id ?? `Step ${index + 1}`);
|
|
386
|
+
return {
|
|
387
|
+
step: Number(item.step ?? index + 1),
|
|
388
|
+
id: item.id ? String(item.id) : slugStepId(description, index),
|
|
389
|
+
description,
|
|
390
|
+
status: item.status ?? 'pending',
|
|
391
|
+
dependsOn: Array.isArray(item.dependsOn) ? item.dependsOn.map(String) : [],
|
|
392
|
+
executor: item.executor ?? selectExecutorForStep(description, session),
|
|
393
|
+
executorQuery: item.executorQuery ?? null,
|
|
394
|
+
outputRefs: Array.isArray(item.outputRefs) ? item.outputRefs.map(String) : [],
|
|
395
|
+
};
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
function slugStepId(description, index) {
|
|
399
|
+
const slug = String(description)
|
|
400
|
+
.toLowerCase()
|
|
401
|
+
.normalize('NFD')
|
|
402
|
+
.replace(/[\u0300-\u036f]/g, '')
|
|
403
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
404
|
+
.replace(/^-+|-+$/g, '')
|
|
405
|
+
.slice(0, 48);
|
|
406
|
+
return slug || `task-${index + 1}`;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
function selectExecutorForStep(description, session) {
|
|
410
|
+
const text = String(description ?? '').toLowerCase();
|
|
411
|
+
let fallback = null;
|
|
412
|
+
for (const [serverName, value] of Object.entries(session.mcp ?? {})) {
|
|
413
|
+
if (value.status !== 'connected') continue;
|
|
414
|
+
for (const tool of value.tools ?? []) {
|
|
415
|
+
const executor = `${serverName}.${tool.name}`;
|
|
416
|
+
fallback ??= executor;
|
|
417
|
+
const haystack = `${serverName} ${tool.name} ${tool.description ?? ''}`.toLowerCase();
|
|
418
|
+
if (text.split(/[^a-z0-9]+/).filter((token) => token.length >= 4).some((token) => haystack.includes(token))) {
|
|
419
|
+
return executor;
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
return fallback;
|
|
424
|
+
}
|
|
425
|
+
|
|
367
426
|
export function buildAgentSystemPrompt(state) {
|
|
368
427
|
const workspace = state.session.workspace ?? 'no workspace selected';
|
|
369
428
|
const wikirc = state.session.wikirc?.profile ?? 'no profile loaded';
|
|
@@ -401,8 +460,8 @@ export function buildAgentSystemPrompt(state) {
|
|
|
401
460
|
'',
|
|
402
461
|
'Task startup:',
|
|
403
462
|
' 1. If the next MCP tool returns _activity.plan.steps, call that tool directly; the shell will create the visible plan from the returned activity.',
|
|
404
|
-
' 2. If the tool cannot declare its own plan, call wiki__plan_set
|
|
405
|
-
' Multi-tool example: wiki__plan_set(steps=["CME export",
|
|
463
|
+
' 2. If the tool cannot declare its own plan, call wiki__plan_set before executing the first step. Prefer structured steps: {id, description, dependsOn, executor, executorQuery, outputRefs}; a legacy list of strings is still accepted.',
|
|
464
|
+
' Multi-tool example: wiki__plan_set(steps=[{id:"cme-export",description:"CME export",dependsOn:[],executor:"cme.cme_export_run",outputRefs:["raw/untracked"]},{id:"production",description:"Production pipeline",dependsOn:["cme-export"],executor:"production.production_start_job",outputRefs:["deliverables"]}])',
|
|
406
465
|
' 3. Immediately execute the first step using the appropriate MCP tool. Do not start step 2 in the same turn unless one async pipeline tool owns and declares the whole sequence.',
|
|
407
466
|
' For synchronous steps (result is immediate, no _activity polling), call wiki__plan_done(step=1) after confirming success.',
|
|
408
467
|
' For async MCP jobs (returns _activity with poll), the orchestrator tracks completion automatically.',
|
package/src/agent/graph.test.js
CHANGED
|
@@ -143,3 +143,67 @@ test('agent graph waits for tool-level approval configured on endpoint', async (
|
|
|
143
143
|
}
|
|
144
144
|
});
|
|
145
145
|
|
|
146
|
+
test('agent graph accepts structured wiki plan steps and selects MCP executors', async () => {
|
|
147
|
+
let calls = 0;
|
|
148
|
+
const session = sessionBase({
|
|
149
|
+
mcp: {
|
|
150
|
+
cme: {
|
|
151
|
+
status: 'connected',
|
|
152
|
+
url: 'http://127.0.0.1:3001/mcp/',
|
|
153
|
+
tools: [{
|
|
154
|
+
name: 'cme_export_run',
|
|
155
|
+
description: 'Export CME pages',
|
|
156
|
+
inputSchema: { type: 'object', properties: {} },
|
|
157
|
+
}],
|
|
158
|
+
},
|
|
159
|
+
production: {
|
|
160
|
+
status: 'connected',
|
|
161
|
+
url: 'http://127.0.0.1:3000/mcp/',
|
|
162
|
+
tools: [{
|
|
163
|
+
name: 'production_start_job',
|
|
164
|
+
description: 'Start production job',
|
|
165
|
+
inputSchema: { type: 'object', properties: { type: { type: 'string' } } },
|
|
166
|
+
}],
|
|
167
|
+
},
|
|
168
|
+
},
|
|
169
|
+
llm: {
|
|
170
|
+
async completeWithTools() {
|
|
171
|
+
calls += 1;
|
|
172
|
+
if (calls === 1) {
|
|
173
|
+
return {
|
|
174
|
+
content: null,
|
|
175
|
+
message: { role: 'assistant', content: null },
|
|
176
|
+
tool_calls: [{
|
|
177
|
+
id: 'plan-call',
|
|
178
|
+
type: 'function',
|
|
179
|
+
function: {
|
|
180
|
+
name: 'wiki__plan_set',
|
|
181
|
+
arguments: JSON.stringify({
|
|
182
|
+
steps: [
|
|
183
|
+
{ id: 'cme-export', description: 'Export CME pages', outputRefs: ['raw/untracked'] },
|
|
184
|
+
{ id: 'build', description: 'Run production build', dependsOn: ['cme-export'] },
|
|
185
|
+
],
|
|
186
|
+
}),
|
|
187
|
+
},
|
|
188
|
+
}],
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
return {
|
|
192
|
+
content: 'Plan ready.',
|
|
193
|
+
message: { role: 'assistant', content: 'Plan ready.' },
|
|
194
|
+
tool_calls: null,
|
|
195
|
+
};
|
|
196
|
+
},
|
|
197
|
+
},
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
const agent = createAgentGraph();
|
|
201
|
+
const result = await agent.invoke({ input: 'Plan export then build', session });
|
|
202
|
+
|
|
203
|
+
assert.equal(result.response, 'Plan ready.');
|
|
204
|
+
assert.deepEqual(session.headlessPlan.map((step) => step.id), ['cme-export', 'build']);
|
|
205
|
+
assert.equal(session.headlessPlan[0].executor, 'cme.cme_export_run');
|
|
206
|
+
assert.equal(session.headlessPlan[1].executor, 'production.production_start_job');
|
|
207
|
+
assert.deepEqual(session.headlessPlan[1].dependsOn, ['cme-export']);
|
|
208
|
+
assert.deepEqual(session.headlessPlan[0].outputRefs, ['raw/untracked']);
|
|
209
|
+
});
|
package/src/cli/wiki-manager.js
CHANGED
|
@@ -8,6 +8,8 @@ import { createAgentGraph } from '../agent/graph.js';
|
|
|
8
8
|
import { handleSlashCommand, printHelp, printVersion, refreshMcpRuntimeStatus } from '../commands/slash.js';
|
|
9
9
|
import { runShell } from '../shell/repl.js';
|
|
10
10
|
import { runChecks } from '../core/startupCheck.js';
|
|
11
|
+
import { applySessionWikircProfile } from '../core/sessionConfig.js';
|
|
12
|
+
import { listWikircProfiles } from '../core/wikirc.js';
|
|
11
13
|
import { callMcpTool, formatMcpToolResult } from '../core/mcp.js';
|
|
12
14
|
import { extractActivity, parseJsonText, sessionActivities, terminalFailures } from '../core/activity.js';
|
|
13
15
|
import { syncActivitiesToPlan, formatPlanStatus } from '../core/plan.js';
|
|
@@ -161,7 +163,7 @@ async function runHeadlessAgenticLoop(agent, session, initialInput, log, { timeo
|
|
|
161
163
|
console.log(response);
|
|
162
164
|
},
|
|
163
165
|
onPlanExtracted: ({ steps }) => {
|
|
164
|
-
log.push(`agentic-loop: plan extracted from text (${steps.length} steps, fallback)`);
|
|
166
|
+
log.push(`agentic-loop: plan extracted from text (${steps.length} steps, deprecated fallback)`);
|
|
165
167
|
},
|
|
166
168
|
onPlanAlreadySet: ({ steps }) => {
|
|
167
169
|
log.push(`agentic-loop: plan set via tool (${steps.length} steps)`);
|
|
@@ -512,11 +514,14 @@ async function runRuntime(argv, agent) {
|
|
|
512
514
|
};
|
|
513
515
|
}
|
|
514
516
|
emitRuntimeLog(context.session, manual ? 'runtime: manual resume completed' : 'runtime: recovery completed');
|
|
517
|
+
const controlStarted = pollingActivities.length === 0
|
|
518
|
+
? serverHandle?.drainControl?.(context) === true
|
|
519
|
+
: false;
|
|
515
520
|
return {
|
|
516
521
|
workspace: context.workspace ?? workspace ?? null,
|
|
517
522
|
resumed: true,
|
|
518
523
|
interrupted: 0,
|
|
519
|
-
mode: pollingActivities.length > 0 ? 'activity_poll' : 'context',
|
|
524
|
+
mode: controlStarted ? 'control_queue' : pollingActivities.length > 0 ? 'activity_poll' : 'context',
|
|
520
525
|
};
|
|
521
526
|
} catch (err) {
|
|
522
527
|
const interrupted = store.interruptRuns({ workspace });
|
|
@@ -629,6 +634,33 @@ async function runRuntime(argv, agent) {
|
|
|
629
634
|
const context = await getWorkspaceContext(workspace);
|
|
630
635
|
return context.approvalManager?.approve({ runId, itemId, approvalId }) ?? { approved: false };
|
|
631
636
|
},
|
|
637
|
+
configProfiles: async (context) => {
|
|
638
|
+
const profiles = listWikircProfiles(context.session.workspacePath);
|
|
639
|
+
return {
|
|
640
|
+
profiles: profiles.map((profile) => profile.name),
|
|
641
|
+
active: context.session.wikirc?.profile ?? null,
|
|
642
|
+
items: profiles.map((profile) => ({
|
|
643
|
+
name: profile.name,
|
|
644
|
+
fileName: profile.fileName,
|
|
645
|
+
default: Boolean(profile.default),
|
|
646
|
+
})),
|
|
647
|
+
};
|
|
648
|
+
},
|
|
649
|
+
useConfigProfile: async (context, profile) => {
|
|
650
|
+
const { summary, config } = applySessionWikircProfile(context.session, profile);
|
|
651
|
+
await refreshMcpRuntimeStatus(context.session);
|
|
652
|
+
dispatchAgentEvent(context.session, createAgentEvent('runtime_log', {
|
|
653
|
+
origin: 'runtime',
|
|
654
|
+
payload: { message: `runtime: config profile switched to ${context.session.wikirc?.profile ?? profile}` },
|
|
655
|
+
}));
|
|
656
|
+
return {
|
|
657
|
+
ok: true,
|
|
658
|
+
active: context.session.wikirc?.profile ?? profile,
|
|
659
|
+
fileName: context.session.wikirc?.fileName ?? null,
|
|
660
|
+
summary,
|
|
661
|
+
config,
|
|
662
|
+
};
|
|
663
|
+
},
|
|
632
664
|
token: auth.token,
|
|
633
665
|
});
|
|
634
666
|
const recovery = await recoverRuntime();
|
package/src/commands/slash.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { execFileSync } from 'node:child_process';
|
|
2
2
|
import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs';
|
|
3
3
|
import { join, relative } from 'node:path';
|
|
4
|
-
import { createLlmClientFromWikiConfig } from '../agent/llm.js';
|
|
5
4
|
import { composeServices, listServices, runWikiCli, serviceLogs, serviceStates, startService, stopService } from '../core/compose.js';
|
|
6
5
|
import {
|
|
7
6
|
applyMcpRuntimeStatus,
|
|
@@ -26,10 +25,10 @@ import {
|
|
|
26
25
|
} from '../core/jobQueue.js';
|
|
27
26
|
import {
|
|
28
27
|
listWikircProfiles,
|
|
29
|
-
loadWikircProfile,
|
|
30
28
|
resolveWikircProfile,
|
|
31
29
|
summarizeWikircConfig,
|
|
32
30
|
} from '../core/wikirc.js';
|
|
31
|
+
import { applySessionWikircProfile } from '../core/sessionConfig.js';
|
|
33
32
|
import { deleteWorkspaceAndFiles, startAgents, stopAgents } from '../core/wikiSetup.js';
|
|
34
33
|
import {
|
|
35
34
|
cleanDocumentUploads,
|
|
@@ -546,25 +545,6 @@ function loadWorkspaceSystemPrompt(workspacePath) {
|
|
|
546
545
|
return existsSync(promptPath) ? readFileSync(promptPath, 'utf8').trim() || null : null;
|
|
547
546
|
}
|
|
548
547
|
|
|
549
|
-
function loadSessionWikirc(session, profileName = 'default') {
|
|
550
|
-
if (!session.workspacePath) {
|
|
551
|
-
throw new Error('No workspace loaded. Use /use <workspace>.');
|
|
552
|
-
}
|
|
553
|
-
const loaded = loadWikircProfile(session.workspacePath, profileName);
|
|
554
|
-
session.wikirc = {
|
|
555
|
-
profile: loaded.profile.name,
|
|
556
|
-
fileName: loaded.profile.fileName,
|
|
557
|
-
path: loaded.profile.path,
|
|
558
|
-
};
|
|
559
|
-
session.wikircConfig = loaded.config;
|
|
560
|
-
session.language = loaded.config?.language ?? null;
|
|
561
|
-
session.llm = createLlmClientFromWikiConfig(loaded.config);
|
|
562
|
-
if (session.mcp?.production) {
|
|
563
|
-
session.mcp.production.activeConfigPath = loaded.profile.fileName;
|
|
564
|
-
}
|
|
565
|
-
return summarizeWikircConfig(loaded.profile, loaded.config);
|
|
566
|
-
}
|
|
567
|
-
|
|
568
548
|
function clearWorkspaceSession(session) {
|
|
569
549
|
session.workspace = null;
|
|
570
550
|
session.workspacePath = null;
|
|
@@ -635,8 +615,8 @@ ${helpPair('/workspace list', 'Workspaces', '/new <n> [path]', 'New workspace')}
|
|
|
635
615
|
${helpPair('/use <workspace>', 'Use workspace', '/status', 'Session status')}
|
|
636
616
|
${helpPair('/config list', 'Config profiles', '/config use <n>', 'Use config')}
|
|
637
617
|
${helpPair('/config edit <n>', 'Edit config', '/workspace delete <n>', 'Delete workspace')}
|
|
638
|
-
${helpPair('/services', 'Services', '/start [service|agents]', 'Start service(s)')}
|
|
639
|
-
${helpPair('/stop [service|agents]', 'Stop service(s)', '/logs <service>', 'Service logs')}
|
|
618
|
+
${helpPair('/services', 'Services', '/start [all|service|agents]', 'Start service(s)')}
|
|
619
|
+
${helpPair('/stop [all|service|agents]', 'Stop service(s)', '/logs <service>', 'Service logs')}
|
|
640
620
|
${helpPair('/skills', 'List skills', '/skills show <n>', 'Show skill')}
|
|
641
621
|
${helpPair('/skills run <n>', 'Run skill guide', '/skills edit <n>', 'Edit skill')}
|
|
642
622
|
${helpPair('/mcp status', 'MCP status', '/mcp endpoints', 'MCP endpoints')}
|
|
@@ -720,7 +700,7 @@ export async function handleSlashCommand(line, context) {
|
|
|
720
700
|
context.session.systemPrompt = loadWorkspaceSystemPrompt(workspace.workspacePath);
|
|
721
701
|
try {
|
|
722
702
|
step(`Workspace: loading ${workspace.name} config…`);
|
|
723
|
-
const summary =
|
|
703
|
+
const { summary } = applySessionWikircProfile(context.session, 'default');
|
|
724
704
|
step(`Workspace: discovering ${workspace.name} MCP tools…`);
|
|
725
705
|
await refreshMcpRuntimeStatus(context.session);
|
|
726
706
|
return {
|
|
@@ -759,7 +739,7 @@ export async function handleSlashCommand(line, context) {
|
|
|
759
739
|
return { output: 'Usage: /config use <default|name>' };
|
|
760
740
|
}
|
|
761
741
|
try {
|
|
762
|
-
const summary =
|
|
742
|
+
const { summary } = applySessionWikircProfile(context.session, profileName);
|
|
763
743
|
await refreshMcpRuntimeStatus(context.session);
|
|
764
744
|
return {
|
|
765
745
|
output: [
|
|
@@ -830,6 +810,10 @@ export async function handleSlashCommand(line, context) {
|
|
|
830
810
|
}
|
|
831
811
|
}
|
|
832
812
|
case 'start': {
|
|
813
|
+
// 'all' already resolves correctly through serviceAliases() (DEFAULT_SERVICE_ALIASES.all
|
|
814
|
+
// = COMPOSE_SERVICES, overridable via docker-compose.yml's service-aliases.all.targets) —
|
|
815
|
+
// do not remap it to undefined, that bypasses any custom "all" target list and always
|
|
816
|
+
// falls back to the hardcoded COMPOSE_SERVICES constant instead.
|
|
833
817
|
const service = args[1];
|
|
834
818
|
if (service === 'agents') return runAgentCommand(startAgents, 'start');
|
|
835
819
|
try {
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Runtime Contracts
|
|
2
|
+
|
|
3
|
+
Versioned JSON Schema-like contracts live in `schemas.js`.
|
|
4
|
+
|
|
5
|
+
Current schema version: `1`.
|
|
6
|
+
|
|
7
|
+
Validated boundaries:
|
|
8
|
+
|
|
9
|
+
- `_activity` after normalization in `core/activity.js`
|
|
10
|
+
- `AgentRunEvent` creation and dispatch in `core/agentEvents.js`
|
|
11
|
+
- structured plan and plan patch normalization
|
|
12
|
+
- runtime `/run` and `/control` request payloads
|
|
13
|
+
|
|
14
|
+
Validation is enabled when `WIKI_MANAGER_VALIDATE_CONTRACTS=1`, `CI=true`, or
|
|
15
|
+
`NODE_ENV` is set to a non-production value. Schemas tolerate additional fields
|
|
16
|
+
so agents can extend payloads without breaking older consumers.
|