@pellux/goodvibes-agent 1.5.6 → 1.5.8
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 +13 -0
- package/README.md +1 -1
- package/dist/package/main.js +1431 -1219
- package/package.json +1 -1
- package/src/agent/memory-prompt.ts +3 -3
- package/src/agent/operator-actions.ts +1 -1
- package/src/agent/prompt-context-receipts.ts +7 -5
- package/src/agent/session-registration.ts +1 -1
- package/src/agent/vibe-file.ts +87 -6
- package/src/cli/local-library-command-shared.ts +1 -1
- package/src/cli/memory-command.ts +9 -6
- package/src/cli/resume-relaunch-notice.ts +1 -1
- package/src/cli/tui-startup.ts +1 -1
- package/src/config/credential-status.ts +165 -0
- package/src/config/index.ts +12 -0
- package/src/config/secrets.ts +17 -0
- package/src/core/conversation-rendering.ts +2 -2
- package/src/core/system-message-noise.ts +3 -3
- package/src/core/thinking-overlay.ts +1 -1
- package/src/input/agent-workspace-basic-command-editor-submission.ts +1 -1
- package/src/input/agent-workspace-basic-command-editors.ts +1 -1
- package/src/input/agent-workspace-calendar-connect-editor.ts +1 -1
- package/src/input/agent-workspace-calendar-oauth-editor.ts +1 -1
- package/src/input/agent-workspace-calendar-subscribe-editor.ts +1 -1
- package/src/input/agent-workspace-command-editor-engine.ts +2 -2
- package/src/input/agent-workspace-direct-editor-submission.ts +1 -1
- package/src/input/agent-workspace-email-connect-editor.ts +1 -1
- package/src/input/agent-workspace-live-counters.ts +1 -1
- package/src/input/agent-workspace-settings.ts +1 -1
- package/src/input/agent-workspace-snapshot-builders.ts +2 -2
- package/src/input/agent-workspace-snapshot-config.ts +1 -1
- package/src/input/agent-workspace-snapshot.ts +9 -9
- package/src/input/agent-workspace-types.ts +4 -4
- package/src/input/agent-workspace.ts +1 -1
- package/src/input/commands/calendar-connect-runtime.ts +1 -1
- package/src/input/commands/calendar-subscription-runtime.ts +2 -2
- package/src/input/commands/operator-actions-runtime.ts +1 -1
- package/src/input/commands/session-content.ts +1 -1
- package/src/input/commands/session-workflow.ts +1 -1
- package/src/input/feed-context-factory.ts +4 -4
- package/src/input/handler-feed.ts +9 -9
- package/src/input/handler.ts +1 -1
- package/src/input/panel-paste-flood-guard.ts +3 -3
- package/src/input/settings-modal.ts +1 -1
- package/src/main.ts +4 -4
- package/src/renderer/agent-workspace-context-lines.ts +1 -1
- package/src/renderer/startup-theme-probe.ts +1 -1
- package/src/renderer/status-glyphs.ts +2 -2
- package/src/renderer/terminal-bg-probe.ts +1 -1
- package/src/renderer/terminal-escapes.ts +3 -2
- package/src/renderer/theme-mode-config.ts +2 -2
- package/src/renderer/theme.ts +4 -4
- package/src/renderer/thinking.ts +1 -1
- package/src/renderer/ui-factory.ts +1 -1
- package/src/renderer/ui-primitives.ts +2 -2
- package/src/runtime/bootstrap-core.ts +32 -1
- package/src/runtime/bootstrap.ts +3 -3
- package/src/runtime/calendar-boot-refresh.ts +1 -1
- package/src/runtime/lan-scan-consent.ts +1 -1
- package/src/runtime/services.ts +7 -7
- package/src/runtime/terminal-output-guard.ts +1 -1
- package/src/runtime/ui-services.ts +1 -1
- package/src/shell/agent-workspace-fullscreen.ts +1 -1
- package/src/shell/terminal-focus-mode.ts +9 -9
- package/src/shell/ui-openers.ts +1 -1
- package/src/tools/agent-harness-operator-methods.ts +1 -1
- package/src/tools/agent-harness-personal-ops-discovery.ts +2 -2
- package/src/tools/agent-harness-personal-ops-lanes.ts +1 -1
- package/src/tools/agent-harness-personal-ops-types.ts +1 -1
- package/src/tools/agent-harness-prompt-context.ts +7 -4
- package/src/tools/agent-local-registry-memory.ts +1 -1
- package/src/tools/agent-operator-method-tool.ts +1 -1
- package/src/version.ts +1 -1
|
@@ -330,7 +330,7 @@ export function agentWorkspaceSettingSchema(context: CommandContext | null, key:
|
|
|
330
330
|
?.getSchema()
|
|
331
331
|
.find((setting) => setting.key === key) ?? null;
|
|
332
332
|
if (fromSchema) return fromSchema;
|
|
333
|
-
// display.themeMode is a TUI-local synthetic setting
|
|
333
|
+
// display.themeMode is a TUI-local synthetic setting that never
|
|
334
334
|
// joined the SDK ConfigKey schema — the classic settings-modal injects the
|
|
335
335
|
// same descriptor into its own groups map rather than the schema. Mirror
|
|
336
336
|
// that fallback here so the workspace surface can discover and cycle it too.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// Sub-builders extracted out of the single ~516-line `buildAgentWorkspaceRuntimeSnapshot`
|
|
2
|
-
// function in agent-workspace-snapshot.ts (
|
|
2
|
+
// function in agent-workspace-snapshot.ts (per the design ruling's
|
|
3
3
|
// giant-single-function-assembler verdict: "splitting into cohesive sub-builders...
|
|
4
4
|
// would reduce single-function size without changing behavior"). Each function here
|
|
5
5
|
// is the verbatim body of one of that function's local IIFEs or local variable blocks,
|
|
@@ -273,7 +273,7 @@ export function buildAgentWorkspaceCompanionAccessSnapshot(context: CommandConte
|
|
|
273
273
|
|
|
274
274
|
/**
|
|
275
275
|
* Honest email-connect status for the inbox connect wizard's entry state
|
|
276
|
-
*
|
|
276
|
+
* — config validation only, no network I/O. Best-effort: never
|
|
277
277
|
* throws, returns null on any read failure.
|
|
278
278
|
*/
|
|
279
279
|
export function buildAgentWorkspaceEmailConnectStatus(context: CommandContext): AgentWorkspaceEmailConnectStatus | null {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// Small config-read helpers shared by agent-workspace-snapshot.ts and
|
|
2
|
-
// agent-workspace-snapshot-builders.ts (
|
|
2
|
+
// agent-workspace-snapshot-builders.ts (split out of the runtime-snapshot giant
|
|
3
3
|
// assembler). Each never throws: config reads fall back to the given default on any
|
|
4
4
|
// error, matching the original inline behavior exactly.
|
|
5
5
|
import type { CommandContext } from './command-registry.ts';
|
|
@@ -36,8 +36,8 @@ import {
|
|
|
36
36
|
} from './agent-workspace-snapshot-builders.ts';
|
|
37
37
|
import type { AgentWorkspaceLocalLibraryItem, AgentWorkspaceRuntimeSnapshot } from './agent-workspace-types.ts';
|
|
38
38
|
|
|
39
|
-
// Re-exported so this module's public surface matches the pre-split file (
|
|
40
|
-
//
|
|
39
|
+
// Re-exported so this module's public surface matches the pre-split file (this
|
|
40
|
+
// builder was originally exported here, before a later split moved its body to
|
|
41
41
|
// agent-workspace-snapshot-builders.ts).
|
|
42
42
|
export { buildAgentWorkspaceEmailConnectStatus } from './agent-workspace-snapshot-builders.ts';
|
|
43
43
|
|
|
@@ -65,16 +65,16 @@ export interface AgentWorkspaceLiveMemoryCounters {
|
|
|
65
65
|
* mid-call) rather than swallowing it — callers that need a best-effort,
|
|
66
66
|
* never-throws default (the full runtime snapshot builder below) should use
|
|
67
67
|
* buildAgentWorkspaceMemorySnapshot instead. The render-path live-counter
|
|
68
|
-
* refresh (AgentWorkspace.syncLiveCountersForRender
|
|
68
|
+
* refresh (AgentWorkspace.syncLiveCountersForRender) calls this
|
|
69
69
|
* directly so a genuine read failure can be surfaced as "stale" instead of
|
|
70
70
|
* being silently rewritten to a fabricated 0.
|
|
71
71
|
*
|
|
72
|
-
* NOTE (
|
|
72
|
+
* NOTE (observability flag): these live process/state counters are
|
|
73
73
|
* flagged as observability-shaped content whose eventual surface home is the
|
|
74
74
|
* fleet/observability layer, not this admin-console snapshot builder. Nothing
|
|
75
75
|
* moves today (no observability layer exists yet); this function is kept
|
|
76
76
|
* intact and separate rather than folded into the sibling sub-builders in
|
|
77
|
-
* agent-workspace-snapshot-builders.ts extracted alongside it
|
|
77
|
+
* agent-workspace-snapshot-builders.ts extracted alongside it.
|
|
78
78
|
*/
|
|
79
79
|
export function readLiveAgentMemoryCounters(context: CommandContext): AgentWorkspaceLiveMemoryCounters {
|
|
80
80
|
const memory = context.clients?.agentKnowledgeApi?.memory;
|
|
@@ -85,7 +85,7 @@ export function readLiveAgentMemoryCounters(context: CommandContext): AgentWorks
|
|
|
85
85
|
reviewQueueCount: memory.reviewQueue(100).length,
|
|
86
86
|
promptActiveCount: records.filter(isPromptActiveMemory).length,
|
|
87
87
|
// Each item carries the honest, per-record eligibility reason straight from
|
|
88
|
-
// describeMemoryPromptEligibility
|
|
88
|
+
// describeMemoryPromptEligibility — the same wording source
|
|
89
89
|
// prompt-context-receipts.ts and agent-harness-prompt-context.ts use for prompt
|
|
90
90
|
// recall. No locally invented "not reviewed"/"outside prompt limit" paraphrase here.
|
|
91
91
|
items: records.map((record) => ({
|
|
@@ -120,9 +120,9 @@ export interface AgentWorkspaceLiveRoutineCounters {
|
|
|
120
120
|
* if the store read fails (e.g. a corrupt/unreadable routines.json —
|
|
121
121
|
* AgentRoutineRegistry.snapshot() itself throws in that case) rather than
|
|
122
122
|
* swallowing it; see readLiveAgentMemoryCounters above for why the
|
|
123
|
-
* render-path live-counter refresh
|
|
123
|
+
* render-path live-counter refresh wants that.
|
|
124
124
|
*
|
|
125
|
-
* NOTE (
|
|
125
|
+
* NOTE (observability flag): see readLiveAgentMemoryCounters above —
|
|
126
126
|
* the same flag applies to these routine counters.
|
|
127
127
|
*/
|
|
128
128
|
export function readLiveAgentRoutineCounters(context: CommandContext): AgentWorkspaceLiveRoutineCounters {
|
|
@@ -150,7 +150,7 @@ export function buildAgentWorkspaceRoutineCounters(context: CommandContext): Age
|
|
|
150
150
|
|
|
151
151
|
/**
|
|
152
152
|
* Assembles the full Agent workspace runtime snapshot. Composes the
|
|
153
|
-
* sub-builders in agent-workspace-snapshot-builders.ts (
|
|
153
|
+
* sub-builders in agent-workspace-snapshot-builders.ts (split out of what
|
|
154
154
|
* was previously one ~516-line function) plus the two live-counter builders
|
|
155
155
|
* above, then maps everything onto the AgentWorkspaceRuntimeSnapshot shape.
|
|
156
156
|
*/
|
|
@@ -370,7 +370,7 @@ export interface AgentWorkspaceLocalLibraryItem {
|
|
|
370
370
|
readonly missingRequirementCount?: number;
|
|
371
371
|
readonly missingRequirements?: readonly string[];
|
|
372
372
|
readonly startCount?: number;
|
|
373
|
-
/** Memory-only
|
|
373
|
+
/** Memory-only: whether this record currently clears the prompt-injection
|
|
374
374
|
* recall floor, per describeMemoryPromptEligibility. */
|
|
375
375
|
readonly promptEligible?: boolean;
|
|
376
376
|
/** Memory-only: the honest, per-record reason from describeMemoryPromptEligibility —
|
|
@@ -640,7 +640,7 @@ export interface AgentWorkspaceCompanionAccessSummary {
|
|
|
640
640
|
readonly nextStep: string;
|
|
641
641
|
}
|
|
642
642
|
|
|
643
|
-
/** Honest, no-I/O email-connect status (config validation only) for the inbox connect card/wizard
|
|
643
|
+
/** Honest, no-I/O email-connect status (config validation only) for the inbox connect card/wizard. */
|
|
644
644
|
export interface AgentWorkspaceEmailConnectStatus {
|
|
645
645
|
readonly connected: boolean;
|
|
646
646
|
readonly username: string;
|
|
@@ -785,7 +785,7 @@ export interface AgentWorkspaceRuntimeSnapshot {
|
|
|
785
785
|
readonly warnings: readonly string[];
|
|
786
786
|
/**
|
|
787
787
|
* True when the most recent render-path attempt to re-derive the live
|
|
788
|
-
* counters (memory count, routine counts + start counts
|
|
788
|
+
* counters (memory count, routine counts + start counts) failed
|
|
789
789
|
* and the previous values below had to be kept. A fresh
|
|
790
790
|
* buildAgentWorkspaceRuntimeSnapshot() call is never stale (it just read
|
|
791
791
|
* everything); this only flips true from
|
|
@@ -794,7 +794,7 @@ export interface AgentWorkspaceRuntimeSnapshot {
|
|
|
794
794
|
* instead of asserting a number the disk might already contradict.
|
|
795
795
|
*/
|
|
796
796
|
readonly liveCountersStale: boolean;
|
|
797
|
-
/** Honest email-connect status for the connect wizard's entry state
|
|
797
|
+
/** Honest email-connect status for the connect wizard's entry state. Null when unavailable in this runtime. */
|
|
798
798
|
readonly emailConnectStatus: AgentWorkspaceEmailConnectStatus | null;
|
|
799
799
|
readonly calendarOAuthConfigStatus: { readonly google: boolean; readonly microsoft: boolean } | null; // F1c: per-provider client-id-configured state for the advanced cards
|
|
800
800
|
}
|
|
@@ -219,7 +219,7 @@ export class AgentWorkspace {
|
|
|
219
219
|
this.lastActionResult = { kind: 'refreshed', title: 'Runtime context refreshed', detail: 'Provider, model, session, local memory, runtime endpoint, and Agent knowledge route posture were re-read from the live command context.' };
|
|
220
220
|
}
|
|
221
221
|
|
|
222
|
-
/**
|
|
222
|
+
/** Render-path live counter mirror (see syncAgentWorkspaceLiveCounters). */ syncLiveCountersForRender(): void { syncAgentWorkspaceLiveCounters({ context: this.context, runtimeSnapshot: this.runtimeSnapshot, setRuntimeSnapshot: (snapshot) => { this.runtimeSnapshot = snapshot; }, clampSelection: () => this.clampSelection() }); }
|
|
223
223
|
|
|
224
224
|
cancelLocalEditor(): void {
|
|
225
225
|
if (!this.localEditor) return;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* calendar-connect-runtime.ts — the /calendar connect|disconnect|accounts subcommands
|
|
3
|
-
* and the provider-event merge for /calendar upcoming
|
|
3
|
+
* and the provider-event merge for /calendar upcoming.
|
|
4
4
|
*
|
|
5
5
|
* The OAuth network dance lives here (not in the workspace card) because a command
|
|
6
6
|
* handler can print the authorization URL / device user-code IMMEDIATELY, then await
|
|
@@ -11,8 +11,8 @@ import { parseAgentLocalLibraryArgs } from './agent-local-library-args.ts';
|
|
|
11
11
|
import { requireShellPaths } from './runtime-services.ts';
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
|
-
* External-calendar SUBSCRIPTION verbs for /calendar — the no-OAuth read path
|
|
15
|
-
*
|
|
14
|
+
* External-calendar SUBSCRIPTION verbs for /calendar — the no-OAuth read path.
|
|
15
|
+
* Subscriptions are iCalendar feeds (Google secret address, Outlook
|
|
16
16
|
* published .ics, or any .ics URL). The parse/RRULE/fetch-status engine is the
|
|
17
17
|
* SDK's platform/calendar; this file is the /calendar command surface over the
|
|
18
18
|
* agent-side CalendarSubscriptionRegistry.
|
|
@@ -93,7 +93,7 @@ function automationActionFromParts(scope: string, verb: string): {
|
|
|
93
93
|
readonly targetField: 'jobId' | 'runId' | 'scheduleId';
|
|
94
94
|
} | null {
|
|
95
95
|
if ((scope === 'job' || scope === 'jobs') && verb === 'run') return { action: 'automation.jobs.run', targetField: 'jobId' };
|
|
96
|
-
//
|
|
96
|
+
// automation.jobs.pause/resume retired (redundant with
|
|
97
97
|
// disable/enable) — the user-facing "pause"/"resume" verb is unchanged,
|
|
98
98
|
// it now maps onto the canonical disable/enable wire actions.
|
|
99
99
|
if ((scope === 'job' || scope === 'jobs') && verb === 'pause') return { action: 'automation.jobs.disable', targetField: 'jobId' };
|
|
@@ -254,7 +254,7 @@ export function registerSessionContentCommands(registry: CommandRegistry): void
|
|
|
254
254
|
usage: '[resume <id|name>]',
|
|
255
255
|
argsHint: '[resume <id|name>]',
|
|
256
256
|
async handler(_args, ctx) {
|
|
257
|
-
// Matches the TUI's /sessions (
|
|
257
|
+
// Matches the TUI's /sessions (worst-class collision #5): this
|
|
258
258
|
// was `hidden: true` here — invisible in help/autocomplete — even
|
|
259
259
|
// though it is a fully working command identical in behavior to the
|
|
260
260
|
// TUI's visible one. Also forward args to /session (the TUI's fix for
|
|
@@ -479,7 +479,7 @@ export async function handleSessionWorkflowCommand(args: string[], ctx: CommandC
|
|
|
479
479
|
return false;
|
|
480
480
|
}
|
|
481
481
|
|
|
482
|
-
// NOTE (
|
|
482
|
+
// NOTE (core-verb pass): this file used to also export
|
|
483
483
|
// registerSessionWorkflowCommands(), a second top-level `/session` (alias
|
|
484
484
|
// `sess`) registration with its own usage text. It was NEVER called from
|
|
485
485
|
// startup — commands.ts only registers `sessionCommand` from ./session.ts —
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* feed-context-factory.ts — Construction and mutable-field sync for InputFeedContext.
|
|
3
3
|
*
|
|
4
|
-
* Extracted from handler.ts (
|
|
4
|
+
* Extracted from handler.ts (0.18.23) to keep handler.ts under the
|
|
5
5
|
* 800-line architecture cap.
|
|
6
6
|
*
|
|
7
7
|
* Two exported functions:
|
|
@@ -95,9 +95,9 @@ export interface FeedContextStableRefs {
|
|
|
95
95
|
selection: SelectionManager;
|
|
96
96
|
pasteRegistry: Map<string, string>;
|
|
97
97
|
imageRegistry: Map<string, { data: string; mediaType: string }>;
|
|
98
|
-
/**
|
|
98
|
+
/** Ported from goodvibes-tui's DEBT-5 item 5; mutated in place, never reallocated. */
|
|
99
99
|
burstGuard: PanelBurstGuardState;
|
|
100
|
-
/**
|
|
100
|
+
/** OS-level terminal focus tracker, ported from goodvibes-tui's W2.3. */
|
|
101
101
|
focusTracker: FocusTracker;
|
|
102
102
|
projectRoot: string;
|
|
103
103
|
selectionModal: SelectionModal;
|
|
@@ -182,7 +182,7 @@ export function buildInitialFeedContext(
|
|
|
182
182
|
...mutable,
|
|
183
183
|
// --- requestRender: placeholder, swapped per-feed to buffered version ---
|
|
184
184
|
requestRender: noop,
|
|
185
|
-
//
|
|
185
|
+
// Wiring-layer-only bookkeeping for the paste-flood guard's honest
|
|
186
186
|
// resolution notice (not part of the ported panel-paste-flood-guard.ts
|
|
187
187
|
// module itself; see handler-feed.ts's feedInputTokens).
|
|
188
188
|
burstSuppressedCount: 0,
|
|
@@ -64,13 +64,13 @@ import type { FocusTracker } from '../core/focus-tracker.ts';
|
|
|
64
64
|
* - `inputHistory`, `conversationManager` — late-wired service handles; synced at
|
|
65
65
|
* feed() entry only since no in-feed action rewires them
|
|
66
66
|
* - `pasteRegistry`, `imageRegistry` — owned Maps, never replaced
|
|
67
|
-
* - `burstGuard` (
|
|
67
|
+
* - `burstGuard` (ported from goodvibes-tui's DEBT-5 item 5) — the
|
|
68
68
|
* unbracketed-paste-flood guard's sliding-window state, mutated in place
|
|
69
69
|
* across tokens by trackPanelPasteFloodGuard (see panel-paste-flood-guard.ts).
|
|
70
70
|
* Never reallocated. `burstSuppressedCount` is this wiring layer's own
|
|
71
71
|
* bookkeeping (not part of the ported module) for the honest resolution
|
|
72
72
|
* notice — see feedInputTokens below.
|
|
73
|
-
* - `focusTracker` (
|
|
73
|
+
* - `focusTracker` (ported from goodvibes-tui's W2.3) — tracks OS-level
|
|
74
74
|
* terminal focus from `\x1b[I`/`\x1b[O` tokens (DECSET ?1004h, enabled in
|
|
75
75
|
* main.ts). Shared instance from RuntimeServices, threaded via
|
|
76
76
|
* uiServices.platform.focusTracker (mirrors the TUI's own wiring).
|
|
@@ -105,11 +105,11 @@ export interface InputFeedContext {
|
|
|
105
105
|
contentWidth: number;
|
|
106
106
|
readonly pasteRegistry: Map<string, string>;
|
|
107
107
|
readonly imageRegistry: Map<string, { data: string; mediaType: string }>;
|
|
108
|
-
/**
|
|
108
|
+
/** Ported from goodvibes-tui DEBT-5 item 5 — mutated in place, never reallocated. */
|
|
109
109
|
readonly burstGuard: PanelBurstGuardState;
|
|
110
|
-
/**
|
|
110
|
+
/** Wiring-layer bookkeeping (not part of the ported module) for the honest suppressed-count notice. */
|
|
111
111
|
burstSuppressedCount: number;
|
|
112
|
-
/**
|
|
112
|
+
/** Ported from goodvibes-tui W2.3 — OS-level terminal focus, fed from 'focus' tokens below. */
|
|
113
113
|
readonly focusTracker: FocusTracker;
|
|
114
114
|
readonly projectRoot: string;
|
|
115
115
|
readonly selection: SelectionManager;
|
|
@@ -176,13 +176,13 @@ export function feedInputTokens(context: InputFeedContext, tokens: readonly Inpu
|
|
|
176
176
|
const scrollTop = context.getScrollTop();
|
|
177
177
|
const lineCount = history.getLineCount();
|
|
178
178
|
const keybindings = context.keybindingsManager;
|
|
179
|
-
//
|
|
179
|
+
// One `now` per feed() call (not per token) — a genuine unbracketed-paste
|
|
180
180
|
// flood delivers many tokens in one drain, and they should all measure as
|
|
181
181
|
// arriving "at once" (mirrors goodvibes-tui's handler-feed.ts DEBT-5 item 5 doc).
|
|
182
182
|
const now = Date.now();
|
|
183
183
|
|
|
184
184
|
for (const token of tokens) {
|
|
185
|
-
//
|
|
185
|
+
// Ported from goodvibes-tui W2.3: focus-reporting tokens (CSI ?1004h)
|
|
186
186
|
// never reach the composer or any modal route — consumed here, first,
|
|
187
187
|
// unconditionally. No render needed.
|
|
188
188
|
if (token.type === 'focus') {
|
|
@@ -294,8 +294,8 @@ export function feedInputTokens(context: InputFeedContext, tokens: readonly Inpu
|
|
|
294
294
|
}
|
|
295
295
|
}
|
|
296
296
|
|
|
297
|
-
//
|
|
298
|
-
// 5
|
|
297
|
+
// Ported from goodvibes-tui's panel-paste-flood-guard.ts, DEBT-5 item
|
|
298
|
+
// 5: guards command-mode's key-driven dispatch (handleCommandModeToken,
|
|
299
299
|
// below) from an unbracketed-paste-replay or control-character-injection
|
|
300
300
|
// burst.
|
|
301
301
|
//
|
package/src/input/handler.ts
CHANGED
|
@@ -94,7 +94,7 @@ export class InputHandler {
|
|
|
94
94
|
public pasteRegistry = new Map<string, string>();
|
|
95
95
|
public nextPasteId = 1;
|
|
96
96
|
public lastCtrlCTime = 0;
|
|
97
|
-
/**
|
|
97
|
+
/** Ported from goodvibes-tui DEBT-5 item 5 — unbracketed-paste-flood guard state, mutated in place. */
|
|
98
98
|
public burstGuard: PanelBurstGuardState = { timestamps: [], suspended: false, hintShown: false };
|
|
99
99
|
/** Long-lived feed context — reused across every feed() call to avoid per-keystroke allocation. */
|
|
100
100
|
public feedContext!: import('./handler-feed.ts').InputFeedContext;
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
// ---------------------------------------------------------------------------
|
|
2
2
|
// panel-paste-flood-guard.ts — ported from goodvibes-tui (commit 90eb3a26,
|
|
3
|
-
// DEBT-5 item 5)
|
|
3
|
+
// DEBT-5 item 5).
|
|
4
4
|
//
|
|
5
5
|
// A terminal WITHOUT bracketed paste delivers a pasted block as a burst of
|
|
6
6
|
// discrete 1-char 'text' tokens (isPasteToken stays false for every one of
|
|
7
7
|
// them, since that flag only fires for a single token whose value.length > 1).
|
|
8
8
|
//
|
|
9
|
-
// AGENT ADAPTATION (this repo has no `src/panels/` — see the
|
|
10
|
-
// matrix's
|
|
9
|
+
// AGENT ADAPTATION (this repo has no `src/panels/` — see the parity
|
|
10
|
+
// matrix's corresponding row): the TUI wires this guard inside handlePanelFocusToken,
|
|
11
11
|
// where it protects a focused PANEL from having each replayed character
|
|
12
12
|
// dispatched as a real hotkey (K arms kill, etc). This agent has no panel
|
|
13
13
|
// focus concept at all — every token that isn't consumed by a modal route or
|
|
@@ -640,7 +640,7 @@ export class SettingsModal {
|
|
|
640
640
|
if (this.groups.has(cat)) this.groups.get(cat)!.push(entry);
|
|
641
641
|
}
|
|
642
642
|
|
|
643
|
-
//
|
|
643
|
+
// Inject the synthetic display.themeMode enum (auto|dark|light) —
|
|
644
644
|
// agent-local key stored under the existing `display` section (not in the
|
|
645
645
|
// SDK ConfigKey union; setDynamic/get round-trip it), the TUI's
|
|
646
646
|
// settings-modal-data.ts synthetic-setting pattern. Cycles like any other
|
package/src/main.ts
CHANGED
|
@@ -67,7 +67,7 @@ const KEYBOARD_EXT_ENABLE = '\x1b[>4;2m' + '\x1b[?1u', KEYBOARD_EXT_DISABLE = '\
|
|
|
67
67
|
async function main() {
|
|
68
68
|
const stdout = process.stdout;
|
|
69
69
|
const stdin = process.stdin;
|
|
70
|
-
installFocusModeExitGuard(stdout); //
|
|
70
|
+
installFocusModeExitGuard(stdout); // see shell/terminal-focus-mode.ts
|
|
71
71
|
const { cli, configManager, bootstrapWorkingDir, bootstrapHomeDirectory } = await prepareShellCliRuntime(process.argv.slice(2), {
|
|
72
72
|
defaultWorkingDirectory: process.env['GOODVIBES_WORKING_DIR'] ?? process.cwd(),
|
|
73
73
|
homeDirectory: process.env['GOODVIBES_AGENT_HOME'] ?? homedir(),
|
|
@@ -159,7 +159,7 @@ async function main() {
|
|
|
159
159
|
|
|
160
160
|
let streamTokenSpeed = 0;
|
|
161
161
|
|
|
162
|
-
const thinkingClock = new ThinkingStallClock(); //
|
|
162
|
+
const thinkingClock = new ThinkingStallClock(); // thinking-indicator stall clock
|
|
163
163
|
|
|
164
164
|
let scrollTop = 0;
|
|
165
165
|
let scrollLocked = true;
|
|
@@ -401,7 +401,7 @@ async function main() {
|
|
|
401
401
|
sidebarOverride = !(sidebarWidthFor(width) > 0);
|
|
402
402
|
render();
|
|
403
403
|
};
|
|
404
|
-
const rawRequestPermission: typeof permissionPromptRef.requestPermission = (request) => new Promise((resolve) => { //
|
|
404
|
+
const rawRequestPermission: typeof permissionPromptRef.requestPermission = (request) => new Promise((resolve) => { // see shell/terminal-focus-mode.ts
|
|
405
405
|
pendingPermission = { ...request, resolve: (approved: boolean, remember = false) => resolve({ approved, remember }) };
|
|
406
406
|
render();
|
|
407
407
|
});
|
|
@@ -692,7 +692,7 @@ async function main() {
|
|
|
692
692
|
stdin.setEncoding('utf8');
|
|
693
693
|
allowTerminalWrite(() => { markFocusModeEnabled(); return stdout.write((cli.flags.noAltScreen ? '' : ALT_SCREEN_ENTER) + CLEAR_SCREEN + CURSOR_HIDE + MOUSE_ENABLE + KEYBOARD_EXT_ENABLE + PASTE_ENABLE + FOCUS_ENABLE); });
|
|
694
694
|
|
|
695
|
-
//
|
|
695
|
+
// Forced dark/light before first paint; auto (TTY) probes + repaints once if light.
|
|
696
696
|
const themeProbe = installStartupThemeProbe({
|
|
697
697
|
configManager, stdout, writeAllowed: allowTerminalWrite,
|
|
698
698
|
resetDiff: () => compositor.resetDiff(), render,
|
|
@@ -28,7 +28,7 @@ function formatMegabytes(bytes: number): string {
|
|
|
28
28
|
return `${Math.round(bytes / (1024 * 1024))} MB`;
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
//
|
|
31
|
+
// The memory/routine counts below are re-derived live on every
|
|
32
32
|
// repaint (AgentWorkspace.syncLiveCountersForRender). If that live read
|
|
33
33
|
// fails, liveCountersStale flags it so we say so instead of asserting a
|
|
34
34
|
// number the disk might already contradict.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* startup-theme-probe.ts
|
|
2
|
+
* startup-theme-probe.ts — install the OSC-11 background probe at
|
|
3
3
|
* startup and wire its resolved mode to the ported theme system.
|
|
4
4
|
*
|
|
5
5
|
* Thin composition seam extracted from main.ts: it binds R2's
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// ---------------------------------------------------------------------------
|
|
2
2
|
// status-glyphs.ts — canonical glyph map for status states.
|
|
3
3
|
//
|
|
4
|
-
//
|
|
5
|
-
// contract (@pellux/goodvibes-sdk/platform/presentation
|
|
4
|
+
// STATE_GLYPHS is no longer hardcoded here. It is the SDK presentation
|
|
5
|
+
// contract (@pellux/goodvibes-sdk/platform/presentation),
|
|
6
6
|
// aliased to GLYPHS.status so the four semantic glyphs are spelled out in
|
|
7
7
|
// exactly one place and can never drift from the registry again. Re-exported
|
|
8
8
|
// under the historical names so status-token.ts and polish.ts import unchanged.
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
* is enabled; otherwise the query is swallowed and the timeout fallback (dark)
|
|
27
27
|
* covers it silently.
|
|
28
28
|
*
|
|
29
|
-
*
|
|
29
|
+
* Adaptation for this agent: the theme-application coupling is INJECTED rather
|
|
30
30
|
* than imported from theme.ts. R2 owns this module; R4 owns the theme system
|
|
31
31
|
* (theme.ts / theme-mode-config.ts) and wires installBackgroundThemeProbe with
|
|
32
32
|
* `applyThemeMode: setActiveThemeMode`. Keeping the coupling injected lets R2
|
|
@@ -5,8 +5,9 @@
|
|
|
5
5
|
* and the entry file stays within the source-file line-count gate.
|
|
6
6
|
*
|
|
7
7
|
* FOCUS_ENABLE / FOCUS_DISABLE (DECSET ?1004) are the shared home for the OS
|
|
8
|
-
* window-focus reporting mode consumed by the focus-tracker
|
|
9
|
-
* FOCUS_ENABLE from here rather
|
|
8
|
+
* window-focus reporting mode consumed by the focus-tracker: the focus-mode
|
|
9
|
+
* module (shell/terminal-focus-mode.ts) imports FOCUS_ENABLE from here rather
|
|
10
|
+
* than redefining it.
|
|
10
11
|
*/
|
|
11
12
|
|
|
12
13
|
export const ALT_SCREEN_ENTER = '\x1b[?1049h';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* theme-mode-config — the appearance/theme-mode preference surface
|
|
2
|
+
* theme-mode-config — the appearance/theme-mode preference surface.
|
|
3
3
|
*
|
|
4
4
|
* The preference lives at the config key `display.themeMode` (auto | dark |
|
|
5
5
|
* light, default auto). It is stored under the existing SDK `display` section
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* display.* toggles.
|
|
9
9
|
*
|
|
10
10
|
* DIVERGENCE FROM THE W4 BRIEF (recorded): the brief listed theme-mode-config.ts
|
|
11
|
-
* as the NEW home for the config-read helpers, but
|
|
11
|
+
* as the NEW home for the config-read helpers, but the terminal-bg-probe.ts change landed FIRST and
|
|
12
12
|
* inlined resolveConfiguredThemeMode / coerceThemeModeSetting /
|
|
13
13
|
* THEME_MODE_CONFIG_KEY / ThemeModeSetting into terminal-bg-probe.ts (so R2
|
|
14
14
|
* could ship the probe before this file existed). Rather than duplicate those
|
package/src/renderer/theme.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* theme.ts — Semantic colour token layer (
|
|
2
|
+
* theme.ts — Semantic colour token layer (port of the TUI theme system).
|
|
3
3
|
*
|
|
4
4
|
* Two token layers, resolved per background mode:
|
|
5
5
|
*
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
*
|
|
17
17
|
* Dark mode values are the historically used colours. Light mode values exist
|
|
18
18
|
* for correctness parity and are consumed once the terminal-bg-probe
|
|
19
|
-
* (terminal-escapes / OSC 11
|
|
19
|
+
* (terminal-escapes / OSC 11) resolves the mode and setActiveThemeMode
|
|
20
20
|
* is called. Callers that do not yet have mode detection get 'dark' — the safe
|
|
21
21
|
* default (activeMode starts dark).
|
|
22
22
|
*
|
|
@@ -162,7 +162,7 @@ export const DARK_THEME: Readonly<ThemeTokens> = DARK;
|
|
|
162
162
|
//
|
|
163
163
|
// The dark table is the SDK's TONE_TOKENS (re-exported here as UI_TONES); the
|
|
164
164
|
// light variant is the SDK's resolveTones('light'). The agent does NOT mint its
|
|
165
|
-
// own light chrome variant — that duplication is exactly what
|
|
165
|
+
// own light chrome variant — that duplication is exactly what the SDK extraction ended.
|
|
166
166
|
// ---------------------------------------------------------------------------
|
|
167
167
|
|
|
168
168
|
/** The chrome tone-token shape (the SDK ToneTokens contract). */
|
|
@@ -189,7 +189,7 @@ export function resolveUiTones(mode: ThemeMode): Readonly<UiToneTokens> {
|
|
|
189
189
|
//
|
|
190
190
|
// registerThemeRefresh exists for owners that BAKE tone values into
|
|
191
191
|
// module-level constants (which cannot be re-resolved per call). Nothing
|
|
192
|
-
// registers
|
|
192
|
+
// registers currently — the agent's opaque panel palettes (polish.ts
|
|
193
193
|
// DEFAULT_PANEL_PALETTE and the modal/overlay/fullscreen surfaces built from
|
|
194
194
|
// it) paint OPAQUE dark boxes whose fg/state tokens stay dark in both modes, so
|
|
195
195
|
// they need no rebuild for dark parity (the opaque-surface trio deferral). The
|
package/src/renderer/thinking.ts
CHANGED
|
@@ -10,7 +10,7 @@ export function renderThinkingBlock(text: string, width: number): Line[] {
|
|
|
10
10
|
// light terminal. In dark mode the accent adopts the shared reasoning purple
|
|
11
11
|
// (state.reasoning) and the body adopts chrome.faint (== fg.dim) — a small,
|
|
12
12
|
// deliberate convergence to the reference tokens from the agent's prior local
|
|
13
|
-
// BORDERS.THINKING.color / COLORS.DIM_TEXT (see the
|
|
13
|
+
// BORDERS.THINKING.color / COLORS.DIM_TEXT (see the visible-changes note).
|
|
14
14
|
const t = activeUiTones();
|
|
15
15
|
return renderConversationNotice(
|
|
16
16
|
text,
|
|
@@ -259,7 +259,7 @@ export class UIFactory {
|
|
|
259
259
|
if (inp > 0 || out > 0) {
|
|
260
260
|
statusTokens.push({ text: `↑${fmtNum(inp)} ↓${fmtNum(out)}`, fg: '240' });
|
|
261
261
|
}
|
|
262
|
-
//
|
|
262
|
+
// The disconnected footer 'waiting for your approval' token is retired
|
|
263
263
|
// here — the approval-wait truth now lives in the unified waiting state of the
|
|
264
264
|
// thinking indicator (createThinkingFragment's approvalPending path) and in the
|
|
265
265
|
// permission prompt itself, so the footer no longer carries a separate,
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
// ---------------------------------------------------------------------------
|
|
2
2
|
// ui-primitives.ts — glyph registry + tone-token table.
|
|
3
3
|
//
|
|
4
|
-
//
|
|
4
|
+
// These four tables (GLYPHS, UI_TONES, DIFF_TONES, SPINNER_FRAMES) are
|
|
5
5
|
// no longer minted locally. They are the SDK presentation contract
|
|
6
|
-
// (@pellux/goodvibes-sdk/platform/presentation
|
|
6
|
+
// (@pellux/goodvibes-sdk/platform/presentation), consumed here
|
|
7
7
|
// so the agent and the TUI share ONE source (Mike's move-to-SDK ruling —
|
|
8
8
|
// machinery needed by 2+ surfaces => SDK). See
|
|
9
9
|
// docs/decisions/2026-07-05-presentation-contract-sdk-extraction.md in the SDK.
|
|
@@ -26,7 +26,10 @@ import {
|
|
|
26
26
|
} from '@/runtime/index.ts';
|
|
27
27
|
import { loadBootstrapSystemPrompt, syncConfiguredServices } from '@/runtime/index.ts';
|
|
28
28
|
import { registerBootstrapHookBridge } from '@/runtime/index.ts';
|
|
29
|
-
import { createRuntimeServices, type RuntimeServices } from './services.ts';
|
|
29
|
+
import { createRuntimeServices, foldAgentLegacyMemory, type RuntimeServices } from './services.ts';
|
|
30
|
+
import { formatMemoryFoldReport } from '@pellux/goodvibes-sdk/platform/state';
|
|
31
|
+
import { summarizeError } from '@pellux/goodvibes-sdk/platform/utils';
|
|
32
|
+
import { importVibeFilesIntoMemoryOnce } from '../agent/vibe-file.ts';
|
|
30
33
|
import { createUiRuntimeServices, type UiRuntimeServices } from './ui-services.ts';
|
|
31
34
|
import { installAgentToolPolicyGuard } from '../tools/agent-tool-policy-guard.ts';
|
|
32
35
|
import { registerAgentChannelSendTool } from '../tools/agent-channel-send-tool.ts';
|
|
@@ -345,6 +348,34 @@ export async function initializeBootstrapCore(
|
|
|
345
348
|
memoryStore.close();
|
|
346
349
|
});
|
|
347
350
|
|
|
351
|
+
// Fold the agent's legacy per-surface memory into the canonical
|
|
352
|
+
// cross-surface store (id-keyed, idempotent, never deletes the legacy file) and
|
|
353
|
+
// SURFACE the fold report — migration honesty requires that what moved is visible,
|
|
354
|
+
// not silently swallowed. Non-fatal: a fold failure must never block startup.
|
|
355
|
+
try {
|
|
356
|
+
const foldReport = await foldAgentLegacyMemory(
|
|
357
|
+
services.memoryStore,
|
|
358
|
+
services.memoryEmbeddingRegistry,
|
|
359
|
+
services.shellPaths,
|
|
360
|
+
);
|
|
361
|
+
logger.info('agent legacy memory fold report', { report: formatMemoryFoldReport(foldReport) });
|
|
362
|
+
} catch (err) {
|
|
363
|
+
logger.warn('agent legacy memory fold failed (non-fatal)', { error: summarizeError(err) });
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
// ONE-TIME migration of discovered VIBE.md files into persona/constraint
|
|
367
|
+
// records, guarded by a persisted path→hash marker so it never re-imports the same
|
|
368
|
+
// file (which would create near-duplicate persona records). After this, the VIBE
|
|
369
|
+
// prompt is a PROJECTION of those records (buildVibeProjectionPrompt).
|
|
370
|
+
try {
|
|
371
|
+
const importedPersona = await importVibeFilesIntoMemoryOnce(services.memoryRegistry, services.shellPaths);
|
|
372
|
+
if (importedPersona > 0) {
|
|
373
|
+
logger.info('agent VIBE.md persona migration', { records: importedPersona });
|
|
374
|
+
}
|
|
375
|
+
} catch (err) {
|
|
376
|
+
logger.warn('agent VIBE.md persona migration failed (non-fatal)', { error: summarizeError(err) });
|
|
377
|
+
}
|
|
378
|
+
|
|
348
379
|
const renderRequestRef = { value: (): void => {} };
|
|
349
380
|
// R1: Coalescing render scheduler — collapses N same-microtask requestRender() calls into 1.
|
|
350
381
|
// Also enforces a 16ms minimum interval to cap at ~60fps during streaming.
|
package/src/runtime/bootstrap.ts
CHANGED
|
@@ -203,10 +203,10 @@ export async function bootstrapRuntime(
|
|
|
203
203
|
services.shellPaths.resolveUserPath(GOODVIBES_AGENT_SURFACE_ROOT, 'prompt-context-receipts.jsonl'),
|
|
204
204
|
);
|
|
205
205
|
let activePromptTurnId: string | null = null;
|
|
206
|
-
// The current turn's raw text
|
|
206
|
+
// The current turn's raw text: the injection seam
|
|
207
207
|
// (composeRuntimePromptWithReceipt, invoked from getSystemPrompt below) needs the
|
|
208
208
|
// active turn's intent to rank the already-eligible memory set by relevance. This is
|
|
209
|
-
// the real seam
|
|
209
|
+
// the real seam that was left unthreaded — TURN_SUBMITTED already carries `prompt`, it
|
|
210
210
|
// was just never captured. Mirrors activePromptTurnId's lifecycle exactly: set on
|
|
211
211
|
// TURN_SUBMITTED, cleared on every terminal event for that turn.
|
|
212
212
|
let activePromptTurnText: string | null = null;
|
|
@@ -551,7 +551,7 @@ export async function bootstrapRuntime(
|
|
|
551
551
|
shellPaths: services.shellPaths,
|
|
552
552
|
surfaceRoot: GOODVIBES_AGENT_SURFACE_ROOT,
|
|
553
553
|
});
|
|
554
|
-
//
|
|
554
|
+
// Refresh explicitly-subscribed external calendar feeds that are DUE
|
|
555
555
|
// per their own bounded interval (conditional 304 requests keep it cheap).
|
|
556
556
|
// Consent was given at subscribe time ("now and on each refresh"); with no
|
|
557
557
|
// subscriptions this touches nothing. Non-blocking — boot never waits on it;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Calendar subscription boot refresh
|
|
2
|
+
* Calendar subscription boot refresh.
|
|
3
3
|
*
|
|
4
4
|
* Fires once from bootstrap's Phase-8 area (after first render, like the gated
|
|
5
5
|
* LAN scan and MCP discovery), fully async and non-blocking: boot never waits on
|