@dotdrelle/wiki-manager 0.7.3 → 0.9.3
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 +20 -0
- package/README.md +50 -1
- package/docker-compose.yml +1 -23
- package/mcp.endpoints.example.json +13 -0
- package/package.json +2 -2
- package/src/agent/graph.js +101 -15
- package/src/agent/graph.test.js +145 -0
- package/src/cli/wiki-manager.js +306 -53
- package/src/commands/slash.js +4 -24
- package/src/core/agentEvents.js +169 -4
- package/src/core/agentEvents.test.js +176 -4
- package/src/core/agentLoop.js +3 -0
- package/src/core/compose.js +1 -2
- package/src/core/dockerCompose.test.js +5 -5
- package/src/core/jobQueue.js +29 -12
- package/src/core/mcp.js +120 -10
- package/src/core/mcp.test.js +121 -1
- package/src/core/plan.js +33 -0
- package/src/core/queueStore.test.js +1 -0
- package/src/core/sessionConfig.js +24 -0
- package/src/core/wikiWorkspace.test.js +24 -0
- package/src/runtime/approvals.js +113 -0
- package/src/runtime/auth.test.js +8 -0
- package/src/runtime/client.js +52 -6
- package/src/runtime/lifecycle.js +27 -3
- package/src/runtime/queueStore.js +3 -3
- package/src/runtime/runner.js +340 -0
- package/src/runtime/runner.test.js +270 -0
- package/src/runtime/server.js +252 -33
- package/src/runtime/server.test.js +577 -0
- package/src/runtime/store.js +181 -39
- package/src/runtime/store.test.js +363 -4
- package/src/runtime/supervisor.js +6 -0
- package/src/runtime/supervisor.test.js +141 -0
- package/src/shell/RightPane.tsx +1 -1
- package/src/shell/repl.js +22 -6
- package/src/shell/useAgent.ts +1 -1
- package/src/shell/useSession.ts +10 -5
- package/wiki-workspace +198 -4
package/src/shell/useSession.ts
CHANGED
|
@@ -5,7 +5,7 @@ import { formatMcpToolResult, callMcpTool } from '../core/mcp.js';
|
|
|
5
5
|
import { extractActivity, parseJsonText, sessionActivities } from '../core/activity.js';
|
|
6
6
|
import { formatPlanStatus, formatCompletedActivities } from '../core/plan.js';
|
|
7
7
|
import { createAgentEvent, dispatchAgentEvent } from '../core/agentEvents.js';
|
|
8
|
-
import { queueCounts, startNextQueuedJob, syncQueueWithActivity } from '../core/jobQueue.js';
|
|
8
|
+
import { projectQueue, queueCounts, startNextQueuedJob, syncQueueWithActivity } from '../core/jobQueue.js';
|
|
9
9
|
import { queueStoreFor } from '../core/queueStore.js';
|
|
10
10
|
import { fetchRuntimeState, streamRuntimeEvents } from '../runtime/client.js';
|
|
11
11
|
import type { ActiveFileEditor } from './FileEditorDialog';
|
|
@@ -186,14 +186,15 @@ export function useSession(props: { agent: unknown; packageJson: Record<string,
|
|
|
186
186
|
version();
|
|
187
187
|
const runtimeQueue = nonEmptyRuntimeArray(runtimeState()?.queue);
|
|
188
188
|
if (runtimeQueue) return runtimeQueue.map((item: any) => ({ ...item, _runtime: true }));
|
|
189
|
-
return ((session as any).jobQueue ?? []
|
|
189
|
+
return projectQueue((session as any).headlessPlan, (session as any).jobQueue ?? [], { workspace: (session as any).workspace ?? null })
|
|
190
|
+
.map((item: any) => ({ ...item }));
|
|
190
191
|
});
|
|
191
192
|
const queueInfo = createMemo(() => {
|
|
192
193
|
version();
|
|
193
194
|
const runtimeQueue = runtimeState()?.queue;
|
|
194
195
|
if (Array.isArray(runtimeQueue)) {
|
|
195
196
|
return {
|
|
196
|
-
active: runtimeQueue.filter((item: any) => ['waiting', 'starting', 'running', 'queued', 'pending'].includes(String(item.status ?? '').toLowerCase())).length,
|
|
197
|
+
active: runtimeQueue.filter((item: any) => ['waiting', 'starting', 'running', 'queued', 'pending', 'pending_approval'].includes(String(item.status ?? '').toLowerCase())).length,
|
|
197
198
|
current: runtimeQueue.filter((item: any) => ['starting', 'running'].includes(String(item.status ?? '').toLowerCase())).length,
|
|
198
199
|
frozen: 0,
|
|
199
200
|
};
|
|
@@ -229,7 +230,7 @@ export function useSession(props: { agent: unknown; packageJson: Record<string,
|
|
|
229
230
|
});
|
|
230
231
|
|
|
231
232
|
function syncRuntimeState() {
|
|
232
|
-
void fetchRuntimeState({ url: props.runtime.url })
|
|
233
|
+
void fetchRuntimeState({ url: props.runtime.url, workspace: (session as any).workspace ?? null })
|
|
233
234
|
.then((state) => {
|
|
234
235
|
setRuntimeState(state);
|
|
235
236
|
setRuntimeStatus('connected');
|
|
@@ -254,7 +255,11 @@ export function useSession(props: { agent: unknown; packageJson: Record<string,
|
|
|
254
255
|
if (!props.runtime?.url || runtimeStreamStopped) return;
|
|
255
256
|
runtimeStreamAbort = new AbortController();
|
|
256
257
|
try {
|
|
257
|
-
for await (const _event of streamRuntimeEvents({
|
|
258
|
+
for await (const _event of streamRuntimeEvents({
|
|
259
|
+
url: props.runtime.url,
|
|
260
|
+
signal: runtimeStreamAbort.signal,
|
|
261
|
+
workspace: (session as any).workspace ?? null,
|
|
262
|
+
})) {
|
|
258
263
|
setRuntimeStatus('connected');
|
|
259
264
|
debouncedSyncRuntimeState();
|
|
260
265
|
}
|
package/wiki-workspace
CHANGED
|
@@ -92,6 +92,11 @@ Commands:
|
|
|
92
92
|
agents pull Pull latest external agent images
|
|
93
93
|
agents status Check reachability of configured MCP endpoints
|
|
94
94
|
|
|
95
|
+
runtime up Start the single host agent-runtime on Node.js 22
|
|
96
|
+
runtime down Stop the host agent-runtime
|
|
97
|
+
runtime status Check host agent-runtime health
|
|
98
|
+
runtime logs [args...] Show host agent-runtime logs
|
|
99
|
+
|
|
95
100
|
wiki <workspace> init Initialize the workspace with wiki init
|
|
96
101
|
wiki <workspace> up Start llm-wiki serve + mcp-http + production-mcp
|
|
97
102
|
wiki <workspace> down Stop all services for this workspace
|
|
@@ -106,6 +111,7 @@ Commands:
|
|
|
106
111
|
Configuration:
|
|
107
112
|
workspaces/<workspace>/.env
|
|
108
113
|
Override directory: WIKI_WORKSPACES_DIR=/path/to/dir
|
|
114
|
+
Runtime node: WIKI_MANAGER_NODE_BIN=/path/to/node
|
|
109
115
|
Local CA: --cacert /absolute/path/to/ca.pem (Docker must be able to read this host path)
|
|
110
116
|
EOF
|
|
111
117
|
}
|
|
@@ -362,6 +368,179 @@ NODE
|
|
|
362
368
|
esac
|
|
363
369
|
}
|
|
364
370
|
|
|
371
|
+
runtime_node_bin() {
|
|
372
|
+
printf '%s\n' "${WIKI_MANAGER_NODE_BIN:-node}"
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
ensure_runtime_node() {
|
|
376
|
+
local node_bin
|
|
377
|
+
node_bin="$(runtime_node_bin)"
|
|
378
|
+
command -v "$node_bin" >/dev/null 2>&1 || die "runtime requires Node.js 22+: command not found: $node_bin (set WIKI_MANAGER_NODE_BIN)"
|
|
379
|
+
local version major
|
|
380
|
+
version="$("$node_bin" -p 'process.versions.node' 2>/dev/null)" || die "could not execute Node runtime: $node_bin"
|
|
381
|
+
major="${version%%.*}"
|
|
382
|
+
[[ "$major" =~ ^[0-9]+$ && "$major" -ge 22 ]] || die "runtime requires Node.js 22+ for node:sqlite; $node_bin is Node $version"
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
ensure_manager_runtime_token() {
|
|
386
|
+
local token
|
|
387
|
+
token="$(env_value "$MANAGER_ENV_FILE" WIKI_MANAGER_RUNTIME_TOKEN "")"
|
|
388
|
+
if [[ -z "$token" ]]; then
|
|
389
|
+
token="$(generate_token)"
|
|
390
|
+
mkdir -p "$(dirname "$MANAGER_ENV_FILE")"
|
|
391
|
+
set_env_value "$MANAGER_ENV_FILE" WIKI_MANAGER_RUNTIME_TOKEN "$token"
|
|
392
|
+
fi
|
|
393
|
+
printf '%s\n' "$token"
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
runtime_pid_file() {
|
|
397
|
+
printf '%s/runtime.pid\n' "$MANAGER_RUNTIME_DIR"
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
runtime_log_file() {
|
|
401
|
+
printf '%s/runtime.log\n' "$MANAGER_RUNTIME_DIR"
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
runtime_pid_running() {
|
|
405
|
+
local pid_file pid
|
|
406
|
+
pid_file="$(runtime_pid_file)"
|
|
407
|
+
[[ -f "$pid_file" ]] || return 1
|
|
408
|
+
pid="$(cat "$pid_file" 2>/dev/null || true)"
|
|
409
|
+
[[ "$pid" =~ ^[0-9]+$ ]] || return 1
|
|
410
|
+
kill -0 "$pid" >/dev/null 2>&1
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
runtime_pid_command() {
|
|
414
|
+
local pid="$1"
|
|
415
|
+
ps -p "$pid" -o command= 2>/dev/null || ps -p "$pid" -o args= 2>/dev/null || true
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
runtime_pid_matches() {
|
|
419
|
+
local pid command
|
|
420
|
+
pid="$(cat "$(runtime_pid_file)" 2>/dev/null || true)"
|
|
421
|
+
[[ "$pid" =~ ^[0-9]+$ ]] || return 1
|
|
422
|
+
command="$(runtime_pid_command "$pid")"
|
|
423
|
+
[[ "$command" == *"/bin/wiki-manager.js runtime"* || "$command" == *" bin/wiki-manager.js runtime"* ]]
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
runtime_health_url() {
|
|
427
|
+
printf 'http://127.0.0.1:%s/health\n' "${WIKI_MANAGER_RUNTIME_PORT:-7788}"
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
runtime_health_check() {
|
|
431
|
+
local token url
|
|
432
|
+
token="$(env_value "$MANAGER_ENV_FILE" WIKI_MANAGER_RUNTIME_TOKEN "")"
|
|
433
|
+
url="$(runtime_health_url)"
|
|
434
|
+
if command -v curl >/dev/null 2>&1; then
|
|
435
|
+
if [[ -n "$token" ]]; then
|
|
436
|
+
curl -fsS -H "Authorization: Bearer $token" "$url" >/dev/null 2>&1
|
|
437
|
+
else
|
|
438
|
+
curl -fsS "$url" >/dev/null 2>&1
|
|
439
|
+
fi
|
|
440
|
+
return
|
|
441
|
+
fi
|
|
442
|
+
local node_bin
|
|
443
|
+
node_bin="$(runtime_node_bin)"
|
|
444
|
+
RUNTIME_URL="$url" RUNTIME_TOKEN="$token" "$node_bin" --input-type=module -e "const h=process.env.RUNTIME_TOKEN?{Authorization:'Bearer '+process.env.RUNTIME_TOKEN}:{}; const r=await fetch(process.env.RUNTIME_URL,{headers:h}); process.exit(r.ok?0:1);"
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
runtime_command() {
|
|
448
|
+
local subcommand="$1"
|
|
449
|
+
shift
|
|
450
|
+
local host="${WIKI_MANAGER_RUNTIME_HOST:-0.0.0.0}"
|
|
451
|
+
local port="${WIKI_MANAGER_RUNTIME_PORT:-7788}"
|
|
452
|
+
local pid_file log_file node_bin token
|
|
453
|
+
pid_file="$(runtime_pid_file)"
|
|
454
|
+
log_file="$(runtime_log_file)"
|
|
455
|
+
node_bin="$(runtime_node_bin)"
|
|
456
|
+
|
|
457
|
+
case "$subcommand" in
|
|
458
|
+
up)
|
|
459
|
+
[[ $# -eq 0 ]] || die "runtime up does not take arguments"
|
|
460
|
+
mkdir -p "$MANAGER_RUNTIME_DIR"
|
|
461
|
+
ensure_runtime_node
|
|
462
|
+
token="$(ensure_manager_runtime_token)"
|
|
463
|
+
export WIKI_MANAGER_RUNTIME_TOKEN="$token"
|
|
464
|
+
if runtime_health_check; then
|
|
465
|
+
printf 'agent-runtime already healthy at %s\n' "$(runtime_health_url)"
|
|
466
|
+
return
|
|
467
|
+
fi
|
|
468
|
+
if runtime_pid_running; then
|
|
469
|
+
printf 'agent-runtime process is already running (pid %s), but health is not ready yet.\n' "$(cat "$pid_file")"
|
|
470
|
+
return
|
|
471
|
+
fi
|
|
472
|
+
WIKI_WORKSPACES_DIR="$WORKSPACES_DIR" \
|
|
473
|
+
WIKI_MANAGER_ENV_FILE="$MANAGER_ENV_FILE" \
|
|
474
|
+
WIKI_MANAGER_STATE_DIR="$MANAGER_RUNTIME_DIR" \
|
|
475
|
+
WIKI_MANAGER_RUNTIME_TOKEN="$token" \
|
|
476
|
+
nohup "$node_bin" "$ROOT_DIR/bin/wiki-manager.js" runtime --host "$host" --port "$port" --state-dir "$MANAGER_RUNTIME_DIR" > "$log_file" 2>&1 &
|
|
477
|
+
printf '%s\n' "$!" > "$pid_file"
|
|
478
|
+
sleep 0.5
|
|
479
|
+
printf 'agent-runtime started on http://127.0.0.1:%s (pid %s)\n' "$port" "$(cat "$pid_file")"
|
|
480
|
+
printf 'state: %s\nlog: %s\n' "$MANAGER_RUNTIME_DIR" "$log_file"
|
|
481
|
+
;;
|
|
482
|
+
down|stop)
|
|
483
|
+
[[ $# -eq 0 ]] || die "runtime down does not take arguments"
|
|
484
|
+
if ! runtime_pid_running; then
|
|
485
|
+
printf 'agent-runtime is not running from %s\n' "$pid_file"
|
|
486
|
+
rm -f "$pid_file"
|
|
487
|
+
return
|
|
488
|
+
fi
|
|
489
|
+
if ! runtime_pid_matches; then
|
|
490
|
+
printf 'refusing to stop pid %s: command does not look like wiki-manager runtime\n' "$(cat "$pid_file")" >&2
|
|
491
|
+
printf 'command: %s\n' "$(runtime_pid_command "$(cat "$pid_file")")" >&2
|
|
492
|
+
rm -f "$pid_file"
|
|
493
|
+
exit 1
|
|
494
|
+
fi
|
|
495
|
+
kill "$(cat "$pid_file")"
|
|
496
|
+
rm -f "$pid_file"
|
|
497
|
+
printf 'agent-runtime stopped\n'
|
|
498
|
+
;;
|
|
499
|
+
status)
|
|
500
|
+
[[ $# -eq 0 ]] || die "runtime status does not take arguments"
|
|
501
|
+
if runtime_health_check; then
|
|
502
|
+
printf 'agent-runtime healthy at %s\n' "$(runtime_health_url)"
|
|
503
|
+
elif runtime_pid_running; then
|
|
504
|
+
printf 'agent-runtime process running (pid %s), health check failed\n' "$(cat "$pid_file")"
|
|
505
|
+
exit 1
|
|
506
|
+
else
|
|
507
|
+
printf 'agent-runtime is not running\n'
|
|
508
|
+
exit 1
|
|
509
|
+
fi
|
|
510
|
+
;;
|
|
511
|
+
logs)
|
|
512
|
+
if [[ ! -f "$log_file" ]]; then
|
|
513
|
+
printf 'No runtime log found at %s\n' "$log_file" >&2
|
|
514
|
+
exit 1
|
|
515
|
+
fi
|
|
516
|
+
if [[ $# -eq 0 ]]; then
|
|
517
|
+
tail -100 -f "$log_file"
|
|
518
|
+
else
|
|
519
|
+
tail "$@" "$log_file"
|
|
520
|
+
fi
|
|
521
|
+
;;
|
|
522
|
+
*)
|
|
523
|
+
die "unknown runtime command: $subcommand (expected: up, down, status, logs)"
|
|
524
|
+
;;
|
|
525
|
+
esac
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
ensure_runtime_up() {
|
|
529
|
+
if [[ "${WIKI_MANAGER_RUNTIME_AUTOSTART:-1}" == "0" ]]; then
|
|
530
|
+
return
|
|
531
|
+
fi
|
|
532
|
+
if runtime_health_check; then
|
|
533
|
+
return
|
|
534
|
+
fi
|
|
535
|
+
printf 'Starting host agent-runtime...\n'
|
|
536
|
+
runtime_command up
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
start_workspace_services() {
|
|
540
|
+
ensure_runtime_up
|
|
541
|
+
compose_for_workspace "$1" up -d serve mcp-http production-mcp
|
|
542
|
+
}
|
|
543
|
+
|
|
365
544
|
ensure_manager_endpoints_file() {
|
|
366
545
|
if [[ ! -f "$MANAGER_ENDPOINTS_FILE" && -f "$ROOT_DIR/mcp.endpoints.example.json" ]]; then
|
|
367
546
|
mkdir -p "$(dirname "$MANAGER_ENDPOINTS_FILE")"
|
|
@@ -743,8 +922,7 @@ up_workspace() {
|
|
|
743
922
|
local ws_path
|
|
744
923
|
ws_path="$(normalize_path "$(workspace_value "$workspace" WIKI_WORKSPACE_PATH)")"
|
|
745
924
|
ensure_workspace_dirs "$ws_path"
|
|
746
|
-
|
|
747
|
-
compose_for_workspace "$workspace" up -d serve mcp-http production-mcp
|
|
925
|
+
start_workspace_services "$workspace"
|
|
748
926
|
|
|
749
927
|
local serve_port prod_port
|
|
750
928
|
serve_port="$(workspace_value "$workspace" WIKI_SERVE_PORT 3100)"
|
|
@@ -752,6 +930,7 @@ up_workspace() {
|
|
|
752
930
|
printf 'Workspace UI: http://localhost:%s\n' "$serve_port"
|
|
753
931
|
printf 'Chat: http://localhost:%s/chat\n' "$serve_port"
|
|
754
932
|
printf 'Production: http://localhost:%s/mcp/\n' "$prod_port"
|
|
933
|
+
printf 'Runtime: %s\n' "$(runtime_health_check && printf 'healthy at %s' "$(runtime_health_url)" || printf 'start with: wiki-workspace runtime up')"
|
|
755
934
|
printf 'External MCPs: see %s\n' "$MANAGER_ENDPOINTS_FILE"
|
|
756
935
|
|
|
757
936
|
if [[ "$open_browser" == "1" ]]; then
|
|
@@ -802,10 +981,22 @@ main() {
|
|
|
802
981
|
exit 0
|
|
803
982
|
fi
|
|
804
983
|
|
|
984
|
+
# runtime <subcommand> [args...]
|
|
985
|
+
if [[ $# -ge 1 && "$1" == "runtime" ]]; then
|
|
986
|
+
local runtime_sub="${2:-status}"
|
|
987
|
+
if [[ $# -ge 2 ]]; then
|
|
988
|
+
shift 2
|
|
989
|
+
else
|
|
990
|
+
shift 1
|
|
991
|
+
fi
|
|
992
|
+
runtime_command "$runtime_sub" "$@"
|
|
993
|
+
exit 0
|
|
994
|
+
fi
|
|
995
|
+
|
|
805
996
|
[[ $# -ge 2 ]] || { usage; exit 2; }
|
|
806
997
|
|
|
807
998
|
local scope="$1"
|
|
808
|
-
[[ "$scope" == "wiki" ]] || die "unknown scope: $scope (expected: wiki, agents, up, config, or list)"
|
|
999
|
+
[[ "$scope" == "wiki" ]] || die "unknown scope: $scope (expected: wiki, agents, runtime, up, config, or list)"
|
|
809
1000
|
shift
|
|
810
1001
|
[[ $# -ge 2 ]] || die "wiki requires a workspace and a command"
|
|
811
1002
|
|
|
@@ -818,13 +1009,14 @@ main() {
|
|
|
818
1009
|
run_wiki "$workspace" init "$@"
|
|
819
1010
|
;;
|
|
820
1011
|
up)
|
|
821
|
-
|
|
1012
|
+
start_workspace_services "$workspace"
|
|
822
1013
|
local serve_port production_port
|
|
823
1014
|
serve_port="$(workspace_value "$workspace" WIKI_SERVE_PORT 3100)"
|
|
824
1015
|
production_port="$(workspace_value "$workspace" PRODUCTION_MCP_PORT 3102)"
|
|
825
1016
|
printf 'Workspace UI: http://localhost:%s\n' "$serve_port"
|
|
826
1017
|
printf 'Chat MCP: http://localhost:%s/chat\n' "$serve_port"
|
|
827
1018
|
printf 'Production: http://localhost:%s/mcp/\n' "$production_port"
|
|
1019
|
+
printf 'Runtime: %s\n' "$(runtime_health_check && printf 'healthy at %s' "$(runtime_health_url)" || printf 'start with: wiki-workspace runtime up')"
|
|
828
1020
|
;;
|
|
829
1021
|
down)
|
|
830
1022
|
compose_for_workspace "$workspace" down
|
|
@@ -842,6 +1034,7 @@ main() {
|
|
|
842
1034
|
die "serve accepts only --open as optional flag; port is configured in the workspace .env"
|
|
843
1035
|
fi
|
|
844
1036
|
|
|
1037
|
+
ensure_runtime_up
|
|
845
1038
|
printf 'Starting mcp-http...\n'
|
|
846
1039
|
compose_for_workspace "$workspace" up -d mcp-http
|
|
847
1040
|
printf 'Starting production-mcp...\n'
|
|
@@ -852,6 +1045,7 @@ main() {
|
|
|
852
1045
|
printf 'Workspace UI: http://localhost:%s\n' "$serve_port"
|
|
853
1046
|
printf 'Chat MCP: http://localhost:%s/chat\n' "$serve_port"
|
|
854
1047
|
printf 'Production: http://localhost:%s/mcp/\n' "$production_port"
|
|
1048
|
+
printf 'Runtime: %s\n' "$(runtime_health_check && printf 'healthy at %s' "$(runtime_health_url)" || printf 'start with: wiki-workspace runtime up')"
|
|
855
1049
|
printf 'Note: compose logs may show http://localhost:3000, which is the container port.\n'
|
|
856
1050
|
if [[ $open_browser -eq 1 ]]; then
|
|
857
1051
|
wait_and_open "http://localhost:${serve_port}" &
|