@dotdrelle/wiki-manager 0.15.25 → 0.15.27

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.
Files changed (38) hide show
  1. package/.env.example +18 -5
  2. package/README.md +35 -13
  3. package/agents.docker-compose.override.example.yml +82 -0
  4. package/agents.docker-compose.yml +14 -2
  5. package/docker-compose.override.example.yml +81 -0
  6. package/docker-compose.yml +23 -17
  7. package/package.json +4 -2
  8. package/src/cli/wiki-manager.js +3 -1
  9. package/src/commands/slash.js +53 -39
  10. package/src/core/agentEvents.js +20 -0
  11. package/src/core/agentEvents.test.js +38 -1
  12. package/src/core/buildInfo.json +2 -2
  13. package/src/core/commandFailure.js +81 -0
  14. package/src/core/commandFailure.test.js +67 -0
  15. package/src/core/compose.js +20 -3
  16. package/src/core/composeOverrides.test.js +74 -0
  17. package/src/core/dockerCompose.test.js +69 -2
  18. package/src/core/env.js +59 -0
  19. package/src/core/env.test.js +33 -1
  20. package/src/core/mcp.js +1 -1
  21. package/src/core/setEnvValue.test.js +96 -0
  22. package/src/runtime/client.js +18 -0
  23. package/src/runtime/lifecycle.js +5 -1
  24. package/src/runtime/server.js +43 -1
  25. package/src/runtime/server.test.js +117 -0
  26. package/src/runtime/store.js +47 -0
  27. package/src/runtime/store.test.js +89 -1
  28. package/src/shell/LeftPane.tsx +46 -16
  29. package/src/shell/RightPane.tsx +2 -4
  30. package/src/shell/SetupWizard.tsx +19 -7
  31. package/src/shell/externalLinks.js +24 -2
  32. package/src/shell/openExternal.js +53 -0
  33. package/src/shell/repl.js +33 -10
  34. package/src/shell/repl.test.js +91 -9
  35. package/src/shell/setupWizardPlaceholders.test.js +66 -0
  36. package/src/shell/tui.tsx +54 -25
  37. package/src/shell/useSession.ts +42 -6
  38. package/wiki-workspace +84 -6
package/wiki-workspace CHANGED
@@ -119,6 +119,13 @@ Configuration:
119
119
  Override directory: WIKI_WORKSPACES_DIR=/path/to/dir
120
120
  Runtime node: WIKI_MANAGER_NODE_BIN=/path/to/node
121
121
  Local CA: --cacert /absolute/path/to/ca.pem (Docker must be able to read this host path)
122
+
123
+ Compose overrides (next to the manager .env, created once, never regenerated):
124
+ docker-compose.override.yml Workspace stack (serve, mcp-http, production-mcp)
125
+ agents.docker-compose.override.yml Agents stack (cme, documents, connectors)
126
+ Use them for proxy passthrough, extra mounts and optional agents.
127
+ Never edit .wiki/runtime/*.compose.yml — that is generated state, rewritten
128
+ on every compose command.
122
129
  EOF
123
130
  }
124
131
 
@@ -173,19 +180,50 @@ generate_token() {
173
180
  die "cannot generate MCP auth token: openssl and /dev/urandom are unavailable"
174
181
  }
175
182
 
183
+ # Matches the commented placeholders shipped in .env.example — `# KEY=`,
184
+ # `#KEY=`, `## KEY=` — but never a prose comment that merely mentions the key.
185
+ commented_assignment() {
186
+ local line="$1"
187
+ local key="$2"
188
+ [[ "$line" =~ ^[[:space:]]*#+[[:space:]]*"$key"= ]]
189
+ }
190
+
176
191
  set_env_value() {
177
192
  local file="$1"
178
193
  local key="$2"
179
194
  local value="$3"
180
195
  local tmp="${file}.tmp.$$"
181
196
  local wrote=0 line
197
+ local has_active=0
182
198
 
183
199
  if [[ -f "$file" ]]; then
200
+ # Most generated keys (OAUTH_STATE_SECRET, GOOGLE_OAUTH_CALLBACK_URL,
201
+ # WIKI_MANAGER_RUNTIME_TOKEN…) ship as commented placeholders in
202
+ # .env.example. Appending the real value at the end of the file left the
203
+ # commented twin above it, so the .env read top-down still documented the
204
+ # key as unset — operators re-generated tokens that already existed. Reuse
205
+ # the placeholder's own line instead, keeping the value under the comment
206
+ # block that explains it.
207
+ #
208
+ # An ACTIVE assignment always wins: it is the operator's own choice, and a
209
+ # commented line further down must stay commented rather than become a
210
+ # second, contradictory assignment.
211
+ while IFS= read -r line || [[ -n "$line" ]]; do
212
+ line="${line%$'\r'}"
213
+ if [[ "$line" == "$key="* ]]; then
214
+ has_active=1
215
+ break
216
+ fi
217
+ done < "$file"
218
+
184
219
  while IFS= read -r line || [[ -n "$line" ]]; do
185
220
  line="${line%$'\r'}"
186
221
  if [[ "$line" == "$key="* ]]; then
187
222
  printf '%s=%s\n' "$key" "$value"
188
223
  wrote=1
224
+ elif [[ "$has_active" -eq 0 && "$wrote" -eq 0 ]] && commented_assignment "$line" "$key"; then
225
+ printf '%s=%s\n' "$key" "$value"
226
+ wrote=1
189
227
  else
190
228
  printf '%s\n' "$line"
191
229
  fi
@@ -207,6 +245,7 @@ agents_compose() {
207
245
  local subcommand="$1"
208
246
  shift
209
247
  ensure_manager_endpoints_file
248
+ ensure_compose_override 'agents.docker-compose.override.example.yml' 'agents.docker-compose.override.yml'
210
249
  local agents_compose_file="$ROOT_DIR/agents.docker-compose.yml"
211
250
  [[ -f "$agents_compose_file" ]] || die "agents compose file not found: $agents_compose_file"
212
251
 
@@ -226,9 +265,9 @@ agents_compose() {
226
265
  connectors_enabled && profile_args+=(--profile connectors)
227
266
  WORKSPACES_ROOT="$workspaces_root" AGENTS_DATA_DIR="$agents_data_dir" \
228
267
  read_lines_into_array cacert_args cacert_compose_args "$agents_compose_file" "agents.cacert.compose.yml"
229
- # User-owned override: optional external agents live in a
230
- # file the user maintains NEXT TO the .env — never generated, never
231
- # overwritten by package updates.
268
+ # User-owned override: optional external agents, proxy passthrough and
269
+ # any local fix live in a file the user maintains NEXT TO the .env —
270
+ # scaffolded once by ensure_compose_override, never overwritten afterwards.
232
271
  local override_args=()
233
272
  local user_override="$MANAGER_STATE_DIR/agents.docker-compose.override.yml"
234
273
  [[ -f "$user_override" ]] && override_args+=(-f "$user_override")
@@ -268,7 +307,7 @@ agents_compose() {
268
307
  "${CME_MCP_PORT:-3336}" "${DOCUMENTS_MCP_PORT:-3337}"
269
308
  connectors_enabled && printf ' connectors=:%s' "${CONNECTORS_MCP_PORT:-3338}"
270
309
  printf '\n'
271
- [[ ! -f "$MANAGER_STATE_DIR/agents.docker-compose.override.yml" ]] || printf 'User override: agents.docker-compose.override.yml included\n'
310
+ [[ ! -f "$MANAGER_STATE_DIR/agents.docker-compose.override.yml" ]] || printf 'User override: %s\n' "$MANAGER_STATE_DIR/agents.docker-compose.override.yml"
272
311
  ;;
273
312
  down)
274
313
  [[ $# -eq 0 ]] || die "agents down does not take arguments"
@@ -430,6 +469,16 @@ ensure_agent_tokens() {
430
469
  fi
431
470
  done
432
471
  if connectors_enabled; then
472
+ # CONNECTORS_MCP_PORT ships as a commented placeholder, so enabling
473
+ # connectors left the workspace stack interpolating an unset variable:
474
+ # `The "CONNECTORS_MCP_PORT" variable is not set` on every compose command,
475
+ # and serve advertising the connectors endpoint on a blank port. Pin the
476
+ # value the agents stack is actually using so both stacks agree.
477
+ if [[ -z "$(env_value "$MANAGER_ENV_FILE" CONNECTORS_MCP_PORT "")" ]]; then
478
+ mkdir -p "$(dirname "$MANAGER_ENV_FILE")"
479
+ set_env_value "$MANAGER_ENV_FILE" CONNECTORS_MCP_PORT "${CONNECTORS_MCP_PORT:-3338}"
480
+ printf 'Pinned CONNECTORS_MCP_PORT=%s in %s\n' "${CONNECTORS_MCP_PORT:-3338}" "$MANAGER_ENV_FILE"
481
+ fi
433
482
  for key in CONNECTORS_MCP_AUTH_TOKEN OAUTH_STATE_SECRET OAUTH_START_TOKEN; do
434
483
  token="$(env_value "$MANAGER_ENV_FILE" "$key" "")"
435
484
  if [[ -z "$token" ]]; then
@@ -687,6 +736,23 @@ start_workspace_services() {
687
736
  compose_for_workspace "$1" up -d serve mcp-http production-mcp
688
737
  }
689
738
 
739
+ ensure_compose_override() {
740
+ # User-owned compose overrides. Seeded ONCE from the packaged example and
741
+ # never rewritten afterwards — the opposite policy from
742
+ # .wiki/runtime/*.cacert.compose.yml, which is generated state and must always
743
+ # be replaced. Without a file scaffolded up front, operators hit a corporate
744
+ # proxy or a missing mount and have no supported place to fix it, so they edit
745
+ # the generated override and lose the change on the next compose command.
746
+ local example_name="$1"
747
+ local target_name="$2"
748
+ local target="$MANAGER_STATE_DIR/$target_name"
749
+ [[ -f "$target" ]] && return 0
750
+ [[ -f "$ROOT_DIR/$example_name" ]] || return 0
751
+ mkdir -p "$MANAGER_STATE_DIR"
752
+ cp "$ROOT_DIR/$example_name" "$target"
753
+ printf 'Created %s (user-owned compose override, never regenerated)\n' "$target" >&2
754
+ }
755
+
690
756
  ensure_manager_endpoints_file() {
691
757
  if [[ ! -f "$MANAGER_ENDPOINTS_FILE" && -f "$ROOT_DIR/mcp.endpoints.example.json" ]]; then
692
758
  mkdir -p "$(dirname "$MANAGER_ENDPOINTS_FILE")"
@@ -803,6 +869,7 @@ compose_for_workspace() {
803
869
  local workspace="$1"
804
870
  shift
805
871
  need_workspace_env "$workspace"
872
+ ensure_compose_override 'docker-compose.override.example.yml' 'docker-compose.override.yml'
806
873
  local workspace_env ws_path serve_port mcp_port prod_port project agents_data_dir
807
874
  workspace_env="$(workspace_env_file "$workspace")"
808
875
  ws_path="$(normalize_path "$(workspace_value "$workspace" WIKI_WORKSPACE_PATH)")"
@@ -822,6 +889,12 @@ compose_for_workspace() {
822
889
  WIKI_MCP_PORT="$mcp_port" \
823
890
  PRODUCTION_MCP_PORT="$prod_port" \
824
891
  read_lines_into_array cacert_args cacert_compose_args "$ROOT_DIR/docker-compose.yml" "cacert.compose.yml"
892
+ # Same contract as the agents stack: a single global user-owned override next
893
+ # to the .env, merged after the packaged file and before the generated CA
894
+ # override so the operator can still be overruled on CA paths only.
895
+ local override_args=()
896
+ local user_override="$MANAGER_STATE_DIR/docker-compose.override.yml"
897
+ [[ -f "$user_override" ]] && override_args+=(-f "$user_override")
825
898
 
826
899
  WIKI_WORKSPACE_PATH="$ws_path" \
827
900
  WIKI_SERVE_PORT="$serve_port" \
@@ -829,7 +902,7 @@ compose_for_workspace() {
829
902
  PRODUCTION_MCP_PORT="$prod_port" \
830
903
  AGENTS_DATA_DIR="$agents_data_dir" \
831
904
  docker compose --project-directory "$DEFAULT_MANAGER_DIR" \
832
- ${compose_env_args[@]+"${compose_env_args[@]}"} -f "$ROOT_DIR/docker-compose.yml" ${cacert_args[@]+"${cacert_args[@]}"} -p "$project" "$@"
905
+ ${compose_env_args[@]+"${compose_env_args[@]}"} -f "$ROOT_DIR/docker-compose.yml" ${override_args[@]+"${override_args[@]}"} ${cacert_args[@]+"${cacert_args[@]}"} -p "$project" "$@"
833
906
  }
834
907
 
835
908
  logs_args() {
@@ -1036,6 +1109,8 @@ config_workspace() {
1036
1109
  local target_path="${2:-$WORKSPACES_DIR/$workspace}"
1037
1110
  target_path="$(absolute_path "$target_path")"
1038
1111
  ensure_manager_endpoints_file
1112
+ ensure_compose_override 'docker-compose.override.example.yml' 'docker-compose.override.yml'
1113
+ ensure_compose_override 'agents.docker-compose.override.example.yml' 'agents.docker-compose.override.yml'
1039
1114
 
1040
1115
  local env_file="$target_path/.env"
1041
1116
  [[ -f "$env_file" ]] && die "workspace already configured: $env_file"
@@ -1073,13 +1148,16 @@ config_workspace() {
1073
1148
  WIKI_SERVE_PORT="$serve_port" \
1074
1149
  WIKI_MCP_PORT="$mcp_port" \
1075
1150
  read_lines_into_array cacert_args cacert_compose_args "$ROOT_DIR/docker-compose.yml" "cacert.compose.yml"
1151
+ local override_args=()
1152
+ local user_override="$MANAGER_STATE_DIR/docker-compose.override.yml"
1153
+ [[ -f "$user_override" ]] && override_args+=(-f "$user_override")
1076
1154
 
1077
1155
  WIKI_WORKSPACE_PATH="$target_path" \
1078
1156
  WIKI_SERVE_PORT="$serve_port" \
1079
1157
  WIKI_MCP_PORT="$mcp_port" \
1080
1158
  AGENTS_DATA_DIR="$agents_data_dir" \
1081
1159
  docker compose --project-directory "$DEFAULT_MANAGER_DIR" \
1082
- ${compose_env_args[@]+"${compose_env_args[@]}"} -f "$ROOT_DIR/docker-compose.yml" ${cacert_args[@]+"${cacert_args[@]}"} run --rm wiki init
1160
+ ${compose_env_args[@]+"${compose_env_args[@]}"} -f "$ROOT_DIR/docker-compose.yml" ${override_args[@]+"${override_args[@]}"} ${cacert_args[@]+"${cacert_args[@]}"} run --rm wiki init
1083
1161
 
1084
1162
  printf 'Workspace ready: %s\n' "$target_path"
1085
1163
  printf 'Start with: wiki-workspace up %s\n' "$workspace"