@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.
- package/.env.example +10 -3
- package/README.md +54 -0
- package/agent-runtimes.example.json +68 -0
- package/agents.docker-compose.yml +35 -1
- package/docker-compose.yml +3 -3
- package/package.json +3 -2
- package/src/agent/graph.js +12 -11
- package/src/agent/skillRecursion.test.js +13 -12
- package/src/cli/wiki-manager.js +124 -36
- package/src/commands/slash.js +38 -3
- package/src/contracts/schemas.js +67 -0
- package/src/core/activity.js +5 -0
- package/src/core/agentEvents.js +18 -1
- package/src/core/buildInfo.json +2 -2
- package/src/core/dockerCompose.test.js +8 -40
- package/src/core/env.js +14 -0
- package/src/core/env.test.js +19 -0
- package/src/core/googleGrants.test.js +1 -1
- package/src/core/mcp.js +1 -1
- package/src/core/runtimeEventAdapter.js +81 -0
- package/src/core/runtimeEventAdapter.test.js +61 -0
- package/src/core/skillChainView.test.js +2 -2
- package/src/core/skillCompiler.test.js +1 -1
- package/src/core/skillInvocation.js +13 -8
- package/src/core/startupCheck.js +58 -0
- package/src/core/startupCheck.test.js +29 -1
- package/src/orchestrator/agentRegistry.js +1 -22
- package/src/orchestrator/assignmentManager.js +16 -4
- package/src/orchestrator/capabilityRegistry.js +8 -1
- package/src/orchestrator/dispatcher.js +361 -2
- package/src/orchestrator/dispatcher.test.js +112 -1
- package/src/orchestrator/objectiveResolver.js +10 -6
- package/src/orchestrator/objectiveResolver.test.js +26 -27
- package/src/orchestrator/providers/deepAgentsProvider.js +168 -0
- package/src/orchestrator/providers/deepAgentsProvider.test.js +178 -0
- package/src/orchestrator/providers/dispatcherExternalRuntime.test.js +409 -0
- package/src/orchestrator/providers/fakeRuntimeProvider.js +164 -0
- package/src/orchestrator/providers/fakeRuntimeProvider.test.js +201 -0
- package/src/orchestrator/providers/runtimeProvider.js +101 -0
- package/src/orchestrator/providers/runtimeProviders.js +325 -0
- package/src/orchestrator/providers/runtimeProviders.test.js +361 -0
- package/src/orchestrator/resultAggregator.js +35 -2
- package/src/orchestrator/resultAggregator.test.js +62 -0
- package/src/runtime/recoveryManager.js +70 -5
- package/src/runtime/skillChain.e2e.test.js +2 -2
- package/src/runtime/supervisor.js +5 -10
- package/src/shell/RightPane.tsx +9 -1
- package/src/shell/StartupScreen.tsx +44 -7
- package/src/shell/repl.test.js +13 -0
- package/wiki-workspace +19 -3
package/src/shell/RightPane.tsx
CHANGED
|
@@ -263,7 +263,11 @@ export function PlanPanel(props: { plan: PlanStep[]; width: number; jobName?: st
|
|
|
263
263
|
|
|
264
264
|
export function ActivityPanel(props: { activities: any[]; width: number }) {
|
|
265
265
|
const lineWidth = () => Math.max(8, props.width - 2);
|
|
266
|
-
|
|
266
|
+
// session.activities is never pruned within a run (see core/agentEvents.js),
|
|
267
|
+
// so a long batch job's activity count is unbounded — render only the most
|
|
268
|
+
// recent slice, memoized like LogPanel's allLines, instead of copying and
|
|
269
|
+
// re-wrapping the entire lifetime history on every reactive tick.
|
|
270
|
+
const visible = createMemo(() => props.activities.slice(-200).reverse());
|
|
267
271
|
return (
|
|
268
272
|
<box flexGrow={1} flexDirection="column" paddingX={1} backgroundColor="#111318">
|
|
269
273
|
<text width={lineWidth()} fg="#D6DEE8" content="Activity" />
|
|
@@ -340,6 +344,10 @@ type LogSegment = { text: string; fg: string };
|
|
|
340
344
|
// Continuation lines of a wrapped entry are indented and dimmed so each
|
|
341
345
|
// entry reads as one visual block instead of an undifferentiated wall.
|
|
342
346
|
function logMessageColor(message: string): string {
|
|
347
|
+
// A doctor summary with ZERO errors is a warning by construction
|
|
348
|
+
// ("⚠ 0 error(s), 2 warning(s)") — amber, never red, even though it
|
|
349
|
+
// mentions the word "error".
|
|
350
|
+
if (/(?<!\d)0 error\(s\)/i.test(message)) return '#FBBF24';
|
|
343
351
|
if (/\b(?:trace:\s*)?WARN\b/i.test(message)) return '#FBBF24';
|
|
344
352
|
if (/\b(error|failed|exception|unavailable|introuvable|HTTP 4\d\d|HTTP 5\d\d)\b/i.test(message)) return '#F38BA8';
|
|
345
353
|
if (/\b(warn|warning|avertissement|fallback|retry|expired|stale)\b/i.test(message)) return '#FBBF24';
|
|
@@ -238,9 +238,36 @@ export function StartupScreen(props: {
|
|
|
238
238
|
});
|
|
239
239
|
|
|
240
240
|
const preflightChecks = createMemo(() => props.preflight?.checks ?? []);
|
|
241
|
+
const checkByKind = createMemo(() => {
|
|
242
|
+
const map = new Map<string, any>();
|
|
243
|
+
for (const check of preflightChecks()) map.set(check.kind, check);
|
|
244
|
+
return map;
|
|
245
|
+
});
|
|
246
|
+
// Docker and Internet leave the check list: they are ambient state, shown in
|
|
247
|
+
// the header (top right), not among the startup rows.
|
|
248
|
+
const dockerCheck = createMemo(() => checkByKind().get('docker'));
|
|
249
|
+
const internetCheck = createMemo(() => checkByKind().get('internet'));
|
|
250
|
+
const listChecks = createMemo(() => {
|
|
251
|
+
const order = ['workspace', 'runtime', 'agentic', 'agents', 'containers', 'mcp'];
|
|
252
|
+
const seen = new Set<string>(['docker', 'internet']);
|
|
253
|
+
const ordered: Array<{ kind: string; ok?: boolean; skipped?: boolean; pending?: boolean; detail?: string }> = [];
|
|
254
|
+
for (const kind of order) {
|
|
255
|
+
const check = checkByKind().get(kind);
|
|
256
|
+
if (!check) continue;
|
|
257
|
+
// An optional engine is not part of the startup story: when nothing is
|
|
258
|
+
// enabled, its row disappears instead of showing a misleading green ✓.
|
|
259
|
+
if (kind === 'agentic' && check.skipped) continue;
|
|
260
|
+
ordered.push(check);
|
|
261
|
+
seen.add(kind);
|
|
262
|
+
}
|
|
263
|
+
for (const check of preflightChecks()) {
|
|
264
|
+
if (!seen.has(check.kind)) ordered.push(check);
|
|
265
|
+
}
|
|
266
|
+
return ordered;
|
|
267
|
+
});
|
|
241
268
|
const checkLabel = (kind: string) => ({
|
|
242
269
|
docker: 'Docker', internet: 'Internet', agents: 'Agents', workspace: 'Workspaces',
|
|
243
|
-
containers: 'Containers', mcp: 'MCP', runtime: 'Runtime',
|
|
270
|
+
containers: 'Containers', mcp: 'MCP', agentic: 'Agentic runtime', runtime: 'Runtime',
|
|
244
271
|
} as Record<string, string>)[kind] ?? kind;
|
|
245
272
|
|
|
246
273
|
const subtitle = createMemo(() => {
|
|
@@ -281,10 +308,20 @@ export function StartupScreen(props: {
|
|
|
281
308
|
overflow="hidden"
|
|
282
309
|
>
|
|
283
310
|
<box height={1} flexDirection="row">
|
|
284
|
-
<text fg="#8BD5CA" content={fit(`DONNA v${props.version}`, Math.floor(innerWidth() * 0.
|
|
285
|
-
<text fg={statusColor()} content={fit(` ${props.preflightBusy ? '◐' : statusDot(props.preflight?.status === 'ready')} ${status()}`, Math.floor(innerWidth() * 0.
|
|
311
|
+
<text fg="#8BD5CA" content={fit(`DONNA v${props.version}`, Math.floor(innerWidth() * 0.4))} />
|
|
312
|
+
<text fg={statusColor()} content={fit(` ${props.preflightBusy ? '◐' : statusDot(props.preflight?.status === 'ready')} ${status()}`, Math.floor(innerWidth() * 0.32))} />
|
|
313
|
+
<box flexGrow={1} />
|
|
314
|
+
<text fg="#7F8C8D" content={dockerCheck() ? fit(`Docker — ${dockerCheck()?.detail ?? '—'}`, Math.floor(innerWidth() * 0.28)) : ''} />
|
|
315
|
+
</box>
|
|
316
|
+
<box height={1} flexDirection="row">
|
|
317
|
+
<text height={1} fg="#7F8C8D" content={fit(subtitle(), Math.floor(innerWidth() * 0.6))} />
|
|
318
|
+
<box flexGrow={1} />
|
|
319
|
+
<text
|
|
320
|
+
height={1}
|
|
321
|
+
fg={internetCheck() ? (internetCheck()?.ok ? '#8BD5CA' : '#FBBF24') : '#7F8C8D'}
|
|
322
|
+
content={internetCheck() ? fit(`Internet — ${internetCheck()?.ok ? 'OK' : 'KO'}`, Math.floor(innerWidth() * 0.28)) : ''}
|
|
323
|
+
/>
|
|
286
324
|
</box>
|
|
287
|
-
<text height={1} fg="#7F8C8D" content={fit(subtitle(), innerWidth())} />
|
|
288
325
|
<text height={1}>{''}</text>
|
|
289
326
|
<box
|
|
290
327
|
height={8}
|
|
@@ -295,7 +332,7 @@ export function StartupScreen(props: {
|
|
|
295
332
|
overflow="hidden"
|
|
296
333
|
>
|
|
297
334
|
<text fg="#d6a85f">{DONNA_LOGO}</text>
|
|
298
|
-
<text fg="#888888">Intelligent workspace</text>
|
|
335
|
+
<text fg="#888888">Intelligent Agentic workspace(s)</text>
|
|
299
336
|
</box>
|
|
300
337
|
<text height={1}>{''}</text>
|
|
301
338
|
<text height={1} fg="#7F8C8D" content={menuTitle()} />
|
|
@@ -320,8 +357,8 @@ export function StartupScreen(props: {
|
|
|
320
357
|
</For>
|
|
321
358
|
</box>
|
|
322
359
|
<text height={1}>{''}</text>
|
|
323
|
-
<box height={Math.max(3,
|
|
324
|
-
<For each={
|
|
360
|
+
<box height={Math.max(3, listChecks().length)} flexDirection="column" border={['left']} borderStyle="heavy" borderColor="#5DADE2" paddingX={1} overflow="hidden">
|
|
361
|
+
<For each={listChecks().length ? listChecks() : [
|
|
325
362
|
{ kind: 'workspace', ok: props.wikiReady, detail: props.wikiReady ? 'default profile ready' : 'init required' },
|
|
326
363
|
{ kind: 'mcp', ok: props.connectedMcpServers > 0, detail: `${props.connectedMcpServers} server(s) configured` },
|
|
327
364
|
{ kind: 'llm', ok: Boolean(props.model), detail: props.model || 'not configured' },
|
package/src/shell/repl.test.js
CHANGED
|
@@ -173,6 +173,19 @@ test('Flow/Trace does not repeat the runtime source prefix on every line', async
|
|
|
173
173
|
assert.match(entryRenderer, /prefix\.push\(\{ text: `\$\{parts\.time\} /);
|
|
174
174
|
});
|
|
175
175
|
|
|
176
|
+
test('a doctor summary with a nonzero error count is colored as an error, not a warning', async () => {
|
|
177
|
+
const source = await readFile(new URL('./RightPane.tsx', import.meta.url), 'utf8');
|
|
178
|
+
const colorFn = source.slice(
|
|
179
|
+
source.indexOf('function logMessageColor'),
|
|
180
|
+
source.indexOf('function logRenderLines'),
|
|
181
|
+
);
|
|
182
|
+
// The "0 error(s)" amber shortcut must be digit-anchored: "10 error(s)"
|
|
183
|
+
// ends in "0 error(s)" too, and an unanchored test painted a 10-error
|
|
184
|
+
// doctor failure the same colour as a clean run.
|
|
185
|
+
assert.match(colorFn, /\(\?<!\\d\)0 error\\\(s\\\)/);
|
|
186
|
+
assert.doesNotMatch(colorFn, /\/0 error\\\(s\\\)\/i\.test/);
|
|
187
|
+
});
|
|
188
|
+
|
|
176
189
|
test('runtime logs have a separator and a concise Runtime tab label', async () => {
|
|
177
190
|
const source = await readFile(new URL('./RightPane.tsx', import.meta.url), 'utf8');
|
|
178
191
|
const logPanel = source.slice(
|
package/wiki-workspace
CHANGED
|
@@ -299,7 +299,12 @@ agents_compose() {
|
|
|
299
299
|
local cacert_args=()
|
|
300
300
|
local profile_args=()
|
|
301
301
|
connectors_enabled && profile_args+=(--profile connectors)
|
|
302
|
-
|
|
302
|
+
gateway_enabled && profile_args+=(--profile gateway)
|
|
303
|
+
# The gateway mounts the MANAGER's agent-runtimes.json — absolute path:
|
|
304
|
+
# compose resolves relative volume paths against the compose file's
|
|
305
|
+
# directory (the installed package), never the operator's state dir.
|
|
306
|
+
local agent_runtimes_file="$(dirname "$MANAGER_ENV_FILE")/agent-runtimes.json"
|
|
307
|
+
WORKSPACES_ROOT="$workspaces_root" AGENTS_DATA_DIR="$agents_data_dir" AGENT_RUNTIMES_FILE="$agent_runtimes_file" \
|
|
303
308
|
read_lines_into_array cacert_args cacert_compose_args "$agents_compose_file" "agents.cacert.compose.yml"
|
|
304
309
|
# User-owned override: optional external agents, proxy passthrough and
|
|
305
310
|
# any local fix live in a file the user maintains under .wiki/compose —
|
|
@@ -307,7 +312,7 @@ agents_compose() {
|
|
|
307
312
|
local override_args=()
|
|
308
313
|
local user_override="$MANAGER_COMPOSE_DIR/agents.docker-compose.override.yml"
|
|
309
314
|
[[ -f "$user_override" ]] && override_args+=(-f "$user_override")
|
|
310
|
-
WORKSPACES_ROOT="$workspaces_root" AGENTS_DATA_DIR="$agents_data_dir" \
|
|
315
|
+
WORKSPACES_ROOT="$workspaces_root" AGENTS_DATA_DIR="$agents_data_dir" AGENT_RUNTIMES_FILE="$agent_runtimes_file" \
|
|
311
316
|
COMPOSE_PROFILES= \
|
|
312
317
|
docker compose --project-directory "$DEFAULT_MANAGER_DIR" \
|
|
313
318
|
${compose_env_args[@]+"${compose_env_args[@]}"} -f "$agents_compose_file" ${override_args[@]+"${override_args[@]}"} ${cacert_args[@]+"${cacert_args[@]}"} ${profile_args[@]+"${profile_args[@]}"} -p wiki-agents "$@"
|
|
@@ -331,6 +336,7 @@ agents_compose() {
|
|
|
331
336
|
[[ -f "$MANAGER_ENV_FILE" ]] && compose_env_args+=(--env-file "$MANAGER_ENV_FILE")
|
|
332
337
|
mkdir -p "$agents_data_dir/cme" "$agents_data_dir/documents/input" "$agents_data_dir/documents/output" "$agents_data_dir/documents/uploads"
|
|
333
338
|
connectors_enabled && mkdir -p "$agents_data_dir/connectors"
|
|
339
|
+
gateway_enabled && mkdir -p "$agents_data_dir/gateway"
|
|
334
340
|
mkdir -p "$workspaces_root"
|
|
335
341
|
$do_pull && _agents_dc pull
|
|
336
342
|
local up_args=(up -d)
|
|
@@ -345,6 +351,7 @@ agents_compose() {
|
|
|
345
351
|
printf 'Agents: cme=:%s documents=:%s' \
|
|
346
352
|
"${CME_MCP_PORT:-3336}" "${DOCUMENTS_MCP_PORT:-3337}"
|
|
347
353
|
connectors_enabled && printf ' connectors=:%s' "${CONNECTORS_MCP_PORT:-3338}"
|
|
354
|
+
gateway_enabled && printf ' gateway=:%s' "${GATEWAY_PORT:-7789}"
|
|
348
355
|
printf '\n'
|
|
349
356
|
[[ ! -f "$MANAGER_COMPOSE_DIR/agents.docker-compose.override.yml" ]] || printf 'User override: %s\n' "$MANAGER_COMPOSE_DIR/agents.docker-compose.override.yml"
|
|
350
357
|
;;
|
|
@@ -509,7 +516,7 @@ ensure_agent_tokens() {
|
|
|
509
516
|
# workspace and runtime tokens are generated. Leaving them empty made a
|
|
510
517
|
# fresh install start agents nobody could talk to.
|
|
511
518
|
local key token
|
|
512
|
-
for key in CME_MCP_AUTH_TOKEN DOCUMENTS_MCP_AUTH_TOKEN; do
|
|
519
|
+
for key in CME_MCP_AUTH_TOKEN DOCUMENTS_MCP_AUTH_TOKEN GATEWAY_AUTH_TOKEN; do
|
|
513
520
|
token="$(env_value "$MANAGER_ENV_FILE" "$key" "")"
|
|
514
521
|
if [[ -z "$token" ]]; then
|
|
515
522
|
token="$(generate_token)"
|
|
@@ -558,6 +565,15 @@ connectors_enabled() {
|
|
|
558
565
|
esac
|
|
559
566
|
}
|
|
560
567
|
|
|
568
|
+
gateway_enabled() {
|
|
569
|
+
local enabled
|
|
570
|
+
enabled="$(env_value "$MANAGER_ENV_FILE" GATEWAY_ENABLED "${GATEWAY_ENABLED:-true}")"
|
|
571
|
+
case "$enabled" in
|
|
572
|
+
1|[Tt][Rr][Uu][Ee]|[Yy][Ee][Ss]|[Oo][Nn]) return 0 ;;
|
|
573
|
+
*) return 1 ;;
|
|
574
|
+
esac
|
|
575
|
+
}
|
|
576
|
+
|
|
561
577
|
ensure_endpoints_file() {
|
|
562
578
|
# Without mcp.endpoints.json the shell never connects to the agents it
|
|
563
579
|
# just started (and `agents status` refuses to run). Seed it from the
|