@dotdrelle/wiki-manager 0.15.34 → 0.15.38
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 +8 -5
- package/README.md +42 -0
- package/agents.docker-compose.yml +11 -16
- package/docker-compose.yml +9 -8
- package/package.json +2 -2
- package/src/agent/graph.js +20 -0
- package/src/cli/wiki-manager.js +20 -0
- package/src/commands/slash.js +85 -13
- package/src/commands/slash.test.js +85 -3
- package/src/core/agentsCompose.js +86 -1
- package/src/core/buildInfo.json +2 -2
- package/src/core/compose.js +24 -2
- package/src/core/dockerCompose.test.js +18 -0
- package/src/core/env.js +2 -1
- package/src/core/env.test.js +14 -0
- package/src/core/googleGrants.js +38 -0
- package/src/core/googleGrants.test.js +59 -0
- package/src/core/mcp.js +1 -1
- package/src/core/mcp.test.js +1 -0
- package/src/core/mcpEndpoints.js +96 -0
- package/src/core/mcpEndpoints.test.js +126 -0
- package/src/core/modelFetch.js +241 -27
- package/src/core/modelFetch.test.js +213 -0
- package/src/core/profileServiceStatus.test.js +146 -0
- package/src/core/wikiSetup.js +11 -2
- package/src/core/wikiWorkspace.test.js +16 -3
- package/src/orchestrator/agentRegistry.js +13 -1
- package/src/orchestrator/agentRegistry.test.js +20 -0
- package/src/runtime/lifecycle.js +105 -3
- package/src/runtime/lifecycle.test.js +68 -0
- package/src/runtime/server.js +28 -0
- package/src/shell/LeftPane.tsx +55 -41
- package/src/shell/SetupWizard.tsx +416 -116
- package/src/shell/repl.js +61 -12
- package/src/shell/repl.test.js +48 -19
- package/src/shell/setupWizardDiscovery.test.js +48 -0
- package/src/shell/setupWizardPlaceholders.test.js +15 -2
- package/src/shell/setupWizardSuggestions.test.js +36 -2
- package/src/shell/wrapText.js +57 -0
- package/src/shell/wrapText.test.js +48 -0
- package/wiki-workspace +122 -32
package/wiki-workspace
CHANGED
|
@@ -262,30 +262,10 @@ agents_compose() {
|
|
|
262
262
|
local compose_env_args=()
|
|
263
263
|
[[ -f "$MANAGER_ENV_FILE" ]] && compose_env_args+=(--env-file "$MANAGER_ENV_FILE")
|
|
264
264
|
|
|
265
|
-
#
|
|
266
|
-
#
|
|
267
|
-
#
|
|
268
|
-
#
|
|
269
|
-
# --env-file, so the variables must be exported here or the image ships with
|
|
270
|
-
# empty WIKILLM_GOOGLE_OAUTH_* and every Google connector stays unusable.
|
|
271
|
-
local connectors_build_env="$ROOT_DIR/../agent-external/agent-connectors/.env.build.local"
|
|
272
|
-
if [[ -f "$connectors_build_env" ]]; then
|
|
273
|
-
local build_key build_value
|
|
274
|
-
while IFS='=' read -r build_key build_value; do
|
|
275
|
-
case "$build_key" in
|
|
276
|
-
WIKILLM_GOOGLE_OAUTH_CLIENT_ID|WIKILLM_GOOGLE_OAUTH_CLIENT_SECRET) ;;
|
|
277
|
-
*) continue ;;
|
|
278
|
-
esac
|
|
279
|
-
[[ -n "${!build_key:-}" ]] || export "$build_key=$build_value"
|
|
280
|
-
done < <(grep -v '^[[:space:]]*#' "$connectors_build_env" || true)
|
|
281
|
-
fi
|
|
282
|
-
|
|
283
|
-
require_connectors_build_credentials() {
|
|
284
|
-
local build_key
|
|
285
|
-
for build_key in WIKILLM_GOOGLE_OAUTH_CLIENT_ID WIKILLM_GOOGLE_OAUTH_CLIENT_SECRET; do
|
|
286
|
-
[[ -n "${!build_key:-}" ]] || die "cannot build connectors: $build_key is missing from $connectors_build_env"
|
|
287
|
-
done
|
|
288
|
-
}
|
|
265
|
+
# Ce script ne construit aucune image. L'application OAuth Google est cuite
|
|
266
|
+
# dans l'image publiée par build-and-push.sh ; pour en utiliser une autre,
|
|
267
|
+
# l'opérateur pose GOOGLE_OAUTH_CLIENT_ID / _SECRET dans le .env du manager,
|
|
268
|
+
# que Compose transmet au conteneur et qui l'emporte sur la valeur embarquée.
|
|
289
269
|
|
|
290
270
|
_agents_dc() {
|
|
291
271
|
local cacert_args=()
|
|
@@ -312,12 +292,11 @@ agents_compose() {
|
|
|
312
292
|
do_pull=true
|
|
313
293
|
shift
|
|
314
294
|
fi
|
|
315
|
-
|
|
295
|
+
# Services nommés : démarrer `connectors` seul une fois le profil actif,
|
|
296
|
+
# sans relancer toute la pile. Sans argument, tout monte comme avant.
|
|
297
|
+
local only_services=("$@")
|
|
316
298
|
ensure_agent_tokens
|
|
317
299
|
ensure_endpoints_file
|
|
318
|
-
if connectors_enabled && [[ -f "$ROOT_DIR/../agent-external/agent-connectors/Dockerfile" ]]; then
|
|
319
|
-
require_connectors_build_credentials
|
|
320
|
-
fi
|
|
321
300
|
# The .env may have just been created above — recompute the env-file
|
|
322
301
|
# flag so freshly generated tokens reach the containers on first run.
|
|
323
302
|
compose_env_args=()
|
|
@@ -330,6 +309,7 @@ agents_compose() {
|
|
|
330
309
|
if [[ -n "$CACERT_PATH" ]]; then
|
|
331
310
|
up_args+=(--force-recreate)
|
|
332
311
|
fi
|
|
312
|
+
up_args+=(${only_services[@]+"${only_services[@]}"})
|
|
333
313
|
_agents_dc "${up_args[@]}"
|
|
334
314
|
printf 'Workspaces root: %s\n' "$workspaces_root"
|
|
335
315
|
printf 'Agents data: %s\n' "$agents_data_dir"
|
|
@@ -341,8 +321,15 @@ agents_compose() {
|
|
|
341
321
|
[[ ! -f "$MANAGER_COMPOSE_DIR/agents.docker-compose.override.yml" ]] || printf 'User override: %s\n' "$MANAGER_COMPOSE_DIR/agents.docker-compose.override.yml"
|
|
342
322
|
;;
|
|
343
323
|
down)
|
|
344
|
-
|
|
345
|
-
|
|
324
|
+
# `down` sans argument démonte la pile ; avec des services nommés, Compose
|
|
325
|
+
# n'accepte que `stop` + `rm` — `down <service>` supprime le réseau commun
|
|
326
|
+
# et couperait les autres agents.
|
|
327
|
+
if [[ $# -eq 0 ]]; then
|
|
328
|
+
_agents_dc down
|
|
329
|
+
else
|
|
330
|
+
_agents_dc stop "$@"
|
|
331
|
+
_agents_dc rm -f "$@"
|
|
332
|
+
fi
|
|
346
333
|
;;
|
|
347
334
|
purge)
|
|
348
335
|
[[ $# -eq 0 ]] || die "agents purge does not take arguments"
|
|
@@ -547,7 +534,11 @@ ensure_endpoints_file() {
|
|
|
547
534
|
# Without mcp.endpoints.json the shell never connects to the agents it
|
|
548
535
|
# just started (and `agents status` refuses to run). Seed it from the
|
|
549
536
|
# packaged example; the \${VAR} placeholders resolve against the .env.
|
|
537
|
+
if [[ -e "$MANAGER_ENDPOINTS_FILE" && ! -f "$MANAGER_ENDPOINTS_FILE" ]]; then
|
|
538
|
+
die "MCP endpoints path is not a file: $MANAGER_ENDPOINTS_FILE"
|
|
539
|
+
fi
|
|
550
540
|
if [[ ! -f "$MANAGER_ENDPOINTS_FILE" && -f "$ROOT_DIR/mcp.endpoints.example.json" ]]; then
|
|
541
|
+
mkdir -p "$(dirname "$MANAGER_ENDPOINTS_FILE")"
|
|
551
542
|
cp "$ROOT_DIR/mcp.endpoints.example.json" "$MANAGER_ENDPOINTS_FILE"
|
|
552
543
|
printf 'Created %s from packaged example\n' "$MANAGER_ENDPOINTS_FILE"
|
|
553
544
|
fi
|
|
@@ -634,12 +625,65 @@ runtime_pid_command() {
|
|
|
634
625
|
ps -p "$pid" -o command= 2>/dev/null || ps -p "$pid" -o args= 2>/dev/null || true
|
|
635
626
|
}
|
|
636
627
|
|
|
628
|
+
runtime_command_looks_like_runtime() {
|
|
629
|
+
local command="$1"
|
|
630
|
+
[[ "$command" == *"/bin/wiki-manager.js runtime"* || "$command" == *" bin/wiki-manager.js runtime"* ]]
|
|
631
|
+
}
|
|
632
|
+
|
|
637
633
|
runtime_pid_matches() {
|
|
638
634
|
local pid command
|
|
639
635
|
pid="$(cat "$(runtime_pid_file)" 2>/dev/null || true)"
|
|
640
636
|
[[ "$pid" =~ ^[0-9]+$ ]] || return 1
|
|
641
637
|
command="$(runtime_pid_command "$pid")"
|
|
642
|
-
|
|
638
|
+
runtime_command_looks_like_runtime "$command"
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
# Pids qui écoutent sur le port du runtime, quel que soit leur parent.
|
|
642
|
+
#
|
|
643
|
+
# Un runtime démarré par une session de shell précédente survit à la mort de
|
|
644
|
+
# cette session : il ne répond plus à notre jeton (401, donc « injoignable »)
|
|
645
|
+
# et son fichier pid a disparu avec l'ancien répertoire d'état. Sans ce repli,
|
|
646
|
+
# `runtime down` répond « not running » pendant que le port reste occupé, et il
|
|
647
|
+
# ne reste que le `kill` manuel — inacceptable pour qui utilise l'application.
|
|
648
|
+
runtime_port_pids() {
|
|
649
|
+
local port="$1"
|
|
650
|
+
if command -v lsof >/dev/null 2>&1; then
|
|
651
|
+
lsof -nP -iTCP:"$port" -sTCP:LISTEN -t 2>/dev/null | sort -u
|
|
652
|
+
elif command -v ss >/dev/null 2>&1; then
|
|
653
|
+
ss -lptnH "sport = :${port}" 2>/dev/null |
|
|
654
|
+
grep -o 'pid=[0-9]*' | cut -d= -f2 | sort -u
|
|
655
|
+
fi
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
# Arrête les runtimes orphelins tenant le port. Ne tue QUE des processus dont
|
|
659
|
+
# la ligne de commande est celle d'un `wiki-manager runtime` : un port occupé
|
|
660
|
+
# par autre chose est signalé, jamais tué.
|
|
661
|
+
runtime_kill_orphans() {
|
|
662
|
+
local port="$1"
|
|
663
|
+
local pid command stopped=0 waited
|
|
664
|
+
while read -r pid; do
|
|
665
|
+
[[ "$pid" =~ ^[0-9]+$ ]] || continue
|
|
666
|
+
[[ "$pid" == "$$" ]] && continue
|
|
667
|
+
command="$(runtime_pid_command "$pid")"
|
|
668
|
+
if ! runtime_command_looks_like_runtime "$command"; then
|
|
669
|
+
printf 'port %s is held by pid %s, which is not a wiki-manager runtime — leaving it alone\n' "$port" "$pid" >&2
|
|
670
|
+
printf 'command: %s\n' "$command" >&2
|
|
671
|
+
continue
|
|
672
|
+
fi
|
|
673
|
+
printf 'Stopping orphan agent-runtime (pid %s)\n' "$pid"
|
|
674
|
+
kill "$pid" 2>/dev/null || true
|
|
675
|
+
waited=0
|
|
676
|
+
while kill -0 "$pid" 2>/dev/null && (( waited < 50 )); do
|
|
677
|
+
sleep 0.1
|
|
678
|
+
(( waited++ )) || true
|
|
679
|
+
done
|
|
680
|
+
if kill -0 "$pid" 2>/dev/null; then
|
|
681
|
+
printf 'pid %s did not stop, sending SIGKILL\n' "$pid" >&2
|
|
682
|
+
kill -9 "$pid" 2>/dev/null || true
|
|
683
|
+
fi
|
|
684
|
+
stopped=1
|
|
685
|
+
done < <(runtime_port_pids "$port")
|
|
686
|
+
(( stopped == 1 ))
|
|
643
687
|
}
|
|
644
688
|
|
|
645
689
|
runtime_port() {
|
|
@@ -704,6 +748,14 @@ runtime_command() {
|
|
|
704
748
|
if runtime_pid_running; then
|
|
705
749
|
printf 'Waiting for agent-runtime process (pid %s)...\n' "$(cat "$pid_file")"
|
|
706
750
|
else
|
|
751
|
+
# Le port peut être tenu par un runtime d'une session précédente, qui
|
|
752
|
+
# répond 401 à notre jeton : la sonde de santé le croit absent, et le
|
|
753
|
+
# démarrage se solderait par un EADDRINUSE incompréhensible. On le
|
|
754
|
+
# remplace, puisque `runtime up` veut précisément un runtime ici.
|
|
755
|
+
if [[ -n "$(runtime_port_pids "$port")" ]]; then
|
|
756
|
+
printf 'Port %s is already held by an unreachable agent-runtime.\n' "$port"
|
|
757
|
+
runtime_kill_orphans "$port" || true
|
|
758
|
+
fi
|
|
707
759
|
WIKI_WORKSPACES_DIR="$WORKSPACES_DIR" \
|
|
708
760
|
WIKI_MANAGER_ENV_FILE="$MANAGER_ENV_FILE" \
|
|
709
761
|
WIKI_MANAGER_STATE_DIR="$MANAGER_RUNTIME_DIR" \
|
|
@@ -730,12 +782,24 @@ runtime_command() {
|
|
|
730
782
|
sleep 0.1
|
|
731
783
|
(( wait_count++ )) || true
|
|
732
784
|
done
|
|
785
|
+
# Un arrêt propre refusé laissait le port occupé sans le dire.
|
|
786
|
+
if runtime_health_check; then
|
|
787
|
+
printf 'agent-runtime ignored the shutdown request; stopping the process\n' >&2
|
|
788
|
+
runtime_kill_orphans "$port" || true
|
|
789
|
+
fi
|
|
733
790
|
rm -f "$pid_file"
|
|
734
791
|
printf 'agent-runtime stopped\n'
|
|
735
792
|
return
|
|
736
793
|
fi
|
|
737
794
|
if ! runtime_pid_running; then
|
|
738
|
-
|
|
795
|
+
# Ni sain, ni référencé par un pid : reste le port. C'est le cas d'un
|
|
796
|
+
# orphelin, qu'on ne peut pas demander à l'utilisateur de tuer.
|
|
797
|
+
if runtime_kill_orphans "$port"; then
|
|
798
|
+
rm -f "$pid_file"
|
|
799
|
+
printf 'agent-runtime stopped\n'
|
|
800
|
+
return
|
|
801
|
+
fi
|
|
802
|
+
printf 'agent-runtime is not running (no healthy endpoint, no pid in %s, nothing listening on port %s)\n' "$pid_file" "$port"
|
|
739
803
|
rm -f "$pid_file"
|
|
740
804
|
return
|
|
741
805
|
fi
|
|
@@ -757,6 +821,16 @@ runtime_command() {
|
|
|
757
821
|
printf 'agent-runtime process running (pid %s), health check failed\n' "$(cat "$pid_file")"
|
|
758
822
|
exit 1
|
|
759
823
|
else
|
|
824
|
+
local orphan_pids
|
|
825
|
+
orphan_pids="$(runtime_port_pids "$port")"
|
|
826
|
+
if [[ -n "$orphan_pids" ]]; then
|
|
827
|
+
# Le symptôme perçu comme « ça ne démarre pas » : quelqu'un tient le
|
|
828
|
+
# port et répond 401 à notre jeton, donc les sondes le voient absent.
|
|
829
|
+
printf 'agent-runtime is not reachable with this token, but pid(s) %s hold port %s\n' \
|
|
830
|
+
"$(printf '%s' "$orphan_pids" | tr '\n' ' ')" "$port"
|
|
831
|
+
printf 'run `%s runtime down` to stop it\n' "$(basename "$0")"
|
|
832
|
+
exit 1
|
|
833
|
+
fi
|
|
760
834
|
printf 'agent-runtime is not running\n'
|
|
761
835
|
exit 1
|
|
762
836
|
fi
|
|
@@ -792,6 +866,19 @@ refresh_project() {
|
|
|
792
866
|
|
|
793
867
|
printf 'Removing external-agent stack and images...\n'
|
|
794
868
|
agents_compose purge
|
|
869
|
+
|
|
870
|
+
# `refresh` promet un état propre : le vérifier plutôt que l'affirmer. Un
|
|
871
|
+
# port encore tenu ici signifie qu'il l'est par un processus étranger, que
|
|
872
|
+
# `runtime down` refuse de tuer à raison — mais le taire ferait échouer le
|
|
873
|
+
# prochain démarrage sans que personne ne fasse le lien.
|
|
874
|
+
local leftover
|
|
875
|
+
leftover="$(runtime_port_pids "$(runtime_port)")"
|
|
876
|
+
if [[ -n "$leftover" ]]; then
|
|
877
|
+
printf 'Refresh incomplete: port %s is still held by pid(s) %s.\n' \
|
|
878
|
+
"$(runtime_port)" "$(printf '%s' "$leftover" | tr '\n' ' ')" >&2
|
|
879
|
+
printf 'It is not a wiki-manager runtime, so it was left running. Free the port, or set WIKI_MANAGER_RUNTIME_PORT to another one.\n' >&2
|
|
880
|
+
return 1
|
|
881
|
+
fi
|
|
795
882
|
printf 'Refresh complete. Persistent workspace and agent data were preserved.\n'
|
|
796
883
|
}
|
|
797
884
|
|
|
@@ -835,6 +922,9 @@ ensure_compose_override() {
|
|
|
835
922
|
}
|
|
836
923
|
|
|
837
924
|
ensure_manager_endpoints_file() {
|
|
925
|
+
if [[ -e "$MANAGER_ENDPOINTS_FILE" && ! -f "$MANAGER_ENDPOINTS_FILE" ]]; then
|
|
926
|
+
die "MCP endpoints path is not a file: $MANAGER_ENDPOINTS_FILE"
|
|
927
|
+
fi
|
|
838
928
|
if [[ ! -f "$MANAGER_ENDPOINTS_FILE" && -f "$ROOT_DIR/mcp.endpoints.example.json" ]]; then
|
|
839
929
|
mkdir -p "$(dirname "$MANAGER_ENDPOINTS_FILE")"
|
|
840
930
|
cp "$ROOT_DIR/mcp.endpoints.example.json" "$MANAGER_ENDPOINTS_FILE"
|