@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/README.md +48 -4
- package/package.json +2 -2
- package/src/agent/graph.js +3 -8
- package/src/cli/wiki-manager.js +35 -2
- package/src/commands/slash.js +36 -8
- package/src/core/agentEvents.js +23 -0
- package/src/core/agentEvents.test.js +32 -0
- package/src/core/buildInfo.json +2 -2
- package/src/core/compose.js +32 -0
- package/src/core/dockerCompose.test.js +32 -0
- package/src/core/mcp.js +1 -1
- package/src/core/otherWorkspacesRunning.test.js +51 -0
- package/src/core/profile.js +19 -0
- package/src/core/profileServiceStatus.test.js +26 -2
- package/src/core/toolLoop.js +32 -7
- package/src/core/toolLoop.test.js +95 -0
- package/src/core/wikiSetup.js +50 -7
- package/src/core/wikiWorkspace.test.js +64 -0
- package/src/core/wikirc.test.js +121 -2
- package/src/core/workspaceInherit.js +149 -0
- package/src/core/workspaceInherit.test.js +181 -0
- package/src/core/workspaceProfile.test.js +55 -0
- package/src/runtime/server.js +15 -5
- package/src/runtime/server.test.js +31 -2
- package/src/runtime/workspaceIsolation.test.js +178 -0
- package/src/shell/repl.js +28 -7
- package/src/shell/setupWizardModality.test.js +55 -0
- package/src/shell/tui.tsx +29 -9
- package/wiki-workspace +147 -5
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
|
-
|
|
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
|
-
<
|
|
438
|
-
|
|
439
|
-
|
|
447
|
+
<box
|
|
448
|
+
position="absolute"
|
|
449
|
+
left={0}
|
|
450
|
+
top={0}
|
|
440
451
|
width={dimensions().width}
|
|
441
452
|
height={dimensions().height}
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
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
|
-
|
|
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
|
;;
|