@dotdrelle/wiki-manager 0.14.9 → 0.14.12

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
@@ -13,6 +13,7 @@ import { buildMcpStatus } from '../core/mcp.js';
13
13
  import { loadWikircProfile, summarizeWikircConfig } from '../core/wikirc.js';
14
14
  import { listWorkspaces } from '../core/workspaces.js';
15
15
  import { postRuntimeShutdown } from '../runtime/client.js';
16
+ import { runPreflightChecks, withRuntimePreflight } from '../core/startupCheck.js';
16
17
 
17
18
  const SPINNER_FRAMES = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
18
19
 
@@ -103,6 +104,7 @@ function App(props: {
103
104
  agent: unknown;
104
105
  packageJson: Record<string, unknown>;
105
106
  runtime?: any;
107
+ preflight?: any;
106
108
  }) {
107
109
  const renderer = useRenderer();
108
110
  const dimensions = useTerminalDimensions();
@@ -115,6 +117,8 @@ function App(props: {
115
117
  // that invariant structural instead of relying on two booleans staying in
116
118
  // sync at every call site.
117
119
  const [screen, setScreen] = createSignal<'startup' | 'setup' | 'main'>('startup');
120
+ const [preflight, setPreflight] = createSignal(props.preflight ?? { status: 'degraded', checks: [] });
121
+ const [preflightBusy, setPreflightBusy] = createSignal(false);
118
122
  let ctrlCTimer: ReturnType<typeof setTimeout> | null = null;
119
123
  let exiting = false;
120
124
  // Single exit path: the owned-runtime shutdown MUST happen here, on the
@@ -185,6 +189,13 @@ function App(props: {
185
189
  // closeSetup() already does.
186
190
  const loadDefaultWorkspace = async () => loadWorkspace(startupInfo(props.packageJson).workspaceName);
187
191
 
192
+ // The canonical status is the first useful view after entering ShellUI.
193
+ // Run it only after /use has established the workspace so config, services,
194
+ // MCP connectivity and runtime state are all reported in the same snapshot.
195
+ const showDefaultStatus = async (workspaceLoaded: boolean) => {
196
+ if (workspaceLoaded) await state.submitInput('/status');
197
+ };
198
+
188
199
  // "Open a workspace" is really one composite action (load it, then bring
189
200
  // its services up) — named here so it has one definition instead of being
190
201
  // inlined as three sequential submitInput calls in openAction.
@@ -197,18 +208,60 @@ function App(props: {
197
208
  return loaded;
198
209
  };
199
210
 
211
+ const refreshPreflight = async () => {
212
+ setPreflightBusy(true);
213
+ try {
214
+ const next = await runPreflightChecks();
215
+ setPreflight(withRuntimePreflight(next, props.runtime));
216
+ } finally {
217
+ setPreflightBusy(false);
218
+ }
219
+ };
220
+
200
221
  const openAction = (action: StartupAction, workspaceName?: string) => {
201
222
  if (action === 'init-workspace') {
202
223
  setScreen('setup');
203
224
  return;
204
225
  }
226
+ if (action === 'retry-preflight') {
227
+ void refreshPreflight();
228
+ return;
229
+ }
230
+ if (action === 'start-services') {
231
+ void (async () => {
232
+ setPreflightBusy(true);
233
+ try {
234
+ await openWorkspaceAndStartServices(workspaceName ?? startupInfo(props.packageJson).workspaceName);
235
+ const next = await runPreflightChecks();
236
+ setPreflight(withRuntimePreflight(next, props.runtime));
237
+ } finally {
238
+ setPreflightBusy(false);
239
+ }
240
+ })();
241
+ return;
242
+ }
243
+ if (action === 'open-logs') {
244
+ setScreen('main');
245
+ void (async () => {
246
+ const loaded = await loadDefaultWorkspace();
247
+ if (!loaded) return;
248
+ const containerCheck = preflight().checks?.find((check: any) => check.kind === 'containers');
249
+ const service = containerCheck?.context?.unavailable?.[0];
250
+ if (service) await state.submitInput(`/logs ${service} 120`);
251
+ else await state.submitInput('/services');
252
+ await state.submitInput('/mcp status');
253
+ })();
254
+ return;
255
+ }
205
256
  setScreen('main');
206
257
  void (async () => {
207
258
  try {
208
259
  if (action === 'open-workspace') {
209
- await openWorkspaceAndStartServices(workspaceName ?? startupInfo(props.packageJson).workspaceName);
260
+ const loaded = await openWorkspaceAndStartServices(workspaceName ?? startupInfo(props.packageJson).workspaceName);
261
+ await showDefaultStatus(loaded);
210
262
  } else if (action === 'new-conversation' || action === 'run-workflow') {
211
263
  const loaded = await loadDefaultWorkspace();
264
+ await showDefaultStatus(loaded);
212
265
  if (action === 'run-workflow' && loaded) {
213
266
  await state.submitInput('/agent');
214
267
  }
@@ -230,7 +283,7 @@ function App(props: {
230
283
  setScreen('main');
231
284
  // Reuse loadWorkspace (not a bare /use dispatch) so the "already on this
232
285
  // workspace" short-circuit applies here too.
233
- void loadWorkspace(info.workspaceName);
286
+ void loadWorkspace(info.workspaceName).then(showDefaultStatus);
234
287
  };
235
288
 
236
289
  const showCopyHint = (message: string) => {
@@ -397,6 +450,8 @@ function App(props: {
397
450
  profileName={startup().profileName}
398
451
  workspaces={startup().workspaces}
399
452
  hasWorkspace={startup().hasWorkspace}
453
+ preflight={preflight()}
454
+ preflightBusy={preflightBusy()}
400
455
  width={dimensions().width}
401
456
  height={dimensions().height}
402
457
  keyboardEvent={startupKeyboardEvent()}
@@ -411,13 +466,15 @@ export async function runOpenTuiShell({
411
466
  agent,
412
467
  packageJson,
413
468
  runtime = null,
469
+ preflight = null,
414
470
  }: {
415
471
  agent: unknown;
416
472
  packageJson: Record<string, unknown>;
417
473
  runtime?: any;
474
+ preflight?: any;
418
475
  }) {
419
476
  await new Promise<void>((resolve, reject) => {
420
- render(() => <App agent={agent} packageJson={packageJson} runtime={runtime} />, {
477
+ render(() => <App agent={agent} packageJson={packageJson} runtime={runtime} preflight={preflight} />, {
421
478
  exitOnCtrlC: false,
422
479
  useMouse: true,
423
480
  targetFps: 30,
package/wiki-workspace CHANGED
@@ -773,23 +773,26 @@ cacert_compose_args() {
773
773
 
774
774
  mkdir -p "$MANAGER_RUNTIME_DIR"
775
775
  local override_path="$MANAGER_RUNTIME_DIR/$override_name"
776
- if [[ ! -f "$override_path" ]]; then
777
- {
778
- printf '# Generated by wiki-manager. Edit freely; delete to regenerate.\n'
779
- printf 'services:\n'
780
- while IFS= read -r service || [[ -n "$service" ]]; do
781
- [[ -n "$service" ]] || continue
782
- printf ' %s:\n' "$service"
783
- printf ' volumes:\n'
784
- printf ' - %s:/wiki-manager-ca.pem:ro\n' "$CACERT_PATH"
785
- printf ' environment:\n'
786
- printf ' NODE_EXTRA_CA_CERTS: /wiki-manager-ca.pem\n'
787
- printf ' SSL_CERT_FILE: /wiki-manager-ca.pem\n'
788
- printf ' REQUESTS_CA_BUNDLE: /wiki-manager-ca.pem\n'
789
- printf ' CURL_CA_BUNDLE: /wiki-manager-ca.pem\n'
790
- done <<< "$services"
791
- } > "$override_path"
792
- fi
776
+ local tmp_override="$override_path.tmp.$$"
777
+ {
778
+ printf '# Generated by wiki-manager. Changes are overwritten on the next compose command.\n'
779
+ printf 'services:\n'
780
+ while IFS= read -r service || [[ -n "$service" ]]; do
781
+ [[ -n "$service" ]] || continue
782
+ printf ' %s:\n' "$service"
783
+ printf ' volumes:\n'
784
+ printf ' - %s:/wiki-manager-ca.pem:ro\n' "$CACERT_PATH"
785
+ printf ' environment:\n'
786
+ printf ' NODE_EXTRA_CA_CERTS: /wiki-manager-ca.pem\n'
787
+ printf ' SSL_CERT_FILE: /wiki-manager-ca.pem\n'
788
+ printf ' REQUESTS_CA_BUNDLE: /wiki-manager-ca.pem\n'
789
+ printf ' CURL_CA_BUNDLE: /wiki-manager-ca.pem\n'
790
+ done <<< "$services"
791
+ } > "$tmp_override"
792
+ # Always replace generated state: package updates may add/remove services,
793
+ # and retaining an older override creates invalid phantom services (for
794
+ # example a removed optional mailer with no image in the current base file).
795
+ mv "$tmp_override" "$override_path"
793
796
  printf '%s\n' -f "$override_path"
794
797
  }
795
798