@dotdrelle/wiki-manager 0.14.20 → 0.15.25

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/wiki-workspace CHANGED
@@ -222,17 +222,20 @@ agents_compose() {
222
222
 
223
223
  _agents_dc() {
224
224
  local cacert_args=()
225
+ local profile_args=()
226
+ connectors_enabled && profile_args+=(--profile connectors)
225
227
  WORKSPACES_ROOT="$workspaces_root" AGENTS_DATA_DIR="$agents_data_dir" \
226
228
  read_lines_into_array cacert_args cacert_compose_args "$agents_compose_file" "agents.cacert.compose.yml"
227
- # User-owned override: optional external agents (e.g. mailer) live in a
229
+ # User-owned override: optional external agents live in a
228
230
  # file the user maintains NEXT TO the .env — never generated, never
229
231
  # overwritten by package updates.
230
232
  local override_args=()
231
233
  local user_override="$MANAGER_STATE_DIR/agents.docker-compose.override.yml"
232
234
  [[ -f "$user_override" ]] && override_args+=(-f "$user_override")
233
235
  WORKSPACES_ROOT="$workspaces_root" AGENTS_DATA_DIR="$agents_data_dir" \
236
+ COMPOSE_PROFILES= \
234
237
  docker compose --project-directory "$DEFAULT_MANAGER_DIR" \
235
- ${compose_env_args[@]+"${compose_env_args[@]}"} -f "$agents_compose_file" ${override_args[@]+"${override_args[@]}"} ${cacert_args[@]+"${cacert_args[@]}"} -p wiki-agents "$@"
238
+ ${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 "$@"
236
239
  }
237
240
 
238
241
  case "$subcommand" in
@@ -250,6 +253,7 @@ agents_compose() {
250
253
  compose_env_args=()
251
254
  [[ -f "$MANAGER_ENV_FILE" ]] && compose_env_args+=(--env-file "$MANAGER_ENV_FILE")
252
255
  mkdir -p "$agents_data_dir/cme" "$agents_data_dir/documents/input" "$agents_data_dir/documents/output" "$agents_data_dir/documents/uploads"
256
+ connectors_enabled && mkdir -p "$agents_data_dir/connectors"
253
257
  mkdir -p "$workspaces_root"
254
258
  $do_pull && _agents_dc pull
255
259
  local up_args=(up -d)
@@ -260,8 +264,10 @@ agents_compose() {
260
264
  printf 'Workspaces root: %s\n' "$workspaces_root"
261
265
  printf 'Agents data: %s\n' "$agents_data_dir"
262
266
  [[ -z "$CACERT_PATH" ]] || printf 'CA cert: %s -> /wiki-manager-ca.pem\n' "$CACERT_PATH"
263
- printf 'Agents: cme=:%s documents=:%s\n' \
267
+ printf 'Agents: cme=:%s documents=:%s' \
264
268
  "${CME_MCP_PORT:-3336}" "${DOCUMENTS_MCP_PORT:-3337}"
269
+ connectors_enabled && printf ' connectors=:%s' "${CONNECTORS_MCP_PORT:-3338}"
270
+ printf '\n'
265
271
  [[ ! -f "$MANAGER_STATE_DIR/agents.docker-compose.override.yml" ]] || printf 'User override: agents.docker-compose.override.yml included\n'
266
272
  ;;
267
273
  down)
@@ -409,7 +415,7 @@ ensure_runtime_node() {
409
415
  }
410
416
 
411
417
  ensure_agent_tokens() {
412
- # The external agents (cme, documents) authenticate with tokens
418
+ # External agents authenticate with tokens
413
419
  # from the manager .env — generate any missing one, exactly like the
414
420
  # workspace and runtime tokens are generated. Leaving them empty made a
415
421
  # fresh install start agents nobody could talk to.
@@ -423,6 +429,34 @@ ensure_agent_tokens() {
423
429
  printf 'Generated %s in %s\n' "$key" "$MANAGER_ENV_FILE"
424
430
  fi
425
431
  done
432
+ if connectors_enabled; then
433
+ for key in CONNECTORS_MCP_AUTH_TOKEN OAUTH_STATE_SECRET OAUTH_START_TOKEN; do
434
+ token="$(env_value "$MANAGER_ENV_FILE" "$key" "")"
435
+ if [[ -z "$token" ]]; then
436
+ token="$(generate_token)"
437
+ mkdir -p "$(dirname "$MANAGER_ENV_FILE")"
438
+ set_env_value "$MANAGER_ENV_FILE" "$key" "$token"
439
+ printf 'Generated %s in %s\n' "$key" "$MANAGER_ENV_FILE"
440
+ fi
441
+ done
442
+ local callback_url connectors_port
443
+ callback_url="$(env_value "$MANAGER_ENV_FILE" GOOGLE_OAUTH_CALLBACK_URL "")"
444
+ if [[ -z "$callback_url" ]]; then
445
+ connectors_port="$(env_value "$MANAGER_ENV_FILE" CONNECTORS_MCP_PORT "${CONNECTORS_MCP_PORT:-3338}")"
446
+ callback_url="http://127.0.0.1:${connectors_port}/oauth/google/callback"
447
+ set_env_value "$MANAGER_ENV_FILE" GOOGLE_OAUTH_CALLBACK_URL "$callback_url"
448
+ printf 'Configured local GOOGLE_OAUTH_CALLBACK_URL in %s\n' "$MANAGER_ENV_FILE"
449
+ fi
450
+ fi
451
+ }
452
+
453
+ connectors_enabled() {
454
+ local enabled
455
+ enabled="$(env_value "$MANAGER_ENV_FILE" CONNECTORS_ENABLED "${CONNECTORS_ENABLED:-false}")"
456
+ case "$enabled" in
457
+ 1|[Tt][Rr][Uu][Ee]|[Yy][Ee][Ss]|[Oo][Nn]) return 0 ;;
458
+ *) return 1 ;;
459
+ esac
426
460
  }
427
461
 
428
462
  ensure_endpoints_file() {
@@ -433,6 +467,44 @@ ensure_endpoints_file() {
433
467
  cp "$ROOT_DIR/mcp.endpoints.example.json" "$MANAGER_ENDPOINTS_FILE"
434
468
  printf 'Created %s from packaged example\n' "$MANAGER_ENDPOINTS_FILE"
435
469
  fi
470
+ [[ -f "$MANAGER_ENDPOINTS_FILE" ]] || return
471
+ local connector_state=false
472
+ connectors_enabled && connector_state=true
473
+ node - "$MANAGER_ENDPOINTS_FILE" "$connector_state" <<'NODE'
474
+ import fs from 'node:fs';
475
+
476
+ const [, , filePath, enabled] = process.argv;
477
+ const config = JSON.parse(fs.readFileSync(filePath, 'utf8'));
478
+ config.mcpServers ??= {};
479
+ config.chatAccess ??= { maxToolIterations: 8, servers: {} };
480
+ config.chatAccess.servers ??= {};
481
+ if (enabled === 'true') {
482
+ config.mcpServers.connectors ??= {
483
+ url: 'http://host.docker.internal:${CONNECTORS_MCP_PORT:-3338}/mcp/',
484
+ headers: {
485
+ Authorization: 'Bearer ${CONNECTORS_MCP_AUTH_TOKEN}',
486
+ },
487
+ };
488
+ config.chatAccess.servers.connectors ??= {};
489
+ const connectorAccess = config.chatAccess.servers.connectors;
490
+ // One shape for every server: a single `allow` list. The legacy
491
+ // `allowActions` split is folded back in and removed, so a file written by
492
+ // an older manager converges to the common shape on the next `agents up`.
493
+ connectorAccess.allow = [
494
+ ...new Set([
495
+ ...(Array.isArray(connectorAccess.allow) ? connectorAccess.allow : []),
496
+ ...(Array.isArray(connectorAccess.allowActions) ? connectorAccess.allowActions : []),
497
+ 'connectors_google_status',
498
+ 'connectors_google_oauth_start',
499
+ ]),
500
+ ];
501
+ delete connectorAccess.allowActions;
502
+ } else {
503
+ delete config.mcpServers.connectors;
504
+ delete config.chatAccess.servers.connectors;
505
+ }
506
+ fs.writeFileSync(filePath, `${JSON.stringify(config, null, 2)}\n`);
507
+ NODE
436
508
  }
437
509
 
438
510
  ensure_manager_runtime_token() {
@@ -476,8 +548,12 @@ runtime_pid_matches() {
476
548
  [[ "$command" == *"/bin/wiki-manager.js runtime"* || "$command" == *" bin/wiki-manager.js runtime"* ]]
477
549
  }
478
550
 
551
+ runtime_port() {
552
+ env_value "$MANAGER_ENV_FILE" WIKI_MANAGER_RUNTIME_PORT "${WIKI_MANAGER_RUNTIME_PORT:-7788}"
553
+ }
554
+
479
555
  runtime_health_url() {
480
- printf 'http://127.0.0.1:%s/health\n' "${WIKI_MANAGER_RUNTIME_PORT:-7788}"
556
+ printf 'http://127.0.0.1:%s/health\n' "$(runtime_port)"
481
557
  }
482
558
 
483
559
  runtime_health_check() {
@@ -497,11 +573,24 @@ runtime_health_check() {
497
573
  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);"
498
574
  }
499
575
 
576
+ wait_for_runtime_health() {
577
+ local attempts="${1:-60}"
578
+ local i=0
579
+ while (( i < attempts )); do
580
+ runtime_health_check && return 0
581
+ runtime_pid_running || return 1
582
+ sleep 0.25
583
+ (( i++ )) || true
584
+ done
585
+ return 1
586
+ }
587
+
500
588
  runtime_command() {
501
589
  local subcommand="$1"
502
590
  shift
503
591
  local host="${WIKI_MANAGER_RUNTIME_HOST:-0.0.0.0}"
504
- local port="${WIKI_MANAGER_RUNTIME_PORT:-7788}"
592
+ local port
593
+ port="$(runtime_port)"
505
594
  local pid_file log_file node_bin token
506
595
  pid_file="$(runtime_pid_file)"
507
596
  log_file="$(runtime_log_file)"
@@ -519,17 +608,21 @@ runtime_command() {
519
608
  return
520
609
  fi
521
610
  if runtime_pid_running; then
522
- printf 'agent-runtime process is already running (pid %s), but health is not ready yet.\n' "$(cat "$pid_file")"
523
- return
611
+ printf 'Waiting for agent-runtime process (pid %s)...\n' "$(cat "$pid_file")"
612
+ else
613
+ WIKI_WORKSPACES_DIR="$WORKSPACES_DIR" \
614
+ WIKI_MANAGER_ENV_FILE="$MANAGER_ENV_FILE" \
615
+ WIKI_MANAGER_STATE_DIR="$MANAGER_RUNTIME_DIR" \
616
+ WIKI_MANAGER_RUNTIME_TOKEN="$token" \
617
+ nohup "$node_bin" "$ROOT_DIR/bin/wiki-manager.js" runtime --host "$host" --port "$port" --state-dir "$MANAGER_RUNTIME_DIR" > "$log_file" 2>&1 &
618
+ printf '%s\n' "$!" > "$pid_file"
619
+ fi
620
+ if ! wait_for_runtime_health; then
621
+ printf 'agent-runtime failed to become healthy at %s\n' "$(runtime_health_url)" >&2
622
+ [[ ! -f "$log_file" ]] || tail -20 "$log_file" >&2
623
+ return 1
524
624
  fi
525
- WIKI_WORKSPACES_DIR="$WORKSPACES_DIR" \
526
- WIKI_MANAGER_ENV_FILE="$MANAGER_ENV_FILE" \
527
- WIKI_MANAGER_STATE_DIR="$MANAGER_RUNTIME_DIR" \
528
- WIKI_MANAGER_RUNTIME_TOKEN="$token" \
529
- nohup "$node_bin" "$ROOT_DIR/bin/wiki-manager.js" runtime --host "$host" --port "$port" --state-dir "$MANAGER_RUNTIME_DIR" > "$log_file" 2>&1 &
530
- printf '%s\n' "$!" > "$pid_file"
531
- sleep 0.5
532
- printf 'agent-runtime started on http://127.0.0.1:%s (pid %s)\n' "$port" "$(cat "$pid_file")"
625
+ printf 'agent-runtime healthy on http://127.0.0.1:%s (pid %s)\n' "$port" "$(cat "$pid_file")"
533
626
  printf 'state: %s\nlog: %s\n' "$MANAGER_RUNTIME_DIR" "$log_file"
534
627
  ;;
535
628
  down|stop)
@@ -819,8 +912,7 @@ cacert_compose_args() {
819
912
  done <<< "$services"
820
913
  } > "$tmp_override"
821
914
  # Always replace generated state: package updates may add/remove services,
822
- # and retaining an older override creates invalid phantom services (for
823
- # example a removed optional mailer with no image in the current base file).
915
+ # and retaining an older override creates invalid phantom services.
824
916
  mv "$tmp_override" "$override_path"
825
917
  printf '%s\n' -f "$override_path"
826
918
  }
@@ -1,36 +0,0 @@
1
- # agents.docker-compose.mailer.example.yml — optional MailerSend agent
2
- #
3
- # The mailer agent is NOT part of the default delivery: it is an external
4
- # MCP connector operated at the user's charge. To enable it:
5
- #
6
- # 1. Copy this file NEXT TO YOUR .env (the directory where you run
7
- # wiki-manager) under the name: agents.docker-compose.override.yml
8
- # That file is yours — wiki-manager never generates or overwrites it,
9
- # and `wiki-workspace agents up` includes it automatically when present.
10
- # 2. Add to your .env:
11
- # MAILER_MCP_AUTH_TOKEN=$(openssl rand -hex 32)
12
- # MAILERSEND_API_KEY=...
13
- # MAILERSEND_FROM_EMAIL=...
14
- # 3. Declare the endpoint in your mcp.endpoints.json:
15
- # "mailer": {
16
- # "url": "http://host.docker.internal:${MAILER_MCP_PORT:-3335}/mcp/",
17
- # "headers": { "Authorization": "Bearer ${MAILER_MCP_AUTH_TOKEN}" }
18
- # }
19
- #
20
- services:
21
- mailer:
22
- image: dotdrelle/agent-mailer-api:latest
23
- user: "${UID:-1000}:${GID:-1000}"
24
- ports:
25
- - "${MAILER_MCP_PORT:-3335}:8080"
26
- environment:
27
- - MAILERSEND_API_KEY=${MAILERSEND_API_KEY:-}
28
- - MAILERSEND_FROM_EMAIL=${MAILERSEND_FROM_EMAIL:-no-reply@example.com}
29
- - MAILERSEND_FROM_NAME=${MAILERSEND_FROM_NAME:-Mailer Agent}
30
- - MAILERSEND_USER_AGENT=${MAILERSEND_USER_AGENT:-curl/8.7.1}
31
- - MAILERSEND_VERIFY_SSL=${MAILERSEND_VERIFY_SSL:-true}
32
- - MAILERSEND_CA_CERT=${MAILERSEND_CA_CERT:-}
33
- - MAILER_REQUIRE_CONFIRMATION=${MAILER_REQUIRE_CONFIRMATION:-true}
34
- - MAILER_DRY_RUN=${MAILER_DRY_RUN:-false}
35
- - MCP_AUTH_TOKEN=${MAILER_MCP_AUTH_TOKEN:-}
36
- restart: unless-stopped