@pellux/goodvibes-tui 0.19.20 → 0.19.23
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 +74 -0
- package/README.md +10 -2
- package/docs/foundation-artifacts/operator-contract.json +1 -1
- package/package.json +2 -2
- package/src/input/handler.ts +2 -0
- package/src/panels/agent-inspector-panel.ts +4 -0
- package/src/panels/wrfc-panel.ts +132 -2
- package/src/renderer/agent-detail-modal.ts +48 -1
- package/src/renderer/process-modal.ts +5 -1
- package/src/runtime/bootstrap-core.ts +58 -0
- package/src/version.ts +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,80 @@ All notable changes to GoodVibes TUI.
|
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
+
## [0.19.23] — 2026-04-22
|
|
8
|
+
|
|
9
|
+
SDK 0.23.x constraint-propagation reconciliation. Surfaces the new per-chain constraint data across the WRFC panel, process modal, agent inspector, and agent detail modal; adds system-message notifications for constraint enumeration and violations; exposes the WRFC-injected `systemPromptAddendum` so operators can see the engineer addendum was applied.
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
|
|
13
|
+
- **SDK dep bumped to `@pellux/goodvibes-sdk@0.23.2`.** Picks up constraint-propagation additions from 0.23.0 (feature), the 0.23.1 cleanup (removed opt-in golden-prompt suite that was skipped by default), and the 0.23.2 docs bundle (the complete `docs/wrfc-constraint-propagation.md` + reference-runtime-events + observability + error-kinds + migration docs shipped with the feature). New types consumed by this TUI release: `Constraint` and `ConstraintFinding` from `platform/agents/completion-report`; three new fields on `WrfcChain` (`constraints`, `constraintsEnumerated`, `syntheticIssues`); `WORKFLOW_CONSTRAINTS_ENUMERATED` runtime event; optional constraint summary fields on `WORKFLOW_REVIEW_COMPLETED` (`constraintsSatisfied`, `constraintsTotal`, `unsatisfiedConstraintIds`) and `WORKFLOW_FIX_ATTEMPTED` (`targetConstraintIds`); optional `constraints?` on `EngineerReport`; optional `constraintFindings?` on `ReviewerReport`; `AgentRecord.systemPromptAddendum?`.
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
|
|
17
|
+
- **`WORKFLOW_CONSTRAINTS_ENUMERATED` system message** (`src/runtime/bootstrap-core.ts`). When an engineer agent enumerates one or more constraints, a low-priority `[WRFC] Engineer enumerated N constraint(s) for chain <chainId>` message is routed to the SystemMessagesPanel. Zero-constraint chains produce no message (backward-compatible).
|
|
18
|
+
- **Constraint-violation system message on review failure** (`src/runtime/bootstrap-core.ts`). When `WORKFLOW_REVIEW_COMPLETED` fires with `passed: false` and `unsatisfiedConstraintIds` is non-empty, a high-priority `[WRFC] ✗ Chain <chainId>: N constraint violation(s) forced failure` message is emitted to both the main conversation and the SystemMessagesPanel. Complements the existing SDK-level score/threshold message.
|
|
19
|
+
- **`WORKFLOW_FIX_ATTEMPTED` constraint-targeting message** (`src/runtime/bootstrap-core.ts`). When a fix agent is spawned to address specific constraints (`targetConstraintIds` present), a low-priority `[WRFC] Fix #N targeting N constraint(s) on chain <chainId>` message is routed to the SystemMessagesPanel. Only fires when `targetConstraintIds` is non-empty.
|
|
20
|
+
- **Constraint count in Fix agent process-modal label** (`src/renderer/process-modal.ts`). When a running fix agent's WRFC chain has constraints, the Background Processes modal label gains a compact `[Nc]` suffix (e.g. `[Fix #2] my task (7.8 → 9.9/10) [3c]`). Chains with zero constraints are unchanged.
|
|
21
|
+
- **`systemPromptAddendum` indicator in Agent Inspector** (`src/panels/agent-inspector-panel.ts`). The per-agent summary line in the Inspector panel now includes an `Addendum yes` field when the selected agent's `AgentRecord.systemPromptAddendum` is set. This lets operators confirm that the WRFC constraint addendum was injected into the engineer's system prompt. Agents without an addendum are unchanged.
|
|
22
|
+
- **Constraint data in Agent Detail modal** (`src/renderer/agent-detail-modal.ts`). The agent detail modal (opened from the Background Processes modal with Enter) now surfaces three additional SDK 0.23.x fields when available: (1) an `Addendum: yes` line when `AgentRecord.systemPromptAddendum` is set; (2) a `Constraints (N):` block listing each constraint id/text/source from the agent's WRFC chain; (3) a `Findings: N checked, N unsatisfied` summary from the reviewer's `constraintFindings`. An optional `wrfcController` dep was added to `AgentDetailModalDeps` — backward-compatible, existing callers without it continue working unchanged. Zero-constraint chains and agents not in a WRFC chain render byte-identically to pre-0.23.
|
|
23
|
+
- **WRFC panel constraint badge** (`src/panels/wrfc-panel.ts`). Each chain row renders a compact `c:N/M` badge showing satisfied/total constraints when present, colored by aggregate state: green when all satisfied, red on any unsatisfied finding, grey when no findings yet, yellow for mixed verified/unverified. Omitted entirely for zero-constraint chains.
|
|
24
|
+
- **WRFC panel expanded constraint detail** (`src/panels/wrfc-panel.ts`). Expanding a chain now shows per-constraint lines with a severity-tagged status marker: `[SAT]` (satisfied), `[UNS CRIT]` / `[UNS MAJOR]` / `[UNS MINOR]` (unsatisfied with severity), or `[UNV]` (unverified). Inherited constraints — those carried from a parent chain after gate-failure retry — are suffixed with ` *`. List caps at 10 with a `(+N more)` tail and respects the panel's `maxLines` budget.
|
|
25
|
+
- **WRFC panel selected-chain summary** (`src/panels/wrfc-panel.ts`). The selected-chain summary row now shows `N sat / M total (K inherited)` when the focused chain has constraints, giving the operator at-a-glance status without expanding the row.
|
|
26
|
+
- **WRFC panel controller-flags block** (`src/panels/wrfc-panel.ts`). When the controller injects synthetic issues on the chain (e.g. fixer constraint-continuity violations), a `Controller flags` section renders above the reviewer Issues block with a `[CRITICAL]` prefix, so operators see why a chain went back to fixing even when the reviewer didn't flag anything.
|
|
27
|
+
|
|
28
|
+
### Surface Audit — Per-Surface Verdict
|
|
29
|
+
|
|
30
|
+
| Surface | File | Verdict |
|
|
31
|
+
|---------|------|---------|
|
|
32
|
+
| WRFC chain panel | `src/panels/wrfc-panel.ts` | Reconciled — constraint badge `c:N/M`, expanded-detail severity-tagged markers (`[SAT]` / `[UNS CRIT|MAJOR|MINOR]` / `[UNV]`) with inherited ` *` suffix, selected-chain summary, controller-flags block, `WORKFLOW_CONSTRAINTS_ENUMERATED` subscription |
|
|
33
|
+
| System message router | `src/core/system-message-router.ts` | Not applicable — routing infrastructure, no direct event handling |
|
|
34
|
+
| Bootstrap runtime events | `src/runtime/bootstrap-core.ts` | Reconciled — 3 new subscriptions added |
|
|
35
|
+
| Process modal | `src/renderer/process-modal.ts` | Reconciled — Fix label shows constraint count |
|
|
36
|
+
| Agent Inspector panel | `src/panels/agent-inspector-panel.ts` | Reconciled — systemPromptAddendum indicator |
|
|
37
|
+
| Agent Logs panel | `src/panels/agent-logs-panel.ts` | Not applicable — log tail only, no report/constraint fields |
|
|
38
|
+
| Agent Detail modal | `src/renderer/agent-detail-modal.ts` | Reconciled — systemPromptAddendum indicator, constraint list, reviewer findings |
|
|
39
|
+
| Orchestration panel | `src/panels/orchestration-panel.ts` | Not applicable — reads `OrchestrationGraphRecord` from store domain, no constraint fields |
|
|
40
|
+
| Agent builtin panel registry | `src/panels/builtin/agent.ts` | Not applicable — registration only, no rendering |
|
|
41
|
+
| Tasks panel | `src/panels/builtin/operations.ts` | Not applicable — no WRFC chain rendering |
|
|
42
|
+
| Eval panel | `src/panels/eval-panel.ts` | Not applicable — eval suite scores, not WRFC constraint data |
|
|
43
|
+
| UI events plumbing | `src/runtime/ui-events.ts` | Not applicable — re-exports SDK; `WorkflowEvent` union already includes new event |
|
|
44
|
+
| Config command | `src/input/commands/config.ts` | Not applicable — no new SDK 0.23.0 config knobs |
|
|
45
|
+
| Runtime services | `src/runtime/services.ts` | Not applicable — no new service instantiation required |
|
|
46
|
+
| Bootstrap core | `src/runtime/bootstrap-core.ts` | Reconciled (see above) |
|
|
47
|
+
| Docs | `docs/` | Not applicable — TUI docs have minimal WRFC prose; no legacy content to update |
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## [0.19.22] — 2026-04-21
|
|
52
|
+
|
|
53
|
+
Hotfix release: regenerates foundation artifacts against SDK 0.22.0 after 0.19.21's release pipeline failed the `foundation artifacts gate` test. No consumer-facing feature changes beyond what 0.19.21 carried.
|
|
54
|
+
|
|
55
|
+
### Fixed
|
|
56
|
+
- **`docs/foundation-artifacts/operator-contract.json` regenerated against SDK 0.22.0.** The 0.19.21 tag shipped with an artifact stamped `"version": "0.21.36"` while consuming SDK 0.22.0 — the `foundation artifacts gate` release-gates test detected this drift and failed the release workflow on the `Tests` step, blocking the npm publish. 0.19.22 contains the regenerated artifact (one-line version-stamp update) and ships cleanly.
|
|
57
|
+
- **CI: composite `./.github/actions/setup` action** shared across every `ci.yml` and `release.yml` job: pins Bun 1.3.10, restores `~/.bun/install/cache` via `actions/cache@v4`, runs `bun install`. Eliminates ~60 lines of duplicated setup boilerplate and gives every job a warm dep cache.
|
|
58
|
+
|
|
59
|
+
### Internal
|
|
60
|
+
- Reconciliation sweep against SDK 0.22.0 confirmed no other TUI drift: typecheck clean, architecture check clean, 456/456 test files pass.
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## [0.19.21] — 2026-04-21
|
|
65
|
+
|
|
66
|
+
Maintenance release: SDK 0.22.0 bump + README/gitignore hygiene + test-timeout polish. **Did not publish** — the release workflow's foundation-artifacts gate detected stale artifact drift against SDK 0.22.0; see 0.19.22 for the shipped fix. No consumer-facing feature or behavior changes.
|
|
67
|
+
|
|
68
|
+
### Changed
|
|
69
|
+
- **SDK dep bumped to `@pellux/goodvibes-sdk@0.22.0`.** Picks up the SDK's contract-artifact refresh pipeline, documentation audit, and test-suite cleanup. No TUI code paths change; the bump is source-compatible.
|
|
70
|
+
- **Active-early-development banner** added near the top of `README.md`. Signals that CLI flags, config keys, slash commands, key bindings, daemon routes, and on-disk layouts can change across patch releases pre-1.0; no legacy/compat shims; docs describe current behavior only. 1.0.0 is the stability freeze.
|
|
71
|
+
|
|
72
|
+
### Fixed
|
|
73
|
+
- Raised timeouts on three flaky edit-tool tests from the default 5 s to 7.5 s (`edit tool > fuzzy matching > matches despite extra whitespace`, `edit tool > batch edits on different files > applies edits to multiple files`, `edit tool > ast_pattern mode > respects occurrence number selector`). These were intermittently tripping on heavily-loaded CI runners despite the underlying operation completing well under 5 s on fast hardware.
|
|
74
|
+
|
|
75
|
+
### Internal
|
|
76
|
+
- `docs/uat/` added to `.gitignore` and existing UAT reports untracked (kept on disk locally). UAT validation reports are live-daemon smoke results, not canonical documentation.
|
|
77
|
+
- `:memory:` filename added to `.gitignore` — prevents regression of an SQLite-sentinel-as-path test leak.
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
7
81
|
## [0.19.20] — 2026-04-21
|
|
8
82
|
|
|
9
83
|
### Changes
|
package/README.md
CHANGED
|
@@ -2,10 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://github.com/mgd34msu/goodvibes-tui/actions/workflows/ci.yml)
|
|
4
4
|
[](https://opensource.org/licenses/MIT)
|
|
5
|
-
[](https://github.com/mgd34msu/goodvibes-tui)
|
|
6
6
|
|
|
7
7
|
A terminal-native AI coding, operations, automation, knowledge, and integration console with a typed runtime, omnichannel surfaces, structured memory/knowledge, and a raw ANSI renderer.
|
|
8
8
|
|
|
9
|
+
> ⚠️ **Active early development — pre-1.0.** This project is under active early development. CLI flags, config keys, slash commands, key bindings, daemon routes, and on-disk layouts can and do change quickly — sometimes across patch releases. There are no legacy/compat shims. Documentation always describes the **current** behavior, not historical behavior. When 1.0.0 ships the project freezes to enterprise-grade stability guarantees (semver, deprecation windows, migration guides). Until then: pin exact versions and read `CHANGELOG.md` before upgrading.
|
|
10
|
+
|
|
9
11
|
<!-- screenshot -->
|
|
10
12
|
|
|
11
13
|
---
|
|
@@ -157,6 +159,12 @@ The TUI now consumes the extracted `@pellux/goodvibes-sdk` platform layer for sh
|
|
|
157
159
|
- Archetype registry that supports built-ins and user-defined markdown archetypes
|
|
158
160
|
- Task lifecycle tracking across exec, agent, MCP, plugin, integration, daemon, scheduler, and ACP work
|
|
159
161
|
- Automated WRFC loops with review/fix/check chains, configurable gates, and explicit evidence in completion reports
|
|
162
|
+
- WRFC panel renders a constraint badge (`c:N/M`) per chain, colored by aggregate satisfaction status
|
|
163
|
+
- Expanded chain detail shows each constraint with status marker `[SAT]`, `[UNS CRIT|MAJOR|MINOR]` (unsatisfied, severity-tagged), or `[UNV]` (unverified), with ` *` suffix for inherited constraints
|
|
164
|
+
- Selected-chain summary shows satisfied/total/inherited counts at a glance
|
|
165
|
+
- Controller-flagged synthetic issues render above reviewer issues as `[CRITICAL]` "Controller flags"
|
|
166
|
+
- Agent-detail modal surfaces `systemPromptAddendum` (WRFC engineer addendum) when present on the agent record
|
|
167
|
+
- System-message router surfaces `WORKFLOW_CONSTRAINTS_ENUMERATED` as an operator-visible message when constraints are loaded
|
|
160
168
|
- Built-in planning/strategy layer with execution plans, adaptive plan modes, and status/explain/override controls
|
|
161
169
|
|
|
162
170
|
### Tools And Intelligence
|
|
@@ -1233,7 +1241,7 @@ Those pieces cover conversation-noise routing, panel-health/performance budgets,
|
|
|
1233
1241
|
| `/fork [name]` | `/branch-save` | Save a named snapshot of the current conversation |
|
|
1234
1242
|
| `/merge <name>` | — | Append messages from a branch after the fork point |
|
|
1235
1243
|
| `/agents` | — | List active and completed agents |
|
|
1236
|
-
| `/wrfc` | — | Show WRFC chain status |
|
|
1244
|
+
| `/wrfc` | — | Show WRFC chain status, constraint satisfaction counts, and per-constraint `[SAT]`/`[UNS]`/`[UNV]` breakdown |
|
|
1237
1245
|
| `/health [action]` | — | Unified runtime health review and repair entry point |
|
|
1238
1246
|
| `/guidance [action]` | — | Contextual operational guidance without cluttering the conversation |
|
|
1239
1247
|
| `/remote [action]` | — | Distributed peer, node-host contract, work-queue, and artifact control room |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pellux/goodvibes-tui",
|
|
3
|
-
"version": "0.19.
|
|
3
|
+
"version": "0.19.23",
|
|
4
4
|
"description": "Terminal-native GoodVibes product for coding, operations, automation, knowledge, channels, and daemon-backed control-plane workflows.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/main.ts",
|
|
@@ -90,7 +90,7 @@
|
|
|
90
90
|
"@anthropic-ai/vertex-sdk": "^0.16.0",
|
|
91
91
|
"@ast-grep/napi": "^0.42.0",
|
|
92
92
|
"@aws/bedrock-token-generator": "^1.1.0",
|
|
93
|
-
"@pellux/goodvibes-sdk": "0.
|
|
93
|
+
"@pellux/goodvibes-sdk": "0.23.2",
|
|
94
94
|
"bash-language-server": "^5.6.0",
|
|
95
95
|
"fuse.js": "^7.1.0",
|
|
96
96
|
"graphql": "^16.13.2",
|
package/src/input/handler.ts
CHANGED
|
@@ -207,6 +207,8 @@ export class InputHandler {
|
|
|
207
207
|
agentManager: uiServices.agents.agentManager,
|
|
208
208
|
agentMessageBus: uiServices.agents.agentMessageBus,
|
|
209
209
|
sessionLogPathResolver: (agentId) => uiServices.environment.shellPaths.resolveProjectPath('tui', 'sessions', `${agentId}.jsonl`),
|
|
210
|
+
// SDK 0.23.0: supply wrfcController so the modal can show constraint data
|
|
211
|
+
wrfcController: uiServices.agents.wrfcController,
|
|
210
212
|
});
|
|
211
213
|
this.bookmarkModal = new BookmarkModal(uiServices.shell.bookmarkManager);
|
|
212
214
|
this.sessionPickerModal = new SessionPickerModal(uiServices.sessions.sessionManager);
|
|
@@ -317,6 +317,10 @@ export class AgentInspectorPanel extends BasePanel {
|
|
|
317
317
|
[formatMs(elapsed), DEFAULT_PANEL_PALETTE.value],
|
|
318
318
|
[' Tools ', DEFAULT_PANEL_PALETTE.label],
|
|
319
319
|
[String(rec.toolCallCount), DEFAULT_PANEL_PALETTE.info],
|
|
320
|
+
// SDK 0.23.0: show addendum indicator when WRFC injected a constraint addendum
|
|
321
|
+
...(rec.systemPromptAddendum
|
|
322
|
+
? [[' Addendum ', DEFAULT_PANEL_PALETTE.label] as [string, string], ['yes', DEFAULT_PANEL_PALETTE.info] as [string, string]]
|
|
323
|
+
: []),
|
|
320
324
|
[' Task ', DEFAULT_PANEL_PALETTE.label],
|
|
321
325
|
[taskDisplay, DEFAULT_PANEL_PALETTE.value],
|
|
322
326
|
]);
|
package/src/panels/wrfc-panel.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Line } from '../types/grid.ts';
|
|
2
2
|
import type { WrfcChain, WrfcState, QualityGateResult } from '@pellux/goodvibes-sdk/platform/agents/wrfc-types';
|
|
3
|
+
import type { Constraint, ConstraintFinding } from '@pellux/goodvibes-sdk/platform/agents/completion-report';
|
|
3
4
|
import type { WrfcController } from '@pellux/goodvibes-sdk/platform/agents/wrfc-controller';
|
|
4
5
|
import { BasePanel } from './base-panel.ts';
|
|
5
6
|
import type { WorkflowEvent } from '@pellux/goodvibes-sdk/platform/runtime/events/index';
|
|
@@ -48,6 +49,10 @@ const C = {
|
|
|
48
49
|
issueSug: '#6b7280',
|
|
49
50
|
gatePass: '#22c55e',
|
|
50
51
|
gateFail: '#ef4444',
|
|
52
|
+
// constraint status
|
|
53
|
+
constraintSat: '#22c55e', // green — satisfied
|
|
54
|
+
constraintUnsat:'#ef4444', // red — unsatisfied
|
|
55
|
+
constraintUnv: '#4b5563', // grey — unverified (no finding yet)
|
|
51
56
|
} as const;
|
|
52
57
|
|
|
53
58
|
// ---------------------------------------------------------------------------
|
|
@@ -117,6 +122,37 @@ export function truncate(s: string, max: number): string {
|
|
|
117
122
|
return s.slice(0, max - 3) + '...';
|
|
118
123
|
}
|
|
119
124
|
|
|
125
|
+
// ---------------------------------------------------------------------------
|
|
126
|
+
// Constraint helpers
|
|
127
|
+
// ---------------------------------------------------------------------------
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Returns display tag, foreground colour, and dim flag for a single constraint
|
|
131
|
+
* based on whether a reviewer finding exists for it.
|
|
132
|
+
*/
|
|
133
|
+
export function constraintStatusMarker(
|
|
134
|
+
constraint: Constraint,
|
|
135
|
+
findings: ConstraintFinding[] | undefined,
|
|
136
|
+
): { tag: string; fg: string; dim: boolean } {
|
|
137
|
+
const finding = findings?.find(f => f.constraintId === constraint.id);
|
|
138
|
+
if (!finding) {
|
|
139
|
+
return { tag: '[UNV]', fg: C.constraintUnv, dim: true };
|
|
140
|
+
}
|
|
141
|
+
if (finding.satisfied) {
|
|
142
|
+
return { tag: '[SAT]', fg: C.constraintSat, dim: false };
|
|
143
|
+
}
|
|
144
|
+
// Unsatisfied — use severity to pick colour and tag text
|
|
145
|
+
const sev = finding.severity ?? 'major';
|
|
146
|
+
let sevTag: string;
|
|
147
|
+
let fg: string;
|
|
148
|
+
switch (sev) {
|
|
149
|
+
case 'critical': sevTag = '[UNS CRIT]'; fg = C.issueCrit; break;
|
|
150
|
+
case 'minor': sevTag = '[UNS MINOR]'; fg = C.issueMin; break;
|
|
151
|
+
default: sevTag = '[UNS MAJOR]'; fg = C.issueMaj; break;
|
|
152
|
+
}
|
|
153
|
+
return { tag: sevTag, fg, dim: false };
|
|
154
|
+
}
|
|
155
|
+
|
|
120
156
|
// ---------------------------------------------------------------------------
|
|
121
157
|
// Panel
|
|
122
158
|
// ---------------------------------------------------------------------------
|
|
@@ -228,6 +264,22 @@ export class WrfcPanel extends BasePanel {
|
|
|
228
264
|
[' Scores ', DEFAULT_PANEL_PALETTE.label],
|
|
229
265
|
[selectedChain.reviewScores.length > 0 ? selectedChain.reviewScores.map((score) => score.toFixed(0)).join(' -> ') : 'none', DEFAULT_PANEL_PALETTE.info],
|
|
230
266
|
]),
|
|
267
|
+
...(selectedChain.constraints.length > 0 ? [
|
|
268
|
+
buildPanelLine(width, (() => {
|
|
269
|
+
const total = selectedChain.constraints.length;
|
|
270
|
+
const findings = selectedChain.reviewerReport?.constraintFindings;
|
|
271
|
+
const satisfied = findings ? findings.filter(f => f.satisfied).length : 0;
|
|
272
|
+
const inherited = selectedChain.constraints.filter(c => c.source === 'inherited').length;
|
|
273
|
+
const inheritedPart = inherited > 0 ? ` (${inherited} inherited)` : '';
|
|
274
|
+
const satFg = !findings || findings.length === 0
|
|
275
|
+
? DEFAULT_PANEL_PALETTE.dim
|
|
276
|
+
: satisfied === total ? C.constraintSat : C.constraintUnsat;
|
|
277
|
+
return [
|
|
278
|
+
[' Constraints ', DEFAULT_PANEL_PALETTE.label],
|
|
279
|
+
[`${satisfied} sat / ${total} total${inheritedPart}`, satFg],
|
|
280
|
+
] as Array<[string, string]>;
|
|
281
|
+
})()),
|
|
282
|
+
] : []),
|
|
231
283
|
]
|
|
232
284
|
: [];
|
|
233
285
|
|
|
@@ -300,7 +352,15 @@ export class WrfcPanel extends BasePanel {
|
|
|
300
352
|
const latestScore = chain.reviewScores.length > 0
|
|
301
353
|
? ` ${chain.reviewScores[chain.reviewScores.length - 1].toFixed(1)}/10`
|
|
302
354
|
: '';
|
|
303
|
-
|
|
355
|
+
// Constraint badge: c:sat/total — only when constraints exist
|
|
356
|
+
let constraintBadge = '';
|
|
357
|
+
if (chain.constraints.length > 0) {
|
|
358
|
+
const total = chain.constraints.length;
|
|
359
|
+
const findings = chain.reviewerReport?.constraintFindings;
|
|
360
|
+
const satisfied = findings ? findings.filter(f => f.satisfied).length : 0;
|
|
361
|
+
constraintBadge = ` c:${satisfied}/${total}`;
|
|
362
|
+
}
|
|
363
|
+
const rightInfo = `${latestScore}${fixes}${cycles}${constraintBadge} `;
|
|
304
364
|
|
|
305
365
|
// Compute how much space the task text can use, then check if rightInfo fits.
|
|
306
366
|
// If the terminal is narrow and rightInfo would overflow, omit it entirely
|
|
@@ -319,7 +379,32 @@ export class WrfcPanel extends BasePanel {
|
|
|
319
379
|
];
|
|
320
380
|
if (remaining >= rightInfo.length + 1) {
|
|
321
381
|
// Right-align rightInfo in the remaining space
|
|
322
|
-
|
|
382
|
+
// Colour the constraint badge separately when present
|
|
383
|
+
if (chain.constraints.length > 0 && !isSelected) {
|
|
384
|
+
const total = chain.constraints.length;
|
|
385
|
+
const findings = chain.reviewerReport?.constraintFindings;
|
|
386
|
+
const satisfied = findings ? findings.filter(f => f.satisfied).length : 0;
|
|
387
|
+
// Determine badge colour
|
|
388
|
+
let badgeFg: string;
|
|
389
|
+
if (!findings || findings.length === 0) {
|
|
390
|
+
badgeFg = C.constraintUnv;
|
|
391
|
+
} else if (satisfied === total) {
|
|
392
|
+
badgeFg = C.constraintSat;
|
|
393
|
+
} else if (findings.some(f => !f.satisfied)) {
|
|
394
|
+
badgeFg = C.constraintUnsat;
|
|
395
|
+
} else {
|
|
396
|
+
badgeFg = C.reviewing; // some unverified but none failed
|
|
397
|
+
}
|
|
398
|
+
// Split: everything before the badge, then the badge
|
|
399
|
+
const badgeText = ` c:${satisfied}/${total}`;
|
|
400
|
+
const beforeBadge = rightInfo.slice(0, rightInfo.length - badgeText.length - 1);
|
|
401
|
+
const padding = remaining - rightInfo.length;
|
|
402
|
+
segments.push({ text: beforeBadge.padStart(padding + beforeBadge.length), fg: isSelected ? fg : C.label });
|
|
403
|
+
segments.push({ text: badgeText, fg: badgeFg });
|
|
404
|
+
segments.push({ text: ' ', fg: '' });
|
|
405
|
+
} else {
|
|
406
|
+
segments.push({ text: rightInfo.padStart(remaining), fg: isSelected ? fg : C.label });
|
|
407
|
+
}
|
|
323
408
|
}
|
|
324
409
|
// else: no room — makeSegmentedLine will pad with spaces to fill width
|
|
325
410
|
|
|
@@ -358,6 +443,35 @@ export class WrfcPanel extends BasePanel {
|
|
|
358
443
|
]));
|
|
359
444
|
}
|
|
360
445
|
|
|
446
|
+
// Constraints section (between Cycles and Gates)
|
|
447
|
+
if (chain.constraints.length > 0 && lines.length < maxLines) {
|
|
448
|
+
lines.push(buildStyledPanelLine(width, [{ text: `${indent}Constraints`, fg: C.label }]));
|
|
449
|
+
const MAX_CONSTRAINTS = 10;
|
|
450
|
+
const findings = chain.reviewerReport?.constraintFindings;
|
|
451
|
+
const displayed = chain.constraints.slice(0, MAX_CONSTRAINTS);
|
|
452
|
+
for (const constraint of displayed) {
|
|
453
|
+
if (lines.length >= maxLines) break;
|
|
454
|
+
const marker = constraintStatusMarker(constraint, findings);
|
|
455
|
+
const inheritedMark = constraint.source === 'inherited' ? ' *' : '';
|
|
456
|
+
const statusTag = `${marker.tag}${inheritedMark}`;
|
|
457
|
+
const rowPrefix = `${indent} ${statusTag} `;
|
|
458
|
+
const textMax = Math.max(8, width - rowPrefix.length);
|
|
459
|
+
const constraintText = truncate(constraint.text, textMax);
|
|
460
|
+
lines.push(buildStyledPanelLine(width, [
|
|
461
|
+
{ text: `${indent} `, fg: C.dim },
|
|
462
|
+
{ text: statusTag, fg: marker.fg, dim: marker.dim, bold: !marker.dim },
|
|
463
|
+
{ text: ' ', fg: '' },
|
|
464
|
+
{ text: constraintText, fg: C.value },
|
|
465
|
+
]));
|
|
466
|
+
}
|
|
467
|
+
const remaining = chain.constraints.length - MAX_CONSTRAINTS;
|
|
468
|
+
if (remaining > 0 && lines.length < maxLines) {
|
|
469
|
+
lines.push(buildStyledPanelLine(width, [
|
|
470
|
+
{ text: `${indent} (+${remaining} more)`, fg: C.dim, dim: true },
|
|
471
|
+
]));
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
|
|
361
475
|
// Quality gate results
|
|
362
476
|
if (chain.gateResults && chain.gateResults.length > 0) {
|
|
363
477
|
lines.push(buildStyledPanelLine(width, [{ text: `${indent}Gates`, fg: C.label }]));
|
|
@@ -374,6 +488,21 @@ export class WrfcPanel extends BasePanel {
|
|
|
374
488
|
}
|
|
375
489
|
}
|
|
376
490
|
|
|
491
|
+
// Synthetic issues injected by controller (continuity violations)
|
|
492
|
+
if (chain.syntheticIssues && chain.syntheticIssues.length > 0 && lines.length < maxLines) {
|
|
493
|
+
lines.push(buildStyledPanelLine(width, [{ text: `${indent}Controller flags`, fg: C.issueCrit, bold: true }]));
|
|
494
|
+
for (const synthetic of chain.syntheticIssues) {
|
|
495
|
+
if (lines.length >= maxLines) break;
|
|
496
|
+
const prefix = `${indent} [CRIT] `;
|
|
497
|
+
const descMax = Math.max(8, width - prefix.length);
|
|
498
|
+
const desc = truncate(synthetic.description, descMax);
|
|
499
|
+
lines.push(buildStyledPanelLine(width, [
|
|
500
|
+
{ text: prefix, fg: C.issueCrit, bold: true },
|
|
501
|
+
{ text: desc, fg: C.value },
|
|
502
|
+
]));
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
|
|
377
506
|
// Issues from reviewer
|
|
378
507
|
const issues = chain.reviewerReport?.issues ?? [];
|
|
379
508
|
if (issues.length > 0 && lines.length < maxLines) {
|
|
@@ -458,6 +587,7 @@ export class WrfcPanel extends BasePanel {
|
|
|
458
587
|
this.workflowEvents.on('WORKFLOW_CHAIN_FAILED', refresh),
|
|
459
588
|
this.workflowEvents.on('WORKFLOW_AUTO_COMMITTED', refresh),
|
|
460
589
|
this.workflowEvents.on('WORKFLOW_CASCADE_ABORTED', refresh),
|
|
590
|
+
this.workflowEvents.on('WORKFLOW_CONSTRAINTS_ENUMERATED', refresh),
|
|
461
591
|
);
|
|
462
592
|
}
|
|
463
593
|
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { join } from 'path';
|
|
2
1
|
import { readFile } from 'fs/promises';
|
|
3
2
|
import { type Line } from '../types/grid.ts';
|
|
4
3
|
import { ModalFactory } from './modal-factory.ts';
|
|
5
4
|
import type { AgentManager } from '@pellux/goodvibes-sdk/platform/tools/agent/index';
|
|
6
5
|
import type { AgentMessageBus } from '@pellux/goodvibes-sdk/platform/agents/message-bus';
|
|
6
|
+
import type { WrfcController } from '@pellux/goodvibes-sdk/platform/agents/wrfc-controller';
|
|
7
7
|
import { formatDuration } from './modal-utils.ts';
|
|
8
8
|
import { logger } from '@pellux/goodvibes-sdk/platform/utils/logger';
|
|
9
9
|
import { getOverlaySurfaceMetrics, getStableOverlayContentRows } from './overlay-viewport.ts';
|
|
@@ -19,6 +19,8 @@ export interface AgentDetailModalDeps {
|
|
|
19
19
|
readonly agentManager: Pick<AgentManager, 'getStatus'>;
|
|
20
20
|
readonly agentMessageBus: Pick<AgentMessageBus, 'getMessages'>;
|
|
21
21
|
readonly sessionLogPathResolver: (agentId: string) => string;
|
|
22
|
+
/** Optional — when supplied, constraint data from the agent's WRFC chain is shown (SDK 0.23.0). */
|
|
23
|
+
readonly wrfcController?: Pick<WrfcController, 'getChain'>;
|
|
22
24
|
}
|
|
23
25
|
|
|
24
26
|
// ─── AgentDetailModal ─────────────────────────────────────────────────────────
|
|
@@ -176,6 +178,51 @@ export function renderAgentDetailModal(
|
|
|
176
178
|
sections.push({ type: 'text', content: `Tool calls : ${rec.toolCallCount}` });
|
|
177
179
|
sections.push({ type: 'text', content: `Est tokens : ~${tokenEst.toLocaleString()}` });
|
|
178
180
|
|
|
181
|
+
// SDK 0.23.0: systemPromptAddendum indicator — confirms WRFC constraint addendum was injected
|
|
182
|
+
if (rec.systemPromptAddendum) {
|
|
183
|
+
sections.push({
|
|
184
|
+
type: 'text',
|
|
185
|
+
content: 'Addendum : yes (WRFC constraint layer injected)',
|
|
186
|
+
style: { fg: '#aaffee' },
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// SDK 0.23.0: constraint data from WRFC chain (engineer constraints + reviewer findings)
|
|
191
|
+
if (rec.wrfcId && modal.deps.wrfcController) {
|
|
192
|
+
try {
|
|
193
|
+
const chain = modal.deps.wrfcController.getChain(rec.wrfcId);
|
|
194
|
+
if (chain && chain.constraints.length > 0) {
|
|
195
|
+
sections.push({ type: 'separator' });
|
|
196
|
+
sections.push({
|
|
197
|
+
type: 'text',
|
|
198
|
+
content: `Constraints (${chain.constraints.length}):`,
|
|
199
|
+
style: { dim: true },
|
|
200
|
+
});
|
|
201
|
+
for (const c of chain.constraints) {
|
|
202
|
+
const src = c.source === 'inherited' ? ' [inherited]' : '';
|
|
203
|
+
const text = c.text.length > 80 ? c.text.slice(0, 77) + '…' : c.text;
|
|
204
|
+
sections.push({
|
|
205
|
+
type: 'text',
|
|
206
|
+
content: ` [${c.id}]${src} ${text}`,
|
|
207
|
+
style: { fg: '246' },
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
// Reviewer constraint findings (if review has completed)
|
|
211
|
+
const findings = chain.reviewerReport?.constraintFindings;
|
|
212
|
+
if (findings && findings.length > 0) {
|
|
213
|
+
const unsatisfied = findings.filter((f) => !f.satisfied);
|
|
214
|
+
sections.push({
|
|
215
|
+
type: 'text',
|
|
216
|
+
content: `Findings : ${findings.length} checked, ${unsatisfied.length} unsatisfied`,
|
|
217
|
+
style: { fg: unsatisfied.length > 0 ? '#ff6666' : '#44ff88' },
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
} catch {
|
|
222
|
+
// wrfcController.getChain throws when chain not found — normal during teardown
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
179
226
|
// Progress
|
|
180
227
|
if (rec.progress) {
|
|
181
228
|
sections.push({ type: 'separator' });
|
|
@@ -60,7 +60,11 @@ function buildAgentLabel(rec: AgentRecord, deps: ProcessModalDeps): string {
|
|
|
60
60
|
const attemptMatch = task.match(/Fix attempt:\s*(\d+)/);
|
|
61
61
|
const attempt = attemptMatch ? attemptMatch[1] : '?';
|
|
62
62
|
const desc = truncateFirst(originalTask ?? 'fix in progress', 45);
|
|
63
|
-
|
|
63
|
+
// Show constraint count when the chain has constraints to target (SDK 0.23.0)
|
|
64
|
+
const chain = rec.wrfcId ? (() => { try { return deps.wrfcController.getChain(rec.wrfcId!); } catch { return null; } })() : null;
|
|
65
|
+
const constraintCount = chain && chain.constraints.length > 0 ? chain.constraints.length : 0;
|
|
66
|
+
const constraintSuffix = constraintCount > 0 ? ` [${constraintCount}c]` : '';
|
|
67
|
+
return `[Fix #${attempt}] ${desc} (${fromScore} \u2192 ${toScore}/10)${constraintSuffix}`;
|
|
64
68
|
}
|
|
65
69
|
|
|
66
70
|
// Regular agent — show template and truncated first line
|
|
@@ -292,6 +292,64 @@ export async function initializeBootstrapCore(
|
|
|
292
292
|
wrfcController: services.wrfcController,
|
|
293
293
|
});
|
|
294
294
|
|
|
295
|
+
// ── TUI-specific WRFC constraint-propagation event subscriptions (SDK 0.23.0) ──
|
|
296
|
+
// These supplement the SDK's registerBootstrapRuntimeEvents which handles the
|
|
297
|
+
// core WORKFLOW_REVIEW_COMPLETED / WORKFLOW_CHAIN_CREATED messages.
|
|
298
|
+
// The SDK does not surface constraint-specific system messages; the TUI layer
|
|
299
|
+
// adds them here so operators can observe constraint enumeration and violations
|
|
300
|
+
// in the SystemMessagesPanel and main conversation.
|
|
301
|
+
runtimeUnsubs.push(
|
|
302
|
+
runtimeBus.on<Extract<import('@pellux/goodvibes-sdk/platform/runtime/events/index').WorkflowEvent, { type: 'WORKFLOW_CONSTRAINTS_ENUMERATED' }>>(
|
|
303
|
+
'WORKFLOW_CONSTRAINTS_ENUMERATED',
|
|
304
|
+
({ payload }) => {
|
|
305
|
+
const router = systemMessageRouterRef.value;
|
|
306
|
+
if (!router) return;
|
|
307
|
+
const count = payload.constraints.length;
|
|
308
|
+
if (count > 0) {
|
|
309
|
+
router.wrfc(
|
|
310
|
+
`[WRFC] Engineer enumerated ${count} constraint${count !== 1 ? 's' : ''} for chain ${payload.chainId.slice(0, 12)}`,
|
|
311
|
+
'low',
|
|
312
|
+
);
|
|
313
|
+
}
|
|
314
|
+
requestRender();
|
|
315
|
+
},
|
|
316
|
+
),
|
|
317
|
+
);
|
|
318
|
+
runtimeUnsubs.push(
|
|
319
|
+
runtimeBus.on<Extract<import('@pellux/goodvibes-sdk/platform/runtime/events/index').WorkflowEvent, { type: 'WORKFLOW_FIX_ATTEMPTED' }>>(
|
|
320
|
+
'WORKFLOW_FIX_ATTEMPTED',
|
|
321
|
+
({ payload }) => {
|
|
322
|
+
const router = systemMessageRouterRef.value;
|
|
323
|
+
if (!router) return;
|
|
324
|
+
const targetIds = payload.targetConstraintIds;
|
|
325
|
+
if (targetIds && targetIds.length > 0) {
|
|
326
|
+
router.wrfc(
|
|
327
|
+
`[WRFC] Fix #${payload.attempt} targeting ${targetIds.length} constraint${targetIds.length !== 1 ? 's' : ''} on chain ${payload.chainId.slice(0, 12)}`,
|
|
328
|
+
'low',
|
|
329
|
+
);
|
|
330
|
+
requestRender();
|
|
331
|
+
}
|
|
332
|
+
},
|
|
333
|
+
),
|
|
334
|
+
);
|
|
335
|
+
runtimeUnsubs.push(
|
|
336
|
+
runtimeBus.on<Extract<import('@pellux/goodvibes-sdk/platform/runtime/events/index').WorkflowEvent, { type: 'WORKFLOW_REVIEW_COMPLETED' }>>(
|
|
337
|
+
'WORKFLOW_REVIEW_COMPLETED',
|
|
338
|
+
({ payload }) => {
|
|
339
|
+
const router = systemMessageRouterRef.value;
|
|
340
|
+
if (!router) return;
|
|
341
|
+
const unsatisfied = payload.unsatisfiedConstraintIds;
|
|
342
|
+
if (!payload.passed && unsatisfied && unsatisfied.length > 0) {
|
|
343
|
+
router.wrfc(
|
|
344
|
+
`[WRFC] ✗ Chain ${payload.chainId.slice(0, 12)}: ${unsatisfied.length} constraint violation${unsatisfied.length !== 1 ? 's' : ''} forced failure`,
|
|
345
|
+
'high',
|
|
346
|
+
);
|
|
347
|
+
requestRender();
|
|
348
|
+
}
|
|
349
|
+
},
|
|
350
|
+
),
|
|
351
|
+
);
|
|
352
|
+
|
|
295
353
|
// Subscribe to companion main-chat messages received from the daemon's HTTP layer.
|
|
296
354
|
// The daemon emits COMPANION_MESSAGE_RECEIVED on the runtime bus when a companion
|
|
297
355
|
// POST /api/sessions/:id/messages with kind='message' arrives.
|
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.19.
|
|
9
|
+
let _version = '0.19.23';
|
|
10
10
|
try {
|
|
11
11
|
const pkg = JSON.parse(readFileSync(join(import.meta.dir, '..', 'package.json'), 'utf-8'));
|
|
12
12
|
_version = pkg.version ?? _version;
|