@dotdrelle/wiki-manager 0.15.41 → 0.15.43

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/src/shell/tui.tsx CHANGED
@@ -381,7 +381,11 @@ function App(props: {
381
381
  input={state.input()}
382
382
  busy={state.busy()}
383
383
  chatMode={state.chatMode()}
384
- chatFocused={!state.activeEditor()}
384
+ // The composer must lose focus for EVERY modal, not just the file
385
+ // editor. While the setup wizard was open the input stayed focused
386
+ // underneath it, so answering a wizard question also typed into the
387
+ // chat box at the bottom of the window.
388
+ chatFocused={!state.activeEditor() && screen() === 'main'}
385
389
  setInput={state.setInput}
386
390
  submit={submit}
387
391
  conversationRows={conversationRows()}
@@ -433,17 +437,33 @@ function App(props: {
433
437
  onSave={state.saveEditor}
434
438
  onCancel={state.closeEditor}
435
439
  />
440
+ {/*
441
+ Opaque backdrop, same treatment WizardApp gives the standalone
442
+ wizard. Without it the dialog floated over a live two-pane layout:
443
+ the panes showed through around its border and the whole thing read
444
+ as one garbled screen rather than as a modal.
445
+ */}
436
446
  {screen() === 'setup' ? (
437
- <SetupWizard
438
- mode="setup"
439
- session={state.session}
447
+ <box
448
+ position="absolute"
449
+ left={0}
450
+ top={0}
440
451
  width={dimensions().width}
441
452
  height={dimensions().height}
442
- initialRoute="workspace-name"
443
- closeOnDone
444
- onComplete={closeSetup}
445
- onClose={closeSetup}
446
- />
453
+ zIndex={39}
454
+ backgroundColor="#0B0D12"
455
+ >
456
+ <SetupWizard
457
+ mode="setup"
458
+ session={state.session}
459
+ width={dimensions().width}
460
+ height={dimensions().height}
461
+ initialRoute="workspace-name"
462
+ closeOnDone
463
+ onComplete={closeSetup}
464
+ onClose={closeSetup}
465
+ />
466
+ </box>
447
467
  ) : null}
448
468
  </box>
449
469
  }
package/wiki-workspace CHANGED
@@ -70,13 +70,19 @@ parse_global_options() {
70
70
  export REQUESTS_CA_BUNDLE="$CACERT_PATH"
71
71
  export CURL_CA_BUNDLE="$CACERT_PATH"
72
72
  fi
73
- set -- "${parsed[@]}"
73
+ # `${arr[@]}` on an EMPTY array is an unbound-variable error under `set -u`
74
+ # in bash <= 4.3 — which includes the /bin/bash 3.2 macOS still ships. Every
75
+ # optional array in this script therefore goes through the `${arr[@]+…}`
76
+ # guard (see compose_env_args, override_args, only_services…); these two were
77
+ # missed, so any invocation without a global option died on this line before
78
+ # reaching its subcommand.
79
+ set -- ${parsed[@]+"${parsed[@]}"}
74
80
  PARSED_ARGS=("$@")
75
81
  }
76
82
 
77
83
  PARSED_ARGS=()
78
84
  parse_global_options "$@"
79
- set -- "${PARSED_ARGS[@]}"
85
+ set -- ${PARSED_ARGS[@]+"${PARSED_ARGS[@]}"}
80
86
 
81
87
  usage() {
82
88
  cat <<'EOF'
@@ -111,11 +117,33 @@ Commands:
111
117
  wiki <workspace> down Stop all services for this workspace
112
118
  wiki <workspace> logs [args...] Follow workspace service logs (tail 100 by default)
113
119
  wiki <workspace> serve [--open] Start the web UI in foreground (--open launches browser)
120
+ wiki <workspace> reset [--dry-run] [--yes]
121
+ Empty the workspace, keeping .wikirc*, templates/ and
122
+ build-context/. Requires the services to be stopped.
114
123
  wiki <workspace> doctor Run wiki doctor
115
124
  wiki <workspace> ingest Run wiki ingest
116
125
  wiki <workspace> build Run wiki build
117
126
  wiki <workspace> export Run wiki export
118
- wiki <workspace> run <args...> Run arbitrary wiki CLI args
127
+ wiki <workspace> run <args...> Run arbitrary wiki CLI args (see below)
128
+
129
+ wiki CLI commands reachable through `wiki <workspace> run`:
130
+ history [--file <path>] [--limit <n>] [--json]
131
+ List workspace history commits (Git, workspace-local)
132
+ restore --run <sha> [--dry-run] Revert every file changed by a run commit
133
+ restore --file <path> --to <sha> [--dry-run]
134
+ Restore one versioned file to a revision
135
+ query "<question>" Answer from the wiki and its cited source notes
136
+ index Create or update the local vector index
137
+ refresh Regenerate only the stale deliverables
138
+ lint Static checks: dead links, orphans, stale deliverables
139
+ add-skill <source> Install a workspace method (directory, .zip, HTTPS .zip)
140
+ config Show the effective .wikirc.yaml
141
+ group-concepts Regroup wiki concepts
142
+ doctor, ingest, build, export Also available directly: wiki <workspace> <command>
143
+
144
+ History is versioned for wiki/, templates/, build-context/, deliverables/,
145
+ raw/ingested/ and .wiki/build-state.json only. A restore adds a commit rather
146
+ than rewriting history, and --dry-run previews it without writing.
119
147
 
120
148
  Configuration:
121
149
  workspaces/<workspace>/.env
@@ -338,7 +366,7 @@ agents_compose() {
338
366
  logs)
339
367
  local log_args=()
340
368
  read_lines_into_array log_args logs_args "$@"
341
- _agents_dc logs "${log_args[@]}"
369
+ _agents_dc logs ${log_args[@]+"${log_args[@]}"}
342
370
  ;;
343
371
  pull)
344
372
  [[ $# -eq 0 ]] || die "agents pull does not take arguments"
@@ -1171,6 +1199,117 @@ run_wiki() {
1171
1199
  compose_for_workspace "$workspace" run --rm wiki "$@"
1172
1200
  }
1173
1201
 
1202
+ # What `wiki <workspace> reset` keeps: the METHOD. `.wikirc*` (provider, model,
1203
+ # retrieval, per-profile variants), `templates/` and `build-context/` describe
1204
+ # how this workspace produces; everything else is what it has produced, cached
1205
+ # or logged. `.git/` is kept too — the history from before the reset stays
1206
+ # reachable through `wiki restore`, which is the only cheap undo there is.
1207
+ #
1208
+ # `.env` is kept for a harder reason than method: it IS the workspace's
1209
+ # registration — ports, MCP auth tokens, WIKI_WORKSPACE_PATH. Deleting it makes
1210
+ # the very next line of reset_workspace (`run_wiki … init`, which starts with
1211
+ # need_workspace_env) die under `set -euo pipefail`, leaving the workspace
1212
+ # emptied and never re-scaffolded. And recovering it with `config` mints new
1213
+ # ports and tokens, silently invalidating every reference to the old ones
1214
+ # (mcp.endpoints.json among them). Nothing here may drop it.
1215
+ workspace_reset_keep() {
1216
+ case "$1" in
1217
+ .|..|.git) return 0 ;;
1218
+ .env|.env.*) return 0 ;;
1219
+ .wikirc*) return 0 ;;
1220
+ templates|build-context) return 0 ;;
1221
+ *) return 1 ;;
1222
+ esac
1223
+ }
1224
+
1225
+ # Destructive, and deliberately reachable ONLY from this CLI: no `wiki reset`
1226
+ # subcommand, no production job type, no MCP tool, no skill. Nothing Donna can
1227
+ # call may erase a workspace.
1228
+ #
1229
+ # It also stops after re-scaffolding. Chaining a sync or a build here would be
1230
+ # convenient exactly once and wrong every other time: refilling the workspace
1231
+ # is the user's decision, not a side effect of emptying it.
1232
+ reset_workspace() {
1233
+ local workspace="$1"
1234
+ shift
1235
+ local assume_yes=0 dry_run=0
1236
+ while [[ $# -gt 0 ]]; do
1237
+ case "$1" in
1238
+ --yes|-y) assume_yes=1 ;;
1239
+ --dry-run) dry_run=1 ;;
1240
+ *) die "reset accepts only --yes and --dry-run (got: $1)" ;;
1241
+ esac
1242
+ shift
1243
+ done
1244
+
1245
+ need_workspace_env "$workspace"
1246
+ local ws_path
1247
+ ws_path="$(normalize_path "$(workspace_value "$workspace" WIKI_WORKSPACE_PATH)")"
1248
+ [[ -d "$ws_path" ]] || die "workspace directory not found: $ws_path"
1249
+
1250
+ # A container still writing into the bind mount would recreate part of what
1251
+ # we just erased, and leave files owned by another UID behind.
1252
+ local running_services=()
1253
+ read_lines_into_array running_services compose_for_workspace "$workspace" ps --status running --services
1254
+ if [[ ${#running_services[@]} -gt 0 ]]; then
1255
+ die "workspace services are still running (${running_services[*]}) — stop them first: wiki-workspace wiki $workspace down"
1256
+ fi
1257
+
1258
+ local entry name
1259
+ local removed=() kept=()
1260
+ for entry in "$ws_path"/* "$ws_path"/.*; do
1261
+ [[ -e "$entry" ]] || continue
1262
+ name="$(basename "$entry")"
1263
+ if workspace_reset_keep "$name"; then
1264
+ [[ "$name" == "." || "$name" == ".." ]] || kept+=("$name")
1265
+ continue
1266
+ fi
1267
+ removed+=("$name")
1268
+ done
1269
+
1270
+ printf 'Workspace: %s (%s)\n' "$workspace" "$ws_path"
1271
+ printf 'Keep: %s\n' "${kept[*]:-(nothing)}"
1272
+ printf 'Reset: %s\n' "${removed[*]:-(nothing)}"
1273
+
1274
+ if [[ ${#removed[@]} -eq 0 ]]; then
1275
+ printf 'Nothing to reset.\n'
1276
+ return
1277
+ fi
1278
+
1279
+ if [[ $dry_run -eq 1 ]]; then
1280
+ printf 'Dry run: nothing was deleted. Re-run without --dry-run to apply.\n'
1281
+ return
1282
+ fi
1283
+
1284
+ if [[ $assume_yes -eq 0 ]]; then
1285
+ [[ -t 0 ]] || die "reset needs a terminal to confirm — pass --yes for a non-interactive run"
1286
+ printf 'This deletes the wiki, the deliverables and the sources. Type the workspace name to confirm (%s): ' "$workspace"
1287
+ local answer=''
1288
+ IFS= read -r answer || true
1289
+ [[ "$answer" == "$workspace" ]] || die "reset aborted"
1290
+ fi
1291
+
1292
+ for name in "${removed[@]}"; do
1293
+ rm -rf -- "${ws_path:?}/$name" \
1294
+ || die "could not remove $ws_path/$name — check file ownership (containers run as the node user), then retry"
1295
+ done
1296
+
1297
+ # Puts the structure back: empty raw/wiki/deliverables trees, .wiki/skills,
1298
+ # system-prompt, an empty profile, CLAUDE.md, .gitignore, and a fresh history
1299
+ # baseline. `wiki init` never overwrites an existing file, so the kept
1300
+ # `.wikirc*`, templates/ and build-context/ come through untouched.
1301
+ run_wiki "$workspace" init
1302
+
1303
+ # The scaffold ships a demo brief in raw/untracked/. Reappearing here it would
1304
+ # not read as a sample but as a pending source, and the next ingest would file
1305
+ # it into the wiki as if the user had provided it.
1306
+ rm -f -- "$ws_path/raw/untracked/demo-project-brief.md"
1307
+
1308
+ printf 'Reset done: %s\n' "$workspace"
1309
+ printf 'Kept: %s\n' "${kept[*]:-(nothing)}"
1310
+ printf 'Nothing was rebuilt. Bring the sources back when you decide to (e.g. /wiki-sync), then build.\n'
1311
+ }
1312
+
1174
1313
  open_app_mode() {
1175
1314
  local url="$1"
1176
1315
  case "$(uname -s)" in
@@ -1452,7 +1591,7 @@ main() {
1452
1591
  logs)
1453
1592
  local log_args=()
1454
1593
  read_lines_into_array log_args logs_args "$@"
1455
- compose_for_workspace "$workspace" logs "${log_args[@]}" serve mcp-http production-mcp
1594
+ compose_for_workspace "$workspace" logs ${log_args[@]+"${log_args[@]}"} serve mcp-http production-mcp
1456
1595
  ;;
1457
1596
  serve)
1458
1597
  local open_browser=0
@@ -1481,6 +1620,9 @@ main() {
1481
1620
 
1482
1621
  compose_for_workspace "$workspace" up serve
1483
1622
  ;;
1623
+ reset)
1624
+ reset_workspace "$workspace" "$@"
1625
+ ;;
1484
1626
  doctor|ingest|build|export)
1485
1627
  run_wiki "$workspace" "$command" "$@"
1486
1628
  ;;