@pellux/goodvibes-tui 1.9.0 → 1.9.2
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 +24 -2
- package/README.md +1 -1
- package/package.json +1 -1
- package/src/audio/player.ts +91 -5
- package/src/audio/spoken-turn-controller.ts +30 -2
- package/src/audio/spoken-turn-wiring.ts +3 -0
- package/src/config/credential-availability.ts +122 -0
- package/src/config/index.ts +15 -0
- package/src/core/turn-cancellation.ts +1 -1
- package/src/daemon/cli.ts +4 -4
- package/src/daemon/service-commands.ts +8 -8
- package/src/input/command-registry.ts +5 -5
- package/src/input/commands/config.ts +1 -1
- package/src/input/commands/memory.ts +1 -1
- package/src/input/commands/planning-runtime.ts +1 -1
- package/src/input/commands/recall-review.ts +2 -2
- package/src/input/commands/session-content.ts +1 -1
- package/src/input/feed-context-factory.ts +1 -1
- package/src/input/handler-content-actions.ts +2 -2
- package/src/input/handler-feed-routes.ts +2 -2
- package/src/input/handler-feed.ts +1 -1
- package/src/input/handler-onboarding-daemon-adopt.ts +3 -3
- package/src/input/handler-picker-routes.ts +2 -2
- package/src/input/handler-shortcuts.ts +1 -1
- package/src/input/model-picker.ts +2 -2
- package/src/input/onboarding/onboarding-wizard-apply.ts +3 -3
- package/src/input/onboarding/onboarding-wizard-network-adopt.ts +3 -3
- package/src/input/onboarding/onboarding-wizard-steps.ts +1 -1
- package/src/input/session-picker-modal.ts +1 -1
- package/src/input/settings-modal-data.ts +2 -2
- package/src/main.ts +5 -4
- package/src/panels/base-panel.ts +1 -1
- package/src/panels/builtin/operations.ts +4 -4
- package/src/panels/builtin/shared.ts +1 -1
- package/src/panels/fleet-panel-format.ts +1 -1
- package/src/panels/fleet-panel.ts +15 -15
- package/src/panels/fleet-read-model.ts +11 -11
- package/src/panels/fleet-steer.ts +2 -2
- package/src/panels/fleet-stop.ts +2 -2
- package/src/panels/fleet-tabs.ts +4 -4
- package/src/panels/fleet-transcript.ts +5 -5
- package/src/panels/types.ts +1 -1
- package/src/renderer/compaction-quality.ts +1 -1
- package/src/renderer/fleet-tab-strip.ts +2 -2
- package/src/renderer/footer-tips.ts +1 -1
- package/src/renderer/model-workspace.ts +1 -1
- package/src/renderer/session-picker-modal.ts +4 -4
- package/src/renderer/shell-surface.ts +1 -1
- package/src/renderer/status-glyphs.ts +3 -3
- package/src/renderer/terminal-bg-probe.ts +1 -1
- package/src/renderer/theme.ts +2 -2
- package/src/renderer/turn-injection.ts +3 -3
- package/src/renderer/ui-factory.ts +7 -7
- package/src/renderer/ui-primitives.ts +3 -3
- package/src/runtime/bootstrap-core.ts +15 -15
- package/src/runtime/bootstrap-hook-bridge.ts +2 -2
- package/src/runtime/bootstrap-shell.ts +3 -3
- package/src/runtime/bootstrap.ts +5 -5
- package/src/runtime/code-index-services.ts +2 -2
- package/src/runtime/index.ts +11 -3
- package/src/runtime/legacy-daemon-migration.ts +9 -9
- package/src/runtime/memory-fold.ts +30 -1
- package/src/runtime/onboarding/snapshot.ts +3 -3
- package/src/runtime/onboarding/types.ts +2 -2
- package/src/runtime/operator-token-cleanup.ts +2 -2
- package/src/runtime/orchestrator-core-services.ts +2 -2
- package/src/runtime/process-lifecycle.ts +19 -5
- package/src/runtime/services.ts +14 -14
- package/src/runtime/session-inbound-inputs.ts +1 -1
- package/src/runtime/session-spine-transport.ts +2 -2
- package/src/runtime/ui-services.ts +1 -1
- package/src/runtime/workstream-services.ts +1 -1
- package/src/runtime/wrfc-persistence.ts +2 -2
- package/src/shell/ui-openers.ts +2 -2
- package/src/version.ts +1 -1
|
@@ -57,7 +57,7 @@ export interface ProcessLifecycleDeps {
|
|
|
57
57
|
readonly unsubs: ReadonlyArray<() => void>;
|
|
58
58
|
readonly getRecoveryInterval: () => ReturnType<typeof setInterval> | null;
|
|
59
59
|
readonly setRecoveryInterval: (value: ReturnType<typeof setInterval> | null) => void;
|
|
60
|
-
readonly getStopSpokenOutputForExit: () => (() => void) | null;
|
|
60
|
+
readonly getStopSpokenOutputForExit: () => (() => void | Promise<void>) | null;
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
export interface ProcessLifecycleHandlers {
|
|
@@ -153,7 +153,16 @@ export function installProcessLifecycle(deps: ProcessLifecycleDeps): ProcessLife
|
|
|
153
153
|
// must not re-run teardown or double-fire ctx.shutdown.
|
|
154
154
|
if (exiting) return;
|
|
155
155
|
exiting = true;
|
|
156
|
-
|
|
156
|
+
// Exit lets the spoken audio the user is already hearing finish inside a
|
|
157
|
+
// short bounded window (capped inside stopForExit, under the 3s shutdown
|
|
158
|
+
// budget below) while the rest of teardown proceeds; queued-but-unplayed
|
|
159
|
+
// speech is dropped. Deliberate interrupts (Ctrl+C, /tts stop) still cut
|
|
160
|
+
// instantly through controller.stop() before this path is ever reached.
|
|
161
|
+
let spokenOutputDrain: Promise<void> = Promise.resolve();
|
|
162
|
+
try {
|
|
163
|
+
spokenOutputDrain = Promise.resolve(getStopSpokenOutputForExit()?.()).then(() => undefined);
|
|
164
|
+
} catch { /* non-fatal to exit */ }
|
|
165
|
+
spokenOutputDrain = spokenOutputDrain.catch(() => undefined);
|
|
157
166
|
unsubs.forEach(fn => fn());
|
|
158
167
|
const interval = getRecoveryInterval();
|
|
159
168
|
if (interval !== null) { clearInterval(interval); setRecoveryInterval(null); }
|
|
@@ -169,9 +178,14 @@ export function installProcessLifecycle(deps: ProcessLifecycleDeps): ProcessLife
|
|
|
169
178
|
try {
|
|
170
179
|
// Race the graceful shutdown against a hard timeout — externalServices.stop() can hang
|
|
171
180
|
// and we must still exit; deferredStartup.drain only budgets 100ms internally.
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
181
|
+
// The spoken-audio drain runs concurrently and is internally capped below
|
|
182
|
+
// this budget, so it never extends the exit beyond the hard timeout.
|
|
183
|
+
await Promise.all([
|
|
184
|
+
spokenOutputDrain,
|
|
185
|
+
Promise.race([
|
|
186
|
+
ctx.shutdown({ ...snapshot, ...buildPersistedSessionContext(snapshot.messages, ctx.conversation.getTitleSource(), buildSessionContinuityHints()) }).then(() => { shutdownOk = true; }),
|
|
187
|
+
new Promise<void>((resolve) => setTimeout(resolve, 3000)),
|
|
188
|
+
]),
|
|
175
189
|
]);
|
|
176
190
|
} catch (err) {
|
|
177
191
|
logger.debug('ctx.shutdown error during exitApp (non-fatal)', { error: summarizeError(err) });
|
package/src/runtime/services.ts
CHANGED
|
@@ -222,12 +222,12 @@ export interface RuntimeServices {
|
|
|
222
222
|
readonly agentOrchestrator: AgentOrchestrator;
|
|
223
223
|
readonly wrfcController: WrfcController;
|
|
224
224
|
readonly processManager: ProcessManager;
|
|
225
|
-
/**
|
|
225
|
+
/** The phase/work-item orchestration engine — see runtime/workstream-services.ts. */
|
|
226
226
|
readonly orchestrationEngine: OrchestrationEngine;
|
|
227
227
|
readonly workstreamCommands: WorkstreamCommandService;
|
|
228
|
-
/**
|
|
228
|
+
/** The repo source-tree code index — see runtime/code-index-services.ts. */
|
|
229
229
|
readonly codeIndexStore: CodeIndexStore;
|
|
230
|
-
readonly codeIndexReindexScheduler: CodeIndexReindexScheduler; //
|
|
230
|
+
readonly codeIndexReindexScheduler: CodeIndexReindexScheduler; // tool-site reindex
|
|
231
231
|
/** W2.1/W2.2: unified live process registry (agents, WRFC chains, workflows, watchers, background processes) backing the Fleet panel. */
|
|
232
232
|
readonly processRegistry: ProcessRegistry;
|
|
233
233
|
readonly modeManager: ModeManager;
|
|
@@ -338,7 +338,7 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
|
|
|
338
338
|
executor: agentOrchestrator,
|
|
339
339
|
configManager,
|
|
340
340
|
});
|
|
341
|
-
agentOrchestrator.setConversationSink({ //
|
|
341
|
+
agentOrchestrator.setConversationSink({ // Conversation-snapshot bridge (mirrors the SDK's own createRuntimeServices)
|
|
342
342
|
register: (agentId, source) => agentManager.registerConversationSource(agentId, source),
|
|
343
343
|
release: (agentId) => agentManager.releaseConversationSource(agentId),
|
|
344
344
|
});
|
|
@@ -387,7 +387,7 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
|
|
|
387
387
|
});
|
|
388
388
|
const artifactStore = new ArtifactStore({ configManager });
|
|
389
389
|
const memoryEmbeddingRegistry = new MemoryEmbeddingProviderRegistry({ configManager });
|
|
390
|
-
//
|
|
390
|
+
// Open the ONE home-scoped canonical store; legacy per-project TUI memory folds in at boot (foldTuiLegacyMemory).
|
|
391
391
|
const memoryDbPath = resolveCanonicalMemoryDbPath(homeDirectory);
|
|
392
392
|
const memoryStore = new MemoryStore(memoryDbPath, {
|
|
393
393
|
embeddingRegistry: memoryEmbeddingRegistry,
|
|
@@ -595,18 +595,18 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
|
|
|
595
595
|
artifactStore,
|
|
596
596
|
});
|
|
597
597
|
const processManager = new ProcessManager();
|
|
598
|
-
//
|
|
598
|
+
// The phase/work-item orchestration engine, constructed
|
|
599
599
|
// before the process registry so its fleet nodes (workstream/phase/
|
|
600
600
|
// work-item) can be folded in below via the registry's optional
|
|
601
601
|
// orchestrationEngine dep.
|
|
602
602
|
const { orchestrationEngine, workstreamCommands } = createWorkstreamServices({
|
|
603
603
|
agentManager, configManager, adaptivePlanner, runtimeBus: options.runtimeBus, projectRoot: workingDirectory,
|
|
604
604
|
});
|
|
605
|
-
//
|
|
605
|
+
// Repo source-tree code index, sharing memoryEmbeddingRegistry
|
|
606
606
|
// with MemoryStore above. Auto-build is config-gated (default off) — see
|
|
607
607
|
// code-index-services.ts's header doc.
|
|
608
608
|
const { codeIndexStore, codeIndexReindexScheduler } = createCodeIndexServices({ workingDirectory, configManager, memoryEmbeddingRegistry });
|
|
609
|
-
const codeInjectionOrchestratorDeps = { codeIndex: codeIndexStore, isCodeInjectionSettingEnabled: () => isCodeInjectionSettingEnabled(configManager), codeIndexReindexScheduler }; //
|
|
609
|
+
const codeInjectionOrchestratorDeps = { codeIndex: codeIndexStore, isCodeInjectionSettingEnabled: () => isCodeInjectionSettingEnabled(configManager), codeIndexReindexScheduler }; // Code-injection seam (agent here; main via orchestrator-core-services.ts)
|
|
610
610
|
// W2.1/W2.2: one shared process registry aggregating the managers above —
|
|
611
611
|
// the Fleet panel (panels/fleet-read-model.ts) is its first consumer.
|
|
612
612
|
// Constructed once here (not per-consumer) so the coalesced tick and the
|
|
@@ -614,15 +614,15 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
|
|
|
614
614
|
const processRegistry = createProcessRegistry({
|
|
615
615
|
agentManager,
|
|
616
616
|
wrfcController,
|
|
617
|
-
orchestrationEngine, //
|
|
618
|
-
codeIndexService: codeIndexStore, //
|
|
617
|
+
orchestrationEngine, // Folds workstream/phase/work-item nodes into the fleet
|
|
618
|
+
codeIndexService: codeIndexStore, // Folds a single 'code-index' node into the fleet
|
|
619
619
|
processManager,
|
|
620
620
|
watcherRegistry,
|
|
621
621
|
workflow,
|
|
622
622
|
approvalBroker,
|
|
623
623
|
sessionBroker,
|
|
624
|
-
messageBus: agentMessageBus, //
|
|
625
|
-
automationManager, //
|
|
624
|
+
messageBus: agentMessageBus, // Backs steer()/`steerable` (the Fleet steer composer builds on top)
|
|
625
|
+
automationManager, // Folds /schedule AutomationJobs into the fleet as 'schedule' nodes
|
|
626
626
|
runtimeBus: options.runtimeBus,
|
|
627
627
|
// Honest pricing: never fabricate a cost for an unrecognized model.
|
|
628
628
|
priceUsage: (model, usage) => {
|
|
@@ -681,7 +681,7 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
|
|
|
681
681
|
remoteRunnerRegistry,
|
|
682
682
|
knowledgeService,
|
|
683
683
|
memoryRegistry,
|
|
684
|
-
...codeInjectionOrchestratorDeps, //
|
|
684
|
+
...codeInjectionOrchestratorDeps, // Agent-run code injection + tool-site reindex
|
|
685
685
|
archetypeLoader,
|
|
686
686
|
configManager,
|
|
687
687
|
providerRegistry,
|
|
@@ -790,7 +790,7 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
|
|
|
790
790
|
workspaceCheckpointManager,
|
|
791
791
|
integrationHelpers,
|
|
792
792
|
async rerootStores(newWorkingDir: string): Promise<void> {
|
|
793
|
-
//
|
|
793
|
+
// The memory store is the home-scoped canonical cross-surface store and
|
|
794
794
|
// deliberately does NOT reroot per-project (that would re-silo memory, the E6
|
|
795
795
|
// regression). Only working-tree-bound stores (code index, project index) reroot.
|
|
796
796
|
await codeIndexStore.reroot(newWorkingDir, codeIndexDbPath(newWorkingDir));
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* session-inbound-inputs.ts
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* Live-surface steer delivery (the inbound half of the
|
|
5
5
|
* session spine): the TUI's INBOUND path for steer/follow-up inputs that another
|
|
6
6
|
* live surface (e.g. the webui) queued against THIS TUI's session.
|
|
7
7
|
*
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* session-spine-transport.ts
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* The TUI session-spine cutover: the thin typed-client
|
|
5
5
|
* adapter that lets the TUI's bootstrap drive the SDK's
|
|
6
6
|
* `@pellux/goodvibes-sdk/platform/runtime/session-spine` `SessionSpineClient`
|
|
7
|
-
*
|
|
7
|
+
* via its injected `SpineTransport` seam.
|
|
8
8
|
*
|
|
9
9
|
* The TUI is SDK-clean here: `SpineSessionsClient` is exactly the narrow wire
|
|
10
10
|
* surface the old TUI-local `session-spine-client.ts` declared (structurally
|
|
@@ -114,7 +114,7 @@ export interface UiRuntimeSharedServices {
|
|
|
114
114
|
readonly remoteSupervisor: RuntimeServices['remoteSupervisor'] & RemoteSupervisor;
|
|
115
115
|
/** W2.2: the shared live process registry backing the Fleet panel. */
|
|
116
116
|
readonly processRegistry: RuntimeServices['processRegistry'];
|
|
117
|
-
/**
|
|
117
|
+
/** The shared runtime event bus — the Fleet panel subscribes to its 'communication' domain for the honest steer-consumed signal. */
|
|
118
118
|
readonly runtimeBus: RuntimeServices['runtimeBus'];
|
|
119
119
|
};
|
|
120
120
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// ---------------------------------------------------------------------------
|
|
2
|
-
// workstream-services.ts —
|
|
2
|
+
// workstream-services.ts — phase/work-item orchestration engine
|
|
3
3
|
//
|
|
4
4
|
// Constructs the TUI's OrchestrationEngine instance (@pellux/goodvibes-sdk/
|
|
5
5
|
// platform/orchestration, landed on SDK main as wo701/W4.1) and a thin
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
* additionally exposes the recovered set for inspection.
|
|
20
20
|
*
|
|
21
21
|
* A chain that looked interrupted (non-terminal) in the old snapshot can be
|
|
22
|
-
* reaped to terminal IN PLACE by `WrfcController.importChain` (
|
|
22
|
+
* reaped to terminal IN PLACE by `WrfcController.importChain` (the zombie-reap pass:
|
|
23
23
|
* no member agent survived the restart — see wrfc-controller.ts). This
|
|
24
24
|
* module always re-checks `chain.state` AFTER the import call, never the
|
|
25
25
|
* pre-import classification, so a reaped chain is treated as history, not
|
|
@@ -209,7 +209,7 @@ class WrfcPersistenceImpl implements WrfcPersistence {
|
|
|
209
209
|
// chain. The accessor is optional for read-only test doubles.
|
|
210
210
|
//
|
|
211
211
|
// NOTE: importChain may reap this chain to a terminal state IN PLACE
|
|
212
|
-
// (
|
|
212
|
+
// (zombie reap: no member agent survived the restart) —
|
|
213
213
|
// always read chain.state AFTER this call below, never the pre-import
|
|
214
214
|
// classification captured by candidateInterrupted.
|
|
215
215
|
this.controller.importChain?.(chain);
|
package/src/shell/ui-openers.ts
CHANGED
|
@@ -231,7 +231,7 @@ export function wireShellUiOpeners(options: WireShellUiOpenersOptions): void {
|
|
|
231
231
|
|
|
232
232
|
commandContext.openModelPicker = () => {
|
|
233
233
|
void (async () => {
|
|
234
|
-
//
|
|
234
|
+
// getSelectableModels() is catalog-driven and can list models whose
|
|
235
235
|
// `provider` id (e.g. 'google', sourced from the pricing catalog) was never
|
|
236
236
|
// handed to providerRegistry.register()/registerRuntimeProvider(). Selecting
|
|
237
237
|
// such a model fails hard at turn time with ProviderNotFoundError
|
|
@@ -264,7 +264,7 @@ export function wireShellUiOpeners(options: WireShellUiOpenersOptions): void {
|
|
|
264
264
|
|
|
265
265
|
commandContext.openProviderPicker = () => {
|
|
266
266
|
void (async () => {
|
|
267
|
-
//
|
|
267
|
+
// listModels() surfaces every catalog provider id, not just the ones
|
|
268
268
|
// actually registered on this runtime (see openModelPicker above for the
|
|
269
269
|
// same class of bug). Intersect against providerRegistry.has() so the
|
|
270
270
|
// provider picker never offers a provider that will fail with
|
package/src/version.ts
CHANGED
|
@@ -6,7 +6,7 @@ import { join } from 'node:path';
|
|
|
6
6
|
// The prebuild script updates the fallback value before compilation.
|
|
7
7
|
// Uses import.meta.dir (Bun) to locate package.json relative to this file,
|
|
8
8
|
// which is correct regardless of the process working directory.
|
|
9
|
-
let _version = '1.9.
|
|
9
|
+
let _version = '1.9.2';
|
|
10
10
|
try {
|
|
11
11
|
const pkg = JSON.parse(readFileSync(join(import.meta.dir, '..', 'package.json'), 'utf-8'));
|
|
12
12
|
_version = pkg.version ?? _version;
|