@dotdrelle/wiki-manager 0.6.31 → 0.6.47
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 +3 -2
- package/bin/wiki-manager.js +1 -1
- package/package.json +8 -7
- package/src/agent/graph.js +6 -28
- package/src/cli/wiki-manager.js +17 -2
- package/src/commands/slash.js +121 -28
- package/src/commands/slash.test.js +146 -0
- package/src/core/compose.js +3 -3
- package/src/core/mcp.js +1 -1
- package/src/core/modelFetch.js +97 -0
- package/src/core/modelFetch.test.js +38 -0
- package/src/core/startupCheck.js +130 -0
- package/src/core/startupCheck.test.js +66 -0
- package/src/core/wikiSetup.js +156 -0
- package/src/core/wikirc.js +82 -3
- package/src/core/wikirc.test.js +111 -0
- package/src/core/workspaces.js +1 -1
- package/src/shell/LeftPane.tsx +54 -28
- package/src/shell/RightPane.tsx +25 -2
- package/src/shell/SetupWizard.tsx +806 -0
- package/src/shell/SlashDialog.tsx +4 -3
- package/src/shell/repl.js +21 -8
- package/src/shell/tui.tsx +85 -13
- package/src/shell/useSession.ts +15 -7
- package/wiki-workspace +19 -15
|
@@ -24,14 +24,15 @@ export function SlashDialog(props: { context: any }) {
|
|
|
24
24
|
{(item: any, index) => (
|
|
25
25
|
<text
|
|
26
26
|
height={1}
|
|
27
|
-
fg={index() === context().
|
|
28
|
-
bg={index() === context().
|
|
27
|
+
fg={index() === context().visibleSelected ? '#111318' : '#D6DEE8'}
|
|
28
|
+
bg={index() === context().visibleSelected ? '#8BD5CA' : '#111318'}
|
|
29
29
|
>
|
|
30
30
|
{item.value.padEnd(16, ' ')} {item.description}
|
|
31
31
|
</text>
|
|
32
32
|
)}
|
|
33
33
|
</For>
|
|
34
|
-
<text
|
|
34
|
+
<text height={1} />
|
|
35
|
+
<text fg="#7F8C8D">[up/down navigate, Tab complete, Enter confirm, Esc clear]</text>
|
|
35
36
|
</box>
|
|
36
37
|
)}
|
|
37
38
|
</Show>
|
package/src/shell/repl.js
CHANGED
|
@@ -54,8 +54,8 @@ const COMMAND_COMPLETION_DESCRIPTIONS = {
|
|
|
54
54
|
'/help': 'Show shell commands.',
|
|
55
55
|
'/version': 'Print the wiki-manager version.',
|
|
56
56
|
'/exit': 'Exit the shell.',
|
|
57
|
-
'/
|
|
58
|
-
'/new': '
|
|
57
|
+
'/workspace': 'List, create, or delete workspaces.',
|
|
58
|
+
'/new': 'Open the setup wizard in the interactive TUI.',
|
|
59
59
|
'/use': 'Load a workspace and its default config.',
|
|
60
60
|
'/config': 'Inspect or switch .wikirc.yaml profiles.',
|
|
61
61
|
'/status': 'Show the current workspace and session state.',
|
|
@@ -89,7 +89,9 @@ const SUBCOMMAND_COMPLETION_DESCRIPTIONS = {
|
|
|
89
89
|
'/queue': 'Inspect or cancel queued MCP jobs.',
|
|
90
90
|
'/queue:cancel': 'Cancel a queued or running queue item.',
|
|
91
91
|
'/queue:clear': 'Clear finished queue items.',
|
|
92
|
-
'/workspace:init': '
|
|
92
|
+
'/workspace:init': 'Low-level workspace creation.',
|
|
93
|
+
'/workspace:list': 'List configured workspaces.',
|
|
94
|
+
'/workspace:delete': 'Delete one workspace after confirmation.',
|
|
93
95
|
'/wiki:run': 'Use the low-level llm-wiki CLI fallback.',
|
|
94
96
|
'/skills:edit': 'Edit one workspace skill file.',
|
|
95
97
|
'/skills:list': 'List workspace skills.',
|
|
@@ -106,7 +108,7 @@ export function createSession() {
|
|
|
106
108
|
wikircConfig: null,
|
|
107
109
|
language: null,
|
|
108
110
|
mcp: null,
|
|
109
|
-
commands: ['help', 'version', 'exit', '
|
|
111
|
+
commands: ['help', 'version', 'exit', 'workspace', 'new', 'use', 'config', 'status', 'services', 'start', 'stop', 'logs', 'mcp', 'wiki', 'skills', 'upload', 'uploads', 'clear', 'chat', 'agent', 'openui', 'queue'],
|
|
110
112
|
chatMode: true,
|
|
111
113
|
llm: null,
|
|
112
114
|
activities: {},
|
|
@@ -200,6 +202,7 @@ function completionValuesFor(parts, inputBuffer, session) {
|
|
|
200
202
|
if (tokenIndex === 0) return slashCompletions(session);
|
|
201
203
|
if (command === '/new' && tokenIndex === 1) return [];
|
|
202
204
|
if (command === '/use' && tokenIndex === 1) return workspaceNames();
|
|
205
|
+
if (command === '/use' && tokenIndex === 2) return [];
|
|
203
206
|
if (command === '/config' && tokenIndex === 1) return ['edit', 'list', 'status', 'use'];
|
|
204
207
|
if (command === '/config' && (previousToken === 'use' || previousToken === 'edit')) return wikircProfileNames(session);
|
|
205
208
|
if (command === '/mcp' && tokenIndex === 1) return ['call', 'endpoints', 'status', 'tools'];
|
|
@@ -216,11 +219,16 @@ function completionValuesFor(parts, inputBuffer, session) {
|
|
|
216
219
|
.filter((item) => ['waiting', 'starting', 'running'].includes(item.status))
|
|
217
220
|
.map((item) => item.id);
|
|
218
221
|
}
|
|
219
|
-
if (command === '/workspace'
|
|
222
|
+
if (command === '/workspace') {
|
|
223
|
+
if (tokenIndex === 1) return ['delete', 'init', 'list'];
|
|
224
|
+
if (previousToken === 'delete') return workspaceNames();
|
|
225
|
+
if (parts[1] === 'delete' && tokenIndex === 3) return ['--confirm'];
|
|
226
|
+
}
|
|
220
227
|
if (command === '/wiki' && tokenIndex === 1) return ['run'];
|
|
221
228
|
if (command === '/skills' && tokenIndex === 1) return ['edit', 'list', 'run', 'show'];
|
|
222
229
|
if (command === '/skills' && ['edit', 'run', 'show'].includes(previousToken ?? '')) return skillNames(session);
|
|
223
|
-
if ((command === '/start' || command === '/stop'
|
|
230
|
+
if ((command === '/start' || command === '/stop') && tokenIndex === 1) return ['agents', ...serviceNames()];
|
|
231
|
+
if (command === '/logs' && tokenIndex === 1) return serviceNames();
|
|
224
232
|
return [];
|
|
225
233
|
}
|
|
226
234
|
|
|
@@ -289,6 +297,11 @@ export function completionDescription(value, parts) {
|
|
|
289
297
|
if (command === '/start') return serviceDescription(value) ?? 'Start this Docker Compose service.';
|
|
290
298
|
if (command === '/stop') return serviceDescription(value) ?? 'Stop this Docker Compose service.';
|
|
291
299
|
if (command === '/logs') return serviceDescription(value) ?? 'Show logs for this Docker Compose service.';
|
|
300
|
+
if (command === '/workspace') {
|
|
301
|
+
if (parts[1] === 'delete' && value === '--confirm') return 'Confirm workspace deletion.';
|
|
302
|
+
if (parts.at(-1) === 'delete') return 'Delete this workspace.';
|
|
303
|
+
return 'Choose a workspace action.';
|
|
304
|
+
}
|
|
292
305
|
if (command === '/mcp') return parts[1] === 'call' ? 'Use this MCP server.' : 'Filter tools to this MCP server.';
|
|
293
306
|
if (command === '/skills') {
|
|
294
307
|
if (parts.at(-1) === 'edit') return 'Edit this skill.';
|
|
@@ -1174,7 +1187,7 @@ async function runTuiShell({ agent, packageJson, session }) {
|
|
|
1174
1187
|
rerender();
|
|
1175
1188
|
|
|
1176
1189
|
try {
|
|
1177
|
-
const { output: wsOutput } = await handleSlashCommand('/
|
|
1190
|
+
const { output: wsOutput } = await handleSlashCommand('/workspace list', { packageJson, session });
|
|
1178
1191
|
if (wsOutput) messages.push({ role: 'command', content: wsOutput });
|
|
1179
1192
|
} finally {
|
|
1180
1193
|
clearInterval(spinnerInterval);
|
|
@@ -1316,7 +1329,7 @@ async function runTuiShell({ agent, packageJson, session }) {
|
|
|
1316
1329
|
}
|
|
1317
1330
|
return;
|
|
1318
1331
|
}
|
|
1319
|
-
if (key?.ctrl && key.name === 'c') {
|
|
1332
|
+
if ((key?.ctrl || key?.meta) && key.name === 'c') {
|
|
1320
1333
|
if (busy) {
|
|
1321
1334
|
currentAbortController?.abort();
|
|
1322
1335
|
spinnerLabel = 'Interrupting…';
|
package/src/shell/tui.tsx
CHANGED
|
@@ -6,6 +6,7 @@ import { FileEditorDialog } from './FileEditorDialog';
|
|
|
6
6
|
import { LeftPane } from './LeftPane';
|
|
7
7
|
import { RightPane } from './RightPane';
|
|
8
8
|
import { SlashDialog } from './SlashDialog';
|
|
9
|
+
import { SetupWizard } from './SetupWizard';
|
|
9
10
|
import { useSession } from './useSession';
|
|
10
11
|
|
|
11
12
|
const SPINNER_FRAMES = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
|
|
@@ -37,7 +38,10 @@ function copyToClipboard(text: string, renderer: unknown) {
|
|
|
37
38
|
}
|
|
38
39
|
}
|
|
39
40
|
|
|
40
|
-
function App(props: {
|
|
41
|
+
function App(props: {
|
|
42
|
+
agent: unknown;
|
|
43
|
+
packageJson: Record<string, unknown>;
|
|
44
|
+
}) {
|
|
41
45
|
const renderer = useRenderer();
|
|
42
46
|
const dimensions = useTerminalDimensions();
|
|
43
47
|
const [spinnerIndex, setSpinnerIndex] = createSignal(0);
|
|
@@ -100,11 +104,12 @@ function App(props: { agent: unknown; packageJson: Record<string, unknown> }) {
|
|
|
100
104
|
});
|
|
101
105
|
|
|
102
106
|
useKeyboard((key) => {
|
|
107
|
+
const keyName = String(key.name ?? '').toLowerCase();
|
|
103
108
|
if (state.activeEditor()) {
|
|
104
|
-
if (
|
|
109
|
+
if (keyName === 'escape') state.closeEditor();
|
|
105
110
|
return;
|
|
106
111
|
}
|
|
107
|
-
if (key.ctrl
|
|
112
|
+
if ((key.ctrl || key.meta) && keyName === 'c') {
|
|
108
113
|
if (state.busy()) {
|
|
109
114
|
state.abort();
|
|
110
115
|
return;
|
|
@@ -121,19 +126,19 @@ function App(props: { agent: unknown; packageJson: Record<string, unknown> }) {
|
|
|
121
126
|
}, 1600);
|
|
122
127
|
return;
|
|
123
128
|
}
|
|
124
|
-
if (key.ctrl &&
|
|
129
|
+
if (key.ctrl && keyName === 'q') {
|
|
125
130
|
state.toggleRightTab();
|
|
126
131
|
return;
|
|
127
132
|
}
|
|
128
133
|
if (state.busy()) return;
|
|
129
|
-
if (
|
|
130
|
-
if (
|
|
131
|
-
else if (
|
|
132
|
-
if (
|
|
133
|
-
else if (
|
|
134
|
-
else if (
|
|
135
|
-
else if (
|
|
136
|
-
else if (
|
|
134
|
+
if (keyName === 'tab') state.completeSelected();
|
|
135
|
+
if (keyName === 'pageup') state.scrollConversation(conversationRows());
|
|
136
|
+
else if (keyName === 'pagedown') state.scrollConversation(-conversationRows());
|
|
137
|
+
if (keyName === 'up' && state.slash()) state.moveCompletion(-1);
|
|
138
|
+
else if (keyName === 'down' && state.slash()) state.moveCompletion(1);
|
|
139
|
+
else if (keyName === 'up' && !state.input().includes('\n')) state.historyUp();
|
|
140
|
+
else if (keyName === 'down' && !state.input().includes('\n')) state.historyDown();
|
|
141
|
+
else if (keyName === 'escape') {
|
|
137
142
|
if (state.slash()) state.dismissSlash();
|
|
138
143
|
else state.setInput('');
|
|
139
144
|
}
|
|
@@ -196,10 +201,77 @@ function App(props: { agent: unknown; packageJson: Record<string, unknown> }) {
|
|
|
196
201
|
);
|
|
197
202
|
}
|
|
198
203
|
|
|
199
|
-
export async function runOpenTuiShell({
|
|
204
|
+
export async function runOpenTuiShell({
|
|
205
|
+
agent,
|
|
206
|
+
packageJson,
|
|
207
|
+
}: {
|
|
208
|
+
agent: unknown;
|
|
209
|
+
packageJson: Record<string, unknown>;
|
|
210
|
+
}) {
|
|
200
211
|
await render(() => <App agent={agent} packageJson={packageJson} />, {
|
|
201
212
|
exitOnCtrlC: false,
|
|
202
213
|
useMouse: true,
|
|
203
214
|
targetFps: 30,
|
|
204
215
|
});
|
|
216
|
+
return {};
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
function WizardApp(props: {
|
|
220
|
+
mode: 'startup' | 'setup';
|
|
221
|
+
gaps?: any[];
|
|
222
|
+
initialWorkspaceName?: string;
|
|
223
|
+
initialWorkspacePath?: string | null;
|
|
224
|
+
onDone: () => void;
|
|
225
|
+
}) {
|
|
226
|
+
const renderer = useRenderer();
|
|
227
|
+
const dimensions = useTerminalDimensions();
|
|
228
|
+
const close = () => {
|
|
229
|
+
props.onDone();
|
|
230
|
+
renderer.destroy();
|
|
231
|
+
};
|
|
232
|
+
return (
|
|
233
|
+
<box width="100%" height="100%" backgroundColor="#0B0D12">
|
|
234
|
+
<SetupWizard
|
|
235
|
+
mode={props.mode}
|
|
236
|
+
session={{}}
|
|
237
|
+
gaps={props.gaps}
|
|
238
|
+
width={dimensions().width}
|
|
239
|
+
height={dimensions().height}
|
|
240
|
+
initialRoute={props.mode === 'setup' ? 'workspace-name' : undefined}
|
|
241
|
+
initialWorkspaceName={props.initialWorkspaceName}
|
|
242
|
+
initialWorkspacePath={props.initialWorkspacePath ?? null}
|
|
243
|
+
closeOnDone={props.mode === 'setup'}
|
|
244
|
+
onComplete={close}
|
|
245
|
+
onClose={close}
|
|
246
|
+
/>
|
|
247
|
+
</box>
|
|
248
|
+
);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
export async function runStartupWizard(gaps: any[]) {
|
|
252
|
+
if (!gaps.length) return;
|
|
253
|
+
await new Promise<void>((resolve, reject) => {
|
|
254
|
+
render(() => <WizardApp mode="startup" gaps={gaps} onDone={resolve} />, {
|
|
255
|
+
exitOnCtrlC: false,
|
|
256
|
+
useMouse: true,
|
|
257
|
+
targetFps: 30,
|
|
258
|
+
}).catch(reject);
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
export async function runSetupWizard(options: { workspaceName?: string; workspacePath?: string | null } = {}) {
|
|
263
|
+
await new Promise<void>((resolve, reject) => {
|
|
264
|
+
render(() => (
|
|
265
|
+
<WizardApp
|
|
266
|
+
mode="setup"
|
|
267
|
+
initialWorkspaceName={options.workspaceName}
|
|
268
|
+
initialWorkspacePath={options.workspacePath ?? null}
|
|
269
|
+
onDone={resolve}
|
|
270
|
+
/>
|
|
271
|
+
), {
|
|
272
|
+
exitOnCtrlC: false,
|
|
273
|
+
useMouse: true,
|
|
274
|
+
targetFps: 30,
|
|
275
|
+
}).catch(reject);
|
|
276
|
+
});
|
|
205
277
|
}
|
package/src/shell/useSession.ts
CHANGED
|
@@ -86,14 +86,22 @@ export function useSession(props: { agent: unknown; packageJson: Record<string,
|
|
|
86
86
|
session.llm ? 'llm ready' : 'llm limited',
|
|
87
87
|
].join(' ');
|
|
88
88
|
});
|
|
89
|
-
const
|
|
89
|
+
const matchContext = createMemo(() => {
|
|
90
90
|
if (input() === dismissedSlashInput()) return null;
|
|
91
|
-
|
|
91
|
+
return completionContext(input(), session);
|
|
92
|
+
});
|
|
93
|
+
const slash = createMemo(() => {
|
|
94
|
+
const context = matchContext();
|
|
92
95
|
if (!context) return null;
|
|
96
|
+
const selected = Math.min(selectedCompletion(), Math.max(0, context.matches.length - 1));
|
|
97
|
+
const visibleCount = 10;
|
|
98
|
+
const start = Math.max(0, Math.min(selected - Math.floor(visibleCount / 2), Math.max(0, context.matches.length - visibleCount)));
|
|
99
|
+
const visibleMatches = context.matches.slice(start, start + visibleCount);
|
|
93
100
|
return {
|
|
94
101
|
...context,
|
|
95
|
-
selected
|
|
96
|
-
|
|
102
|
+
selected,
|
|
103
|
+
visibleSelected: selected - start,
|
|
104
|
+
items: visibleMatches.map((value: string) => ({
|
|
97
105
|
value,
|
|
98
106
|
description: completionDescription(value, context.parts),
|
|
99
107
|
})),
|
|
@@ -249,8 +257,8 @@ export function useSession(props: { agent: unknown; packageJson: Record<string,
|
|
|
249
257
|
|
|
250
258
|
function completeSelected() {
|
|
251
259
|
const context = slash();
|
|
252
|
-
if (!context || context.
|
|
253
|
-
const selected = context.
|
|
260
|
+
if (!context || context.matches.length === 0) return;
|
|
261
|
+
const selected = context.matches[context.selected];
|
|
254
262
|
if (!selected) return;
|
|
255
263
|
const lastSpace = input().lastIndexOf(' ');
|
|
256
264
|
const base = input().endsWith(' ') ? input() : input().slice(0, lastSpace + 1);
|
|
@@ -259,7 +267,7 @@ export function useSession(props: { agent: unknown; packageJson: Record<string,
|
|
|
259
267
|
}
|
|
260
268
|
|
|
261
269
|
function moveCompletion(delta: number) {
|
|
262
|
-
const count = slash()?.
|
|
270
|
+
const count = slash()?.matches.length ?? 0;
|
|
263
271
|
if (!count) return;
|
|
264
272
|
setSelectedCompletion((value) => (value + delta + count) % count);
|
|
265
273
|
}
|
package/wiki-workspace
CHANGED
|
@@ -211,7 +211,7 @@ agents_compose() {
|
|
|
211
211
|
read_lines_into_array cacert_args cacert_compose_args "$agents_compose_file" "agents.cacert.compose.yml"
|
|
212
212
|
WORKSPACES_ROOT="$workspaces_root" AGENTS_DATA_DIR="$agents_data_dir" \
|
|
213
213
|
docker compose --project-directory "$DEFAULT_MANAGER_DIR" \
|
|
214
|
-
"${compose_env_args[@]}" -f "$agents_compose_file" "${cacert_args[@]}" -p wiki-agents "$@"
|
|
214
|
+
${compose_env_args[@]+"${compose_env_args[@]}"} -f "$agents_compose_file" ${cacert_args[@]+"${cacert_args[@]}"} -p wiki-agents "$@"
|
|
215
215
|
}
|
|
216
216
|
|
|
217
217
|
case "$subcommand" in
|
|
@@ -225,9 +225,14 @@ agents_compose() {
|
|
|
225
225
|
mkdir -p "$agents_data_dir/cme" "$agents_data_dir/documents/input" "$agents_data_dir/documents/output" "$agents_data_dir/documents/uploads"
|
|
226
226
|
mkdir -p "$workspaces_root"
|
|
227
227
|
$do_pull && _agents_dc pull
|
|
228
|
-
|
|
228
|
+
local up_args=(up -d)
|
|
229
|
+
if [[ -n "$CACERT_PATH" ]]; then
|
|
230
|
+
up_args+=(--force-recreate)
|
|
231
|
+
fi
|
|
232
|
+
_agents_dc "${up_args[@]}"
|
|
229
233
|
printf 'Workspaces root: %s\n' "$workspaces_root"
|
|
230
234
|
printf 'Agents data: %s\n' "$agents_data_dir"
|
|
235
|
+
[[ -z "$CACERT_PATH" ]] || printf 'CA cert: %s -> /wiki-manager-ca.pem\n' "$CACERT_PATH"
|
|
231
236
|
printf 'Agents: cme=:%s documents=:%s mailer=:%s\n' \
|
|
232
237
|
"${CME_MCP_PORT:-3336}" "${DOCUMENTS_MCP_PORT:-3337}" "${MAILER_MCP_PORT:-3335}"
|
|
233
238
|
;;
|
|
@@ -496,7 +501,7 @@ compose_for_workspace() {
|
|
|
496
501
|
WIKI_MCP_PORT="$mcp_port" \
|
|
497
502
|
PRODUCTION_MCP_PORT="$prod_port" \
|
|
498
503
|
docker compose --project-directory "$DEFAULT_MANAGER_DIR" \
|
|
499
|
-
"${compose_env_args[@]}" -f "$ROOT_DIR/docker-compose.yml" "${cacert_args[@]}" -p "$project" "$@"
|
|
504
|
+
${compose_env_args[@]+"${compose_env_args[@]}"} -f "$ROOT_DIR/docker-compose.yml" ${cacert_args[@]+"${cacert_args[@]}"} -p "$project" "$@"
|
|
500
505
|
}
|
|
501
506
|
|
|
502
507
|
logs_args() {
|
|
@@ -524,20 +529,19 @@ cacert_compose_args() {
|
|
|
524
529
|
local compose_file="$1"
|
|
525
530
|
local override_name="$2"
|
|
526
531
|
[[ -n "$CACERT_PATH" ]] || return 0
|
|
527
|
-
command -v node >/dev/null 2>&1 || die "--cacert requires node to generate Docker Compose overrides"
|
|
528
532
|
|
|
529
533
|
local services
|
|
530
534
|
services="$(
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
}
|
|
540
|
-
|
|
535
|
+
awk '
|
|
536
|
+
/^[[:space:]]*services:[[:space:]]*$/ { in_services=1; next }
|
|
537
|
+
in_services && /^[^[:space:]#]/ { exit }
|
|
538
|
+
in_services && /^ [A-Za-z0-9_.-]+:[[:space:]]*$/ {
|
|
539
|
+
line=$0
|
|
540
|
+
sub(/^ /, "", line)
|
|
541
|
+
sub(/:[[:space:]]*$/, "", line)
|
|
542
|
+
print line
|
|
543
|
+
}
|
|
544
|
+
' "$compose_file"
|
|
541
545
|
)"
|
|
542
546
|
[[ -n "$services" ]] || return 0
|
|
543
547
|
|
|
@@ -721,7 +725,7 @@ config_workspace() {
|
|
|
721
725
|
WIKI_SERVE_PORT="$serve_port" \
|
|
722
726
|
WIKI_MCP_PORT="$mcp_port" \
|
|
723
727
|
docker compose --project-directory "$DEFAULT_MANAGER_DIR" \
|
|
724
|
-
"${compose_env_args[@]}" -f "$ROOT_DIR/docker-compose.yml" "${cacert_args[@]}" run --rm wiki init
|
|
728
|
+
${compose_env_args[@]+"${compose_env_args[@]}"} -f "$ROOT_DIR/docker-compose.yml" ${cacert_args[@]+"${cacert_args[@]}"} run --rm wiki init
|
|
725
729
|
|
|
726
730
|
printf 'Workspace ready: %s\n' "$target_path"
|
|
727
731
|
printf 'Start with: wiki-workspace up %s\n' "$workspace"
|