@pellux/goodvibes-tui 0.26.0 → 0.27.0
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 +17 -0
- package/README.md +12 -7
- package/docs/foundation-artifacts/operator-contract.json +4 -1
- package/package.json +2 -2
- package/src/cli/bundle-command.ts +2 -1
- package/src/cli/service-posture.ts +2 -1
- package/src/core/conversation-rendering.ts +2 -2
- package/src/core/conversation.ts +49 -2
- package/src/core/session-recovery.ts +24 -18
- package/src/core/system-message-router.ts +42 -26
- package/src/core/turn-event-wiring.ts +12 -16
- package/src/daemon/handlers/calendar/caldav-client.ts +2 -1
- package/src/daemon/handlers/inbox/index.ts +2 -1
- package/src/daemon/handlers/inbox/poller.ts +2 -1
- package/src/daemon/handlers/inbox/providers/discord.ts +2 -1
- package/src/daemon/handlers/inbox/providers/email.ts +2 -1
- package/src/daemon/handlers/inbox/providers/route-util.ts +2 -1
- package/src/daemon/handlers/inbox/providers/slack.ts +2 -1
- package/src/daemon/handlers/triage/integration.ts +2 -1
- package/src/daemon/handlers/triage/pipeline.ts +2 -1
- package/src/daemon/handlers/triage/tagger/discord.ts +2 -1
- package/src/daemon/handlers/triage/tagger/imap.ts +4 -3
- package/src/export/gist-uploader.ts +3 -1
- package/src/input/command-registry.ts +1 -0
- package/src/input/commands/cloudflare-runtime.ts +2 -1
- package/src/input/commands/guidance-runtime.ts +2 -4
- package/src/input/commands/health-runtime.ts +13 -7
- package/src/input/commands/knowledge.ts +2 -1
- package/src/input/commands/runtime-services.ts +40 -10
- package/src/input/handler-command-route.ts +1 -1
- package/src/input/handler-interactions.ts +2 -1
- package/src/input/handler-modal-routes.ts +2 -1
- package/src/input/handler-onboarding-cloudflare.ts +2 -1
- package/src/input/handler-onboarding.ts +8 -8
- package/src/input/handler-ui-state.ts +1 -1
- package/src/input/tts-settings-actions.ts +2 -1
- package/src/main.ts +52 -59
- package/src/panels/agent-inspector-panel.ts +72 -2
- package/src/panels/agent-logs-panel.ts +127 -19
- package/src/panels/base-panel.ts +2 -1
- package/src/panels/builtin/agent.ts +3 -1
- package/src/panels/builtin/development.ts +1 -0
- package/src/panels/builtin/session.ts +1 -1
- package/src/panels/context-visualizer-panel.ts +24 -14
- package/src/panels/cost-tracker-panel.ts +7 -13
- package/src/panels/debug-panel.ts +11 -22
- package/src/panels/docs-panel.ts +14 -24
- package/src/panels/file-explorer-panel.ts +2 -1
- package/src/panels/file-preview-panel.ts +2 -1
- package/src/panels/git-panel.ts +10 -17
- package/src/panels/marketplace-panel.ts +2 -1
- package/src/panels/memory-panel.ts +2 -1
- package/src/panels/project-planning-panel.ts +5 -4
- package/src/panels/provider-health-panel.ts +56 -67
- package/src/panels/schedule-panel.ts +4 -7
- package/src/panels/session-browser-panel.ts +13 -21
- package/src/panels/skills-panel.ts +2 -1
- package/src/panels/tasks-panel.ts +2 -7
- package/src/panels/thinking-panel.ts +6 -11
- package/src/panels/token-budget-panel.ts +31 -15
- package/src/panels/tool-inspector-panel.ts +10 -18
- package/src/panels/work-plan-panel.ts +2 -1
- package/src/panels/wrfc-panel.ts +37 -35
- package/src/renderer/agent-detail-modal.ts +2 -2
- package/src/renderer/modal-utils.ts +0 -10
- package/src/renderer/process-modal.ts +2 -2
- package/src/runtime/bootstrap-command-context.ts +3 -0
- package/src/runtime/bootstrap-command-parts.ts +3 -1
- package/src/runtime/bootstrap-core.ts +31 -31
- package/src/runtime/bootstrap-shell.ts +1 -0
- package/src/runtime/onboarding/apply.ts +4 -3
- package/src/runtime/onboarding/snapshot.ts +4 -3
- package/src/runtime/process-lifecycle.ts +195 -0
- package/src/runtime/services.ts +4 -1
- package/src/runtime/wrfc-persistence.ts +20 -5
- package/src/shell/ui-openers.ts +3 -2
- package/src/verification/live-verifier.ts +4 -3
- package/src/version.ts +1 -1
- package/src/core/context-auto-compact.ts +0 -110
|
@@ -10,10 +10,11 @@
|
|
|
10
10
|
*
|
|
11
11
|
* 2. `WrfcPersistence.rehydrate(router)` is called once on boot (after the
|
|
12
12
|
* SystemMessageRouter is available). It reads the snapshot, identifies
|
|
13
|
-
* chains that were in a non-terminal state at last write,
|
|
14
|
-
* high-priority 'wrfc' system message per interrupted chain
|
|
15
|
-
*
|
|
16
|
-
*
|
|
13
|
+
* chains that were in a non-terminal state at last write, emits a
|
|
14
|
+
* high-priority 'wrfc' system message per interrupted chain, and re-imports
|
|
15
|
+
* each interrupted chain into the WrfcController so it reappears as a panel
|
|
16
|
+
* row and can be resumed by the operator. The `interruptedChains` accessor
|
|
17
|
+
* additionally exposes the recovered set for inspection.
|
|
17
18
|
*
|
|
18
19
|
* 3. Snapshot lifecycle:
|
|
19
20
|
* - Terminal chains ('passed' | 'failed') are pruned from the snapshot
|
|
@@ -57,6 +58,14 @@ interface WrfcSnapshot {
|
|
|
57
58
|
/** Subset of WrfcController needed by this module. */
|
|
58
59
|
export interface WrfcControllerReader {
|
|
59
60
|
listChains(): WrfcChain[];
|
|
61
|
+
/**
|
|
62
|
+
* Re-import a chain recovered from a previous process so it reappears in the
|
|
63
|
+
* controller's in-memory map and becomes selectable/resumable from the panel.
|
|
64
|
+
* Optional so read-only test doubles can omit it; the real WrfcController
|
|
65
|
+
* provides it. `force` is left at its default — on a fresh start the map is
|
|
66
|
+
* empty so importing never clobbers a live chain.
|
|
67
|
+
*/
|
|
68
|
+
importChain?(chain: WrfcChain, force?: boolean): boolean;
|
|
60
69
|
}
|
|
61
70
|
|
|
62
71
|
export interface WrfcPersistenceOptions {
|
|
@@ -64,7 +73,7 @@ export interface WrfcPersistenceOptions {
|
|
|
64
73
|
readonly snapshotPath: string;
|
|
65
74
|
/** Factory for the current SystemMessageRouter — may return null before it is wired. */
|
|
66
75
|
readonly getSystemMessageRouter: () => SystemMessageRouter | null;
|
|
67
|
-
/** WrfcController
|
|
76
|
+
/** WrfcController access — listChains() (read) plus optional importChain() (re-import on rehydrate). */
|
|
68
77
|
readonly controller: WrfcControllerReader;
|
|
69
78
|
}
|
|
70
79
|
|
|
@@ -140,6 +149,12 @@ class WrfcPersistenceImpl implements WrfcPersistence {
|
|
|
140
149
|
|
|
141
150
|
const router = this.getSystemMessageRouter();
|
|
142
151
|
for (const chain of interrupted) {
|
|
152
|
+
// Re-import so the chain reappears in the controller's in-memory map and
|
|
153
|
+
// becomes selectable/resumable from the panel. On a fresh process start
|
|
154
|
+
// the map is empty, so importChain (force=false) never clobbers a live
|
|
155
|
+
// chain. The accessor is optional for read-only test doubles.
|
|
156
|
+
this.controller.importChain?.(chain);
|
|
157
|
+
|
|
143
158
|
const msg =
|
|
144
159
|
`[WRFC] Chain ${chain.id.slice(0, 12)} (${chain.task.slice(0, 60).trim()}) ` +
|
|
145
160
|
`was interrupted by a restart — state was '${chain.state}' ` +
|
package/src/shell/ui-openers.ts
CHANGED
|
@@ -13,6 +13,7 @@ import type { SecretsManager } from '@pellux/goodvibes-sdk/platform/config';
|
|
|
13
13
|
import type { ServiceInspectionQuery } from '../runtime/ui-service-queries.ts';
|
|
14
14
|
import type { ModelPickerTargetInfo } from '../input/model-picker.ts';
|
|
15
15
|
import { syncServiceSettingToPlatform } from './service-settings-sync.ts';
|
|
16
|
+
import { summarizeError } from '@pellux/goodvibes-sdk/platform/utils';
|
|
16
17
|
|
|
17
18
|
type WireShellUiOpenersOptions = {
|
|
18
19
|
commandContext: CommandContext;
|
|
@@ -203,7 +204,7 @@ export function wireShellUiOpeners(options: WireShellUiOpenersOptions): void {
|
|
|
203
204
|
input.modelPicker.openAllModels(models, getCurrentModelForPickerTarget());
|
|
204
205
|
render();
|
|
205
206
|
})().catch((error: unknown) => {
|
|
206
|
-
commandContext.print?.(`Model picker failed to open: ${
|
|
207
|
+
commandContext.print?.(`Model picker failed to open: ${summarizeError(error)}`);
|
|
207
208
|
render();
|
|
208
209
|
});
|
|
209
210
|
};
|
|
@@ -223,7 +224,7 @@ export function wireShellUiOpeners(options: WireShellUiOpenersOptions): void {
|
|
|
223
224
|
input.modelPicker.openProviders(providers, getCurrentProviderForPickerTarget());
|
|
224
225
|
render();
|
|
225
226
|
})().catch((error: unknown) => {
|
|
226
|
-
commandContext.print?.(`Provider picker failed to open: ${
|
|
227
|
+
commandContext.print?.(`Provider picker failed to open: ${summarizeError(error)}`);
|
|
227
228
|
render();
|
|
228
229
|
});
|
|
229
230
|
};
|
|
@@ -3,6 +3,7 @@ import { join, resolve } from 'node:path';
|
|
|
3
3
|
import { spawn } from 'node:child_process';
|
|
4
4
|
import { auditGoodVibesHome } from '../config/goodvibes-home-audit.ts';
|
|
5
5
|
import { buildVerificationLedger } from './verification-ledger.ts';
|
|
6
|
+
import { summarizeError } from '@pellux/goodvibes-sdk/platform/utils';
|
|
6
7
|
|
|
7
8
|
export type LiveVerificationStatus = 'pass' | 'warn' | 'fail' | 'skip';
|
|
8
9
|
|
|
@@ -111,7 +112,7 @@ function runCommand(command: string, args: string[], cwd: string, timeoutMs = 15
|
|
|
111
112
|
resolveCommand({
|
|
112
113
|
exitCode: -1,
|
|
113
114
|
stdout: '',
|
|
114
|
-
stderr:
|
|
115
|
+
stderr: summarizeError(error),
|
|
115
116
|
timedOut,
|
|
116
117
|
});
|
|
117
118
|
});
|
|
@@ -161,7 +162,7 @@ function commandCheck(
|
|
|
161
162
|
title,
|
|
162
163
|
status: 'fail',
|
|
163
164
|
summary: 'Command succeeded but did not return valid JSON.',
|
|
164
|
-
detail:
|
|
165
|
+
detail: summarizeError(error),
|
|
165
166
|
};
|
|
166
167
|
}
|
|
167
168
|
}
|
|
@@ -208,7 +209,7 @@ async function fetchCheck(
|
|
|
208
209
|
title,
|
|
209
210
|
status: 'fail',
|
|
210
211
|
summary: 'Request failed.',
|
|
211
|
-
detail:
|
|
212
|
+
detail: summarizeError(error),
|
|
212
213
|
};
|
|
213
214
|
}
|
|
214
215
|
}
|
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 = '0.
|
|
9
|
+
let _version = '0.27.0';
|
|
10
10
|
try {
|
|
11
11
|
const pkg = JSON.parse(readFileSync(join(import.meta.dir, '..', 'package.json'), 'utf-8'));
|
|
12
12
|
_version = pkg.version ?? _version;
|
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Auto-compaction helper — TASK-058.
|
|
3
|
-
*
|
|
4
|
-
* Evaluates whether auto-compact should run after a turn completes and, if so,
|
|
5
|
-
* triggers compaction and posts an honest transcript notice.
|
|
6
|
-
*
|
|
7
|
-
* behavior.autoCompactThreshold: SDK schema range [10, 100], default 80.
|
|
8
|
-
* Auto-compact is active whenever the threshold is in its valid range (>0).
|
|
9
|
-
* The display/suggestion path (hint + meter) is always active regardless.
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
import type { ConfigManager } from '@pellux/goodvibes-sdk/platform/config';
|
|
13
|
-
import type { ConversationManager } from './conversation';
|
|
14
|
-
import type { ProviderRegistry } from '@pellux/goodvibes-sdk/platform/providers';
|
|
15
|
-
import type { SystemMessageRouter } from './system-message-router';
|
|
16
|
-
import { logger } from '@pellux/goodvibes-sdk/platform/utils';
|
|
17
|
-
import { summarizeError } from '@pellux/goodvibes-sdk/platform/utils';
|
|
18
|
-
import { getLastCompactionEvent } from '@pellux/goodvibes-sdk/platform/core';
|
|
19
|
-
import type { CompactionContext } from '@pellux/goodvibes-sdk/platform/core';
|
|
20
|
-
import { buildCompactionPreview, buildCompactionAfterNotice } from '../renderer/compaction-preview.ts';
|
|
21
|
-
|
|
22
|
-
export interface AutoCompactDeps {
|
|
23
|
-
readonly configManager: Pick<ConfigManager, 'get'>;
|
|
24
|
-
readonly conversation: ConversationManager;
|
|
25
|
-
readonly providerRegistry: ProviderRegistry;
|
|
26
|
-
readonly systemMessageRouter: SystemMessageRouter;
|
|
27
|
-
readonly model: string;
|
|
28
|
-
readonly provider: string;
|
|
29
|
-
readonly lastInputTokens: number;
|
|
30
|
-
readonly contextWindow: number;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Run after each TURN_COMPLETED event.
|
|
35
|
-
*
|
|
36
|
-
* Reads behavior.autoCompactThreshold from config (SDK default: 80, range [10, 100]).
|
|
37
|
-
* When usage is at or above the threshold, compacts the conversation and posts
|
|
38
|
-
* an honest transcript notice so the user understands any summary discontinuity.
|
|
39
|
-
*
|
|
40
|
-
* This function is intentionally non-throwing; failures are logged and
|
|
41
|
-
* surfaced via the system message router.
|
|
42
|
-
*/
|
|
43
|
-
export async function maybeAutoCompact(deps: AutoCompactDeps): Promise<void> {
|
|
44
|
-
// SDK schema default is 80; valid range is [10, 100]. The ?? 0 fallback is a
|
|
45
|
-
// defensive guard for missing/null values only — not a normal operating state.
|
|
46
|
-
const rawThreshold = Number(deps.configManager.get('behavior.autoCompactThreshold') ?? 0);
|
|
47
|
-
const thresholdPct = Number.isFinite(rawThreshold) ? rawThreshold : 0;
|
|
48
|
-
|
|
49
|
-
// Defensive guard: skip only when threshold is missing/non-positive (real config defaults to 80).
|
|
50
|
-
if (thresholdPct <= 0 || deps.contextWindow <= 0) return;
|
|
51
|
-
|
|
52
|
-
const usagePct = Math.min(100, Math.round((Math.max(0, deps.lastInputTokens) / deps.contextWindow) * 100));
|
|
53
|
-
if (usagePct < thresholdPct) return;
|
|
54
|
-
|
|
55
|
-
try {
|
|
56
|
-
logger.debug('auto-compact triggered', { usagePct, thresholdPct });
|
|
57
|
-
// Pre-compact preview — uses buildCompactionPreview for an honest estimate.
|
|
58
|
-
const messages = deps.conversation.getMessagesForLLM();
|
|
59
|
-
const sessionMemoryStore = deps.conversation.getSessionMemoryStore();
|
|
60
|
-
const sessionMemories = sessionMemoryStore?.list() ?? [];
|
|
61
|
-
const pinnedMemoryCount = sessionMemories.length;
|
|
62
|
-
const preview = buildCompactionPreview({
|
|
63
|
-
messages,
|
|
64
|
-
contextWindow: deps.contextWindow,
|
|
65
|
-
pinnedMemoryCount,
|
|
66
|
-
trigger: 'auto',
|
|
67
|
-
});
|
|
68
|
-
deps.systemMessageRouter.routeSystemMessage(preview, 'high');
|
|
69
|
-
const eventBefore = getLastCompactionEvent();
|
|
70
|
-
const compactionCtx: CompactionContext = {
|
|
71
|
-
messages,
|
|
72
|
-
sessionMemories,
|
|
73
|
-
agents: [],
|
|
74
|
-
wrfcChains: [],
|
|
75
|
-
activePlan: null,
|
|
76
|
-
lineageEntries: [],
|
|
77
|
-
compactionCount: 0,
|
|
78
|
-
contextWindow: deps.contextWindow,
|
|
79
|
-
trigger: 'auto',
|
|
80
|
-
extractionModelId: deps.model,
|
|
81
|
-
extractionProvider: deps.provider,
|
|
82
|
-
};
|
|
83
|
-
await deps.conversation.compact(
|
|
84
|
-
deps.providerRegistry,
|
|
85
|
-
deps.model,
|
|
86
|
-
'auto',
|
|
87
|
-
deps.provider,
|
|
88
|
-
compactionCtx,
|
|
89
|
-
);
|
|
90
|
-
// Post-compact notice using real CompactionEvent figures.
|
|
91
|
-
const eventAfter = getLastCompactionEvent();
|
|
92
|
-
if (eventAfter !== null && eventAfter !== eventBefore) {
|
|
93
|
-
deps.systemMessageRouter.routeSystemMessage(
|
|
94
|
-
buildCompactionAfterNotice({ event: eventAfter, pinnedMemoryCount }),
|
|
95
|
-
'low',
|
|
96
|
-
);
|
|
97
|
-
} else {
|
|
98
|
-
deps.systemMessageRouter.routeSystemMessage(
|
|
99
|
-
'[Context] Auto-compact complete — older turns summarised. Use /compact to compact again manually.',
|
|
100
|
-
'low',
|
|
101
|
-
);
|
|
102
|
-
}
|
|
103
|
-
} catch (err) {
|
|
104
|
-
logger.error('auto-compact failed', { error: summarizeError(err) });
|
|
105
|
-
deps.systemMessageRouter.routeSystemMessage(
|
|
106
|
-
`[Context] Auto-compact failed: ${summarizeError(err)}. Use /compact to try manually.`,
|
|
107
|
-
'high',
|
|
108
|
-
);
|
|
109
|
-
}
|
|
110
|
-
}
|