@pellux/goodvibes-tui 1.7.0 → 1.9.1
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/CHANGELOG.md +11 -0
- package/README.md +10 -9
- package/docs/foundation-artifacts/operator-contract.json +4045 -1763
- package/package.json +2 -2
- package/src/audio/spoken-turn-controller.ts +12 -2
- package/src/audio/spoken-turn-wiring.ts +2 -1
- package/src/cli/help.ts +8 -1
- package/src/cli/service-posture.ts +2 -1
- package/src/cli/status.ts +2 -1
- package/src/cli/surface-command.ts +2 -2
- package/src/config/credential-availability.ts +122 -0
- package/src/config/index.ts +15 -0
- package/src/core/composer-state.ts +11 -3
- package/src/core/conversation-line-cache.ts +27 -3
- package/src/core/conversation-rendering.ts +71 -14
- package/src/core/stream-event-wiring.ts +20 -1
- package/src/core/system-message-noise.ts +87 -0
- package/src/core/system-message-router.ts +68 -1
- package/src/core/turn-cancellation.ts +7 -2
- package/src/core/turn-event-wiring.ts +10 -2
- package/src/daemon/cli.ts +29 -2
- package/src/daemon/handlers/register.ts +8 -1
- package/src/daemon/service-commands.ts +329 -0
- package/src/input/autocomplete.ts +27 -1
- package/src/input/command-registry.ts +46 -4
- package/src/input/commands/codebase-runtime.ts +46 -6
- package/src/input/commands/config.ts +43 -3
- package/src/input/commands/health-runtime.ts +9 -1
- package/src/input/commands/memory.ts +68 -35
- package/src/input/commands/operator-panel-runtime.ts +31 -7
- package/src/input/commands/planning-runtime.ts +95 -6
- package/src/input/commands/qrcode-runtime.ts +25 -5
- package/src/input/commands/remote-runtime-setup.ts +5 -3
- package/src/input/commands/session-content.ts +20 -9
- package/src/input/commands/settings-sync-runtime.ts +15 -3
- package/src/input/commands/shell-core.ts +10 -1
- package/src/input/commands/workstream-runtime.ts +168 -18
- package/src/input/config-modal-types.ts +15 -1
- package/src/input/config-modal.ts +227 -12
- package/src/input/feed-context-factory.ts +3 -0
- package/src/input/handler-command-route.ts +10 -3
- package/src/input/handler-content-actions.ts +17 -2
- package/src/input/handler-feed-routes.ts +43 -121
- package/src/input/handler-feed.ts +32 -4
- package/src/input/handler-modal-routes.ts +78 -13
- package/src/input/handler-modal-stack.ts +11 -2
- package/src/input/handler-onboarding-daemon-adopt.ts +149 -0
- package/src/input/handler-onboarding.ts +71 -59
- package/src/input/handler-picker-routes.ts +15 -8
- package/src/input/handler-shortcuts.ts +59 -9
- package/src/input/handler.ts +6 -1
- package/src/input/keybindings.ts +6 -5
- package/src/input/model-picker.ts +19 -2
- package/src/input/onboarding/onboarding-runtime-status.ts +10 -1
- package/src/input/onboarding/onboarding-wizard-apply.ts +8 -1
- package/src/input/onboarding/onboarding-wizard-constants.ts +4 -1
- package/src/input/onboarding/onboarding-wizard-network-adopt.ts +136 -0
- package/src/input/onboarding/onboarding-wizard-steps.ts +9 -6
- package/src/input/onboarding/onboarding-wizard-types.ts +3 -1
- package/src/input/panel-mouse-geometry.ts +97 -0
- package/src/input/panel-paste-flood-guard.ts +86 -0
- package/src/input/selection-modal.ts +11 -0
- package/src/input/session-picker-modal.ts +44 -4
- package/src/input/settings-modal-data.ts +51 -2
- package/src/input/settings-modal-types.ts +4 -2
- package/src/main.ts +28 -27
- package/src/panels/builtin/shared.ts +9 -3
- package/src/panels/fleet-deep-link.ts +31 -0
- package/src/panels/fleet-panel-format.ts +62 -0
- package/src/panels/fleet-panel-worktree-detail.ts +48 -0
- package/src/panels/fleet-panel.ts +89 -131
- package/src/panels/fleet-read-model.ts +43 -0
- package/src/panels/fleet-steer.ts +35 -2
- package/src/panels/fleet-stop.ts +29 -1
- package/src/panels/modals/keybindings-modal.ts +16 -1
- package/src/panels/modals/modal-theme.ts +35 -29
- package/src/panels/modals/pairing-modal.ts +25 -6
- package/src/panels/modals/planning-modal.ts +43 -21
- package/src/panels/modals/work-plan-modal.ts +28 -0
- package/src/panels/panel-manager.ts +15 -4
- package/src/panels/polish-core.ts +38 -25
- package/src/panels/project-planning-answer-actions.ts +8 -13
- package/src/panels/types.ts +24 -0
- package/src/permissions/prompt.ts +160 -13
- package/src/renderer/autocomplete-overlay.ts +28 -2
- package/src/renderer/compositor.ts +2 -3
- package/src/renderer/config-modal.ts +19 -5
- package/src/renderer/footer-tips.ts +5 -1
- package/src/renderer/fullscreen-primitives.ts +32 -22
- package/src/renderer/git-status.ts +3 -1
- package/src/renderer/layout.ts +0 -4
- package/src/renderer/markdown.ts +7 -3
- package/src/renderer/modal-factory.ts +25 -20
- package/src/renderer/model-workspace.ts +18 -3
- package/src/renderer/overlay-box.ts +21 -17
- package/src/renderer/process-indicator.ts +14 -3
- package/src/renderer/selection-modal-overlay.ts +6 -1
- package/src/renderer/session-picker-modal.ts +196 -3
- package/src/renderer/settings-modal-helpers.ts +2 -0
- package/src/renderer/settings-modal.ts +7 -0
- package/src/renderer/shell-surface.ts +8 -1
- package/src/renderer/status-glyphs.ts +14 -15
- package/src/renderer/system-message.ts +15 -3
- package/src/renderer/terminal-bg-probe.ts +339 -0
- package/src/renderer/terminal-escapes.ts +20 -0
- package/src/renderer/theme-mode-config.ts +67 -0
- package/src/renderer/theme.ts +91 -1
- package/src/renderer/thinking.ts +11 -3
- package/src/renderer/tool-call.ts +15 -9
- package/src/renderer/tool-result-summary.ts +148 -0
- package/src/renderer/turn-injection.ts +22 -3
- package/src/renderer/ui-factory.ts +154 -85
- package/src/renderer/ui-primitives.ts +30 -129
- package/src/runtime/bootstrap-command-context.ts +6 -0
- package/src/runtime/bootstrap-command-parts.ts +8 -4
- package/src/runtime/bootstrap-core.ts +46 -24
- package/src/runtime/bootstrap-hook-bridge.ts +7 -0
- package/src/runtime/bootstrap-shell.ts +19 -1
- package/src/runtime/bootstrap.ts +118 -5
- package/src/runtime/code-index-services.ts +25 -2
- package/src/runtime/legacy-daemon-migration.ts +516 -0
- package/src/runtime/memory-fold.ts +55 -0
- package/src/runtime/onboarding/derivation.ts +7 -2
- package/src/runtime/onboarding/snapshot.ts +27 -1
- package/src/runtime/onboarding/types.ts +31 -1
- package/src/runtime/operator-token-cleanup.ts +82 -1
- package/src/runtime/orchestrator-core-services.ts +10 -0
- package/src/runtime/resume-notice.ts +209 -0
- package/src/runtime/services.ts +12 -8
- package/src/runtime/session-inbound-inputs.ts +252 -0
- package/src/runtime/session-spine-transport.ts +64 -0
- package/src/runtime/terminal-output-guard.ts +15 -8
- package/src/runtime/ui-services.ts +19 -3
- package/src/runtime/workstream-services.ts +160 -28
- package/src/runtime/wrfc-persistence.ts +124 -17
- package/src/shell/blocking-input.ts +46 -3
- package/src/shell/recovery-input-helpers.ts +170 -1
- package/src/shell/ui-openers.ts +42 -9
- package/src/utils/terminal-width.ts +52 -0
- package/src/version.ts +1 -1
package/src/runtime/bootstrap.ts
CHANGED
|
@@ -36,12 +36,16 @@ import {
|
|
|
36
36
|
import { scheduleBackgroundMcpDiscovery, startBackgroundProviderRegistration } from '@/runtime/index.ts';
|
|
37
37
|
import { restoreSavedModel } from '@/runtime/index.ts';
|
|
38
38
|
import { startExternalServices, type ExternalServicesHandle, type HostServiceStatus } from '@/runtime/index.ts';
|
|
39
|
-
import {
|
|
40
|
-
import {
|
|
39
|
+
import { createHttpTransport } from '@/runtime/index.ts';
|
|
40
|
+
import { foldLegacySpineStore, deriveSpineFooterStatus } from '@pellux/goodvibes-sdk/platform/runtime/session-spine';
|
|
41
|
+
import { createTuiSpineTransport, type SpineSessionsClient } from './session-spine-transport.ts';
|
|
42
|
+
import { pruneStaleOperatorTokens } from '@pellux/goodvibes-sdk/platform/pairing';
|
|
43
|
+
import { resolveDaemonCompanionToken, workspaceOperatorTokenCandidates } from './operator-token-cleanup.ts';
|
|
41
44
|
import type { UiRuntimeServices } from './ui-services.ts';
|
|
42
45
|
import { createDeferredStartupCoordinator } from '@/runtime/index.ts';
|
|
43
46
|
import { initializeBootstrapCore } from './bootstrap-core.ts';
|
|
44
47
|
import { createBootstrapShell } from './bootstrap-shell.ts';
|
|
48
|
+
import { announceResumeState } from './resume-notice.ts';
|
|
45
49
|
import { buildSharedOrchestratorCoreServices } from './orchestrator-core-services.ts';
|
|
46
50
|
import { summarizeError } from '@pellux/goodvibes-sdk/platform/utils';
|
|
47
51
|
import { DaemonServer } from '@pellux/goodvibes-sdk/platform/daemon';
|
|
@@ -183,6 +187,9 @@ export async function bootstrapRuntime(
|
|
|
183
187
|
setRenderRequest,
|
|
184
188
|
runtimeSessionIdRef,
|
|
185
189
|
wrfcPersistence,
|
|
190
|
+
sessionSpine,
|
|
191
|
+
sessionInboundInputs,
|
|
192
|
+
sessionUnionCache,
|
|
186
193
|
} = await initializeBootstrapCore(stdout, options, (limit) => controlPlaneRecentEventsRef.value(limit));
|
|
187
194
|
const providerRegistry = services.providerRegistry;
|
|
188
195
|
const {
|
|
@@ -192,6 +199,11 @@ export async function bootstrapRuntime(
|
|
|
192
199
|
pluginManager,
|
|
193
200
|
} = services;
|
|
194
201
|
|
|
202
|
+
// D4b: a liveness flip is only PAINTED once something calls requestRender();
|
|
203
|
+
// without this, the footer's spine segment sat correct-but-undrawn until
|
|
204
|
+
// incidental activity redrew it (minutes, during an idle stretch).
|
|
205
|
+
sessionUnionCache.setOnTransition(() => requestRender());
|
|
206
|
+
|
|
195
207
|
// ── Phase 6: Orchestrator + AcpManager ───────────────────────────────────
|
|
196
208
|
|
|
197
209
|
// Mutable function refs so main.ts can patch these after constructing the scroll/viewport state.
|
|
@@ -262,6 +274,7 @@ export async function bootstrapRuntime(
|
|
|
262
274
|
runtimeBus,
|
|
263
275
|
runtimeStore: store,
|
|
264
276
|
services,
|
|
277
|
+
sessionSpine,
|
|
265
278
|
conversation,
|
|
266
279
|
runtime,
|
|
267
280
|
orchestrator,
|
|
@@ -287,6 +300,25 @@ export async function bootstrapRuntime(
|
|
|
287
300
|
wrfcPersistence.rehydrate();
|
|
288
301
|
const commandRegistry = shell.commandRegistry;
|
|
289
302
|
const commandContext = shell.commandContext;
|
|
303
|
+
// Boot resume notice (UX-D item 1): after rehydrate() so chain history is
|
|
304
|
+
// ready, before the operator can type anything. Fire-and-forget — the
|
|
305
|
+
// checkpoint-count lookup is async (WorkspaceCheckpointManager.list() awaits
|
|
306
|
+
// its own init()), and this must not block the rest of bootstrap the way
|
|
307
|
+
// main.ts's `void workspaceCheckpointManager.init().catch(() => {})`
|
|
308
|
+
// deliberately doesn't either. Local file I/O only; resolves well before a
|
|
309
|
+
// human can react to the first rendered frame.
|
|
310
|
+
void announceResumeState({
|
|
311
|
+
workingDirectory: services.workingDirectory,
|
|
312
|
+
homeDirectory: services.homeDirectory,
|
|
313
|
+
surfaceRoot: 'tui',
|
|
314
|
+
sessionManager: services.sessionManager,
|
|
315
|
+
checkpointManager: services.workspaceCheckpointManager,
|
|
316
|
+
chainHistory: wrfcPersistence.knownChains,
|
|
317
|
+
memoryAvailable: Boolean(commandContext.clients?.knowledgeApi?.memory),
|
|
318
|
+
router: systemMessageRouter,
|
|
319
|
+
}).catch(() => {
|
|
320
|
+
// Best-effort — never let the resume notice block or crash boot.
|
|
321
|
+
});
|
|
290
322
|
const gitStatusProvider = shell.gitStatusProvider;
|
|
291
323
|
const inputHistory = shell.inputHistory;
|
|
292
324
|
const lastGitInfoRef = shell.lastGitInfoRef;
|
|
@@ -343,7 +375,70 @@ export async function bootstrapRuntime(
|
|
|
343
375
|
|
|
344
376
|
const hostServiceIsActive = (status: HostServiceStatus): boolean => status.mode === 'embedded' || status.mode === 'external';
|
|
345
377
|
|
|
346
|
-
|
|
378
|
+
// 'blocked' (occupied by an unverified process) and 'incompatible' (occupied
|
|
379
|
+
// by a GoodVibes daemon we refused to adopt on a wire-version mismatch) both
|
|
380
|
+
// mean the configured port is held and unusable by this TUI instance.
|
|
381
|
+
const hostServiceIsBlocked = (status: HostServiceStatus): boolean => status.mode === 'blocked' || status.mode === 'incompatible';
|
|
382
|
+
|
|
383
|
+
// PERMANENT DESIGN (docs/decisions/2026-07-06-session-spine-mode-branch-is-permanent.md):
|
|
384
|
+
// 'embedded'/'external' are two distinct, both-supported daemon topologies, not
|
|
385
|
+
// migration stages — the ONE client-selection point for the session spine, driven by
|
|
386
|
+
// the SAME authoritative HostServiceMode adopt-or-start already computed above.
|
|
387
|
+
// 'embedded' (daemon.embedInProcess=true) means THIS process's own SharedSessionBroker
|
|
388
|
+
// already IS the daemon's broker — nothing to mirror TO, so the spine stays
|
|
389
|
+
// permanently dormant. Every other mode ('disabled'/'blocked'/'incompatible'/
|
|
390
|
+
// 'unavailable') also stays local-only and honest. Only 'external' (a separately-
|
|
391
|
+
// running daemon this TUI adopted) activates the wire mirror.
|
|
392
|
+
let spineActiveForBaseUrl: string | null = null;
|
|
393
|
+
const syncSessionSpineToHostStatus = (daemonStatus: HostServiceStatus, sharedDaemonToken: string): void => {
|
|
394
|
+
if (daemonStatus.mode !== 'external') {
|
|
395
|
+
if (spineActiveForBaseUrl !== null) {
|
|
396
|
+
sessionSpine.deactivate(`daemon mode changed to '${daemonStatus.mode}'`);
|
|
397
|
+
sessionInboundInputs.deactivate(`daemon mode changed to '${daemonStatus.mode}'`);
|
|
398
|
+
spineActiveForBaseUrl = null;
|
|
399
|
+
}
|
|
400
|
+
// Keep the read facade honest per topology (permanent, not staged): 'embedded'
|
|
401
|
+
// means this process's broker IS the daemon's broker (local reads are the whole
|
|
402
|
+
// truth); every other non-external mode is local-only/dormant.
|
|
403
|
+
if (daemonStatus.mode === 'embedded') sessionUnionCache.markEmbedded();
|
|
404
|
+
else sessionUnionCache.deactivate(`daemon mode '${daemonStatus.mode}'`);
|
|
405
|
+
logger.info(`[bootstrap] session spine: daemon mode '${daemonStatus.mode}' — local-only (no spine mirror)`);
|
|
406
|
+
return;
|
|
407
|
+
}
|
|
408
|
+
const baseUrl = daemonStatus.baseUrl;
|
|
409
|
+
if (spineActiveForBaseUrl === baseUrl) return; // already wired to this exact adopted daemon
|
|
410
|
+
const httpTransport = createHttpTransport({ baseUrl, authToken: sharedDaemonToken });
|
|
411
|
+
const sessionsClient: SpineSessionsClient = {
|
|
412
|
+
register: (input) => httpTransport.operator.sessions.register(input),
|
|
413
|
+
close: (sessionId) => httpTransport.operator.sessions.close(sessionId),
|
|
414
|
+
};
|
|
415
|
+
sessionSpine.activate(createTuiSpineTransport(sessionsClient));
|
|
416
|
+
// D3: adopt the same daemon's wire for the INBOUND steer path — collect
|
|
417
|
+
// steer/follow-up inputs another live surface queued for this session and
|
|
418
|
+
// inject them into the turn machinery (acking delivery on the wire).
|
|
419
|
+
sessionInboundInputs.activate({
|
|
420
|
+
listInputs: async (sessionId, opts) => ({
|
|
421
|
+
inputs: await httpTransport.operator.sessions.inputs(sessionId, opts.limit, { state: opts.state, since: opts.since }),
|
|
422
|
+
}),
|
|
423
|
+
deliverInput: (sessionId, inputId, opts) => httpTransport.operator.sessions.deliverInput(sessionId, inputId, opts),
|
|
424
|
+
});
|
|
425
|
+
// 'external' only: adopt the same daemon's wire as the read facade's cross-surface
|
|
426
|
+
// union source (interval-refreshed; served synchronously to panels).
|
|
427
|
+
sessionUnionCache.activate({ list: (limit) => httpTransport.operator.sessions.list(limit) });
|
|
428
|
+
spineActiveForBaseUrl = baseUrl;
|
|
429
|
+
logger.info(`[bootstrap] session spine: adopted external daemon at ${baseUrl} — mirroring session identity`);
|
|
430
|
+
// Legacy fold: one-time (marker-guarded) import of this project's own
|
|
431
|
+
// pre-spine control-plane sessions.json into the now-adopted daemon.
|
|
432
|
+
const legacyStorePath = services.shellPaths.resolveProjectPath('tui', 'control-plane', 'sessions.json');
|
|
433
|
+
const fold = foldLegacySpineStore(sessionSpine, {
|
|
434
|
+
storePath: legacyStorePath,
|
|
435
|
+
markerPath: `${legacyStorePath}.spine-migrated`,
|
|
436
|
+
project: services.workingDirectory,
|
|
437
|
+
});
|
|
438
|
+
if (fold.folded > 0) {
|
|
439
|
+
logger.info(`[bootstrap] session spine: folded ${fold.folded} legacy local session(s) into the adopted daemon`);
|
|
440
|
+
}
|
|
441
|
+
};
|
|
347
442
|
|
|
348
443
|
const inspectExternalServices = () => {
|
|
349
444
|
const daemonStatus = externalServices.daemonStatus;
|
|
@@ -355,6 +450,16 @@ export async function bootstrapRuntime(
|
|
|
355
450
|
httpListenerPortInUse: hostServiceIsBlocked(httpListenerStatus),
|
|
356
451
|
daemonStatus,
|
|
357
452
|
httpListenerStatus,
|
|
453
|
+
// Honest session-spine posture, independent of daemonRunning —
|
|
454
|
+
// 'external'-adopted-but-currently-unreachable degrades to 'offline' here
|
|
455
|
+
// even though daemonRunning might still read true from a stale handle.
|
|
456
|
+
// D4: sessionSpine.status() alone is ACTIVITY-gated (only updates on a
|
|
457
|
+
// register/heartbeat/close), so after the daemon dies mid-idle it would
|
|
458
|
+
// keep reading 'online'. Derive the footer status from the union cache's
|
|
459
|
+
// 5s liveness probe too — one signal, no new timer — so offline surfaces
|
|
460
|
+
// within one refresh interval of the daemon dying.
|
|
461
|
+
sessionSpineActive: sessionSpine.active,
|
|
462
|
+
sessionSpineStatus: deriveSpineFooterStatus(sessionSpine.status(), sessionUnionCache.crossSurfaceView),
|
|
358
463
|
};
|
|
359
464
|
};
|
|
360
465
|
|
|
@@ -413,7 +518,7 @@ export async function bootstrapRuntime(
|
|
|
413
518
|
await waitForConfigDrivenRestarts(externalServices);
|
|
414
519
|
await externalServices.stop();
|
|
415
520
|
const daemonHomeDir = join(services.homeDirectory, '.goodvibes', 'daemon');
|
|
416
|
-
const companionTokenRecord =
|
|
521
|
+
const companionTokenRecord = resolveDaemonCompanionToken(daemonHomeDir);
|
|
417
522
|
externalServicesPromise = startExternalServices(
|
|
418
523
|
configManager,
|
|
419
524
|
runtimeBus,
|
|
@@ -423,6 +528,7 @@ export async function bootstrapRuntime(
|
|
|
423
528
|
);
|
|
424
529
|
externalServices = await externalServicesPromise;
|
|
425
530
|
controlPlaneRecentEventsRef.value = (limit) => externalServices.listRecentControlPlaneEvents(limit);
|
|
531
|
+
syncSessionSpineToHostStatus(externalServices.daemonStatus, companionTokenRecord.token);
|
|
426
532
|
requestRender();
|
|
427
533
|
return inspectExternalServices();
|
|
428
534
|
},
|
|
@@ -461,7 +567,7 @@ export async function bootstrapRuntime(
|
|
|
461
567
|
// bearer, so tokens scanned from the /qrcode panel's QR actually
|
|
462
568
|
// authenticate against the embedded daemon this surface starts.
|
|
463
569
|
const daemonHomeDir = join(services.homeDirectory, '.goodvibes', 'daemon');
|
|
464
|
-
const companionTokenRecord =
|
|
570
|
+
const companionTokenRecord = resolveDaemonCompanionToken(daemonHomeDir);
|
|
465
571
|
// F3 resolution (TUI 0.19.20): remove stale pre-0.21.28 workspace-scoped operator
|
|
466
572
|
// token files so only the canonical <daemonHomeDir>/operator-tokens.json survives.
|
|
467
573
|
// The prune is best-effort — it silently skips missing files, no-ops when tokens
|
|
@@ -486,6 +592,7 @@ export async function bootstrapRuntime(
|
|
|
486
592
|
);
|
|
487
593
|
externalServices = await externalServicesPromise;
|
|
488
594
|
controlPlaneRecentEventsRef.value = (limit) => externalServices.listRecentControlPlaneEvents(limit);
|
|
595
|
+
syncSessionSpineToHostStatus(externalServices.daemonStatus, companionTokenRecord.token);
|
|
489
596
|
requestRender();
|
|
490
597
|
},
|
|
491
598
|
onError: (error) => {
|
|
@@ -630,6 +737,12 @@ export async function bootstrapRuntime(
|
|
|
630
737
|
runtimeUnsubs.forEach((fn) => fn());
|
|
631
738
|
runtimeUnsubs.length = 0;
|
|
632
739
|
forensicsCollector.dispose();
|
|
740
|
+
// Honest close on exit — fire-and-forget (never blocks shutdown);
|
|
741
|
+
// a no-op when the spine was never activated (embedded/local-only topology).
|
|
742
|
+
sessionSpine.close(runtime.sessionId);
|
|
743
|
+
sessionSpine.dispose();
|
|
744
|
+
sessionInboundInputs.dispose(); // D3: stop the inbound steer poll interval on exit
|
|
745
|
+
sessionUnionCache.dispose(); // stop the wire-refresh interval on exit
|
|
633
746
|
await deferredStartup.drain(100);
|
|
634
747
|
if (externalServicesPromise) {
|
|
635
748
|
try {
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
// ---------------------------------------------------------------------------
|
|
39
39
|
|
|
40
40
|
import { join } from 'node:path';
|
|
41
|
-
import { CodeIndexStore } from '@pellux/goodvibes-sdk/platform/state';
|
|
41
|
+
import { CodeIndexStore, CodeIndexReindexScheduler } from '@pellux/goodvibes-sdk/platform/state';
|
|
42
42
|
import type { MemoryEmbeddingProviderRegistry } from '@pellux/goodvibes-sdk/platform/state';
|
|
43
43
|
import type { ConfigKey, ConfigManager } from '@pellux/goodvibes-sdk/platform/config';
|
|
44
44
|
import { readBooleanConfig } from '../core/alert-gating.ts';
|
|
@@ -67,8 +67,26 @@ export interface CodeIndexServicesDeps {
|
|
|
67
67
|
readonly memoryEmbeddingRegistry: MemoryEmbeddingProviderRegistry;
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
+
/**
|
|
71
|
+
* Whether Stage B code auto-injection / tool-site reindex may run: the SAME
|
|
72
|
+
* storage.codeIndexEnabled switch that gates auto-build. Read live so a runtime
|
|
73
|
+
* /config toggle takes effect without restart. (The separate, default-off
|
|
74
|
+
* `agent-passive-code-injection` feature flag gates injection additionally; this
|
|
75
|
+
* is only the storage-side setting the SDK asks embedders to respect.)
|
|
76
|
+
*/
|
|
77
|
+
export function isCodeInjectionSettingEnabled(configManager: Pick<ConfigManager, 'get'>): boolean {
|
|
78
|
+
return isCodeIndexAutoStartEnabled(configManager);
|
|
79
|
+
}
|
|
80
|
+
|
|
70
81
|
export interface CodeIndexServices {
|
|
71
82
|
readonly codeIndexStore: CodeIndexStore;
|
|
83
|
+
/**
|
|
84
|
+
* Wave-5 Stage B tool-site incremental reindex scheduler, bound to codeIndexStore and
|
|
85
|
+
* gated live on storage.codeIndexEnabled. Threaded into both SDK orchestrators (main +
|
|
86
|
+
* agent) so a successful write/edit debounces an incremental reindex, and into the command
|
|
87
|
+
* context so /codebase status can report the last reindex activity honestly.
|
|
88
|
+
*/
|
|
89
|
+
readonly codeIndexReindexScheduler: CodeIndexReindexScheduler;
|
|
72
90
|
}
|
|
73
91
|
|
|
74
92
|
/** Absolute path to the TUI's code-index sqlite file, sibling to memory.sqlite under .goodvibes/tui/. */
|
|
@@ -108,5 +126,10 @@ export function createCodeIndexServices(deps: CodeIndexServicesDeps): CodeIndexS
|
|
|
108
126
|
if (isCodeIndexAutoStartEnabled(deps.configManager)) {
|
|
109
127
|
codeIndexStore.scheduleBuild();
|
|
110
128
|
}
|
|
111
|
-
|
|
129
|
+
const codeIndexReindexScheduler = new CodeIndexReindexScheduler({
|
|
130
|
+
target: codeIndexStore,
|
|
131
|
+
workingDirectory: deps.workingDirectory,
|
|
132
|
+
isEnabled: () => isCodeInjectionSettingEnabled(deps.configManager),
|
|
133
|
+
});
|
|
134
|
+
return { codeIndexStore, codeIndexReindexScheduler };
|
|
112
135
|
}
|