Skip to content

feat: implement Generalized Extension UI System (Hybrid Schema) - #8

Open
hdkiller wants to merge 3 commits into
BlackBeltTechnology:developfrom
hdkiller:feat/generalized-ui-system
Open

feat: implement Generalized Extension UI System (Hybrid Schema)#8
hdkiller wants to merge 3 commits into
BlackBeltTechnology:developfrom
hdkiller:feat/generalized-ui-system

Conversation

@hdkiller

Copy link
Copy Markdown

This PR introduces a major architectural shift from hardcoded extension dialogs to a generalized, metadata-driven UI system.

Key Improvements:

  1. Generalized UI Rendering: Introduced which renders interactive menus (tables, forms, navigation) based on schemas provided by extensions via the event.
  2. Unified Protocol: Consolidated feature-specific messages into universal and types.
  3. Server-Side Caching: The server now caches UI modules and data lists in the session object, ensuring they survive browser refreshes and are immediately available to new clients.
  4. Global Notifications: Integrated a global Toast notification system listening for events.
  5. Decoupling: Removed all hardcoded logic for and from the dashboard core.
  6. Documentation: Added comprehensive documentation in for extension developers.

This allows any extension to provide a rich dashboard experience just by registering a schema.

@robertcsakany

Copy link
Copy Markdown
Member

Thanks for your contribution. I'm using this PR to draw a more generalized solution for the feature you made.

@robertcsakany robertcsakany self-assigned this May 2, 2026
@robertcsakany robertcsakany added the enhancement New feature or request label May 2, 2026
robertcsakany added a commit that referenced this pull request Jul 22, 2026
- Localize tag-area count + active badge via t() (#1)
- Deselect a globally-deleted tag from the active filter set on confirm so
  the list can't stay filtered to 0 with no chip to clear (#5)
- Path-alphabetical order for the TagDeleteConfirmDialog AGENTS.md row (#6)
- Guard non-string `tag` on remove_tag_globally before normalize (untrusted
  WS payload; normalizeTags calls .trim()) + L1 test (#8)

Rejected (with reason): #2 archive dir is the project ship convention;
#3 archived static mockups (real components already meet 24px+focus/active-
selection); #4 test-plan is the frozen plan-stage artifact, level deviation
documented in tasks.md; #7 last-write-wins fan-out is the design's documented
accepted trade-off (D5/Risks, scenario X4 manual-only).
robertcsakany added a commit that referenced this pull request Jul 22, 2026
… global tag delete (#387)

* feat(sidebar-tag-collapse-and-delete): collapsible tag area + guarded global tag delete

Implements OpenSpec change sidebar-tag-collapse-and-delete:
- Single master collapse over the sidebar tag+phase area (default collapsed,
  persisted; count + active-filter indicator + fold-free clear on the header).
- Overflow cap (10) + `+N more`/`show less` inline expander on the user-tag group.
- Destructive per-tag remove (guarded confirm dialog) that strips a tag from
  every carrying session via the new `remove_tag_globally` browser->server verb
  (server fan-out; one session_updated per changed session).

Archives + syncs specs. QA/manual tasks (9.1, X4) deferred to post-merge.

* fix: apply CodeRabbit feedback for sidebar-tag-collapse-and-delete

- Localize tag-area count + active badge via t() (#1)
- Deselect a globally-deleted tag from the active filter set on confirm so
  the list can't stay filtered to 0 with no chip to clear (#5)
- Path-alphabetical order for the TagDeleteConfirmDialog AGENTS.md row (#6)
- Guard non-string `tag` on remove_tag_globally before normalize (untrusted
  WS payload; normalizeTags calls .trim()) + L1 test (#8)

Rejected (with reason): #2 archive dir is the project ship convention;
#3 archived static mockups (real components already meet 24px+focus/active-
selection); #4 test-plan is the frozen plan-stage artifact, level deviation
documented in tasks.md; #7 last-write-wins fan-out is the design's documented
accepted trade-off (D5/Risks, scenario X4 manual-only).
robertcsakany added a commit that referenced this pull request Aug 19, 2026
- spec (Major): subagent-live-cadence "stored tick" scenario → DELIVERED-wire
  cadence (collapse trims stored events; matches the P3 test) [#2]
- faux-agent-ticks: clamp tick-plan values (Number()→Infinity/0 guard) + L1 test;
  re-check abort after the quiet gap so no extra tick is emitted [#4,#5]
- collectAgentTicks gains sessionId; F1/P1/P2/P3/F5 isolate their OWN run's
  frames (shared harness: a prior producer may still stream) [#10]
- F5: require >=2 ticks so Math.max over empty gaps can't mislead [#11]
- X7: assert the tested session's per-session counters, not the racy aggregate
  sum (a sibling session ending between reads could lower it) [#7]
- AGENTS.md row ordering (qa/fixtures, tests/e2e) + markdown fence language [#1,#3,#6]

Verified: synthetic-arm cadence 5/5, X7/X8 2/2, L1 33/33.
Disputed (reply): #8 (F3 small run does not virtualize; post-settle re-check is
intentional), #9 (2.2 fps is the spec ceiling; widening would weaken it, and
session-filtering removes the spurious frames that narrowed the margin).
robertcsakany added a commit that referenced this pull request Aug 19, 2026
…hrottle (#511)

* feat(bridge): throttle subagent Agent ticks on tool_execution_update

Adds SubagentTickThrottle (leading edge + trailing latest-wins, keyed per
toolCallId, 60s idle TTL, fire-time isActive/sessionReady/sessionId gating,
discard-at-terminal) plus its L1 suite, the subagentTickThrottleMs config
(rollout default 0), and the D6 counters on /api/health via the existing
heartbeat processMetrics transport.

Also adds the >=10s sustained + streaming-heavy faux fixtures and the e2e
config-injection helper the L3 rows need.

See change: reduce-bridge-tick-bandwidth (tasks 1.1-1.3, 3.1-3.19, 4.1-4.2).

* test(e2e): subagent tick throttle L3 rows (cadence, rate, replay, counters)

Adds the test-plan's L3 scenarios: F1/P1 cadence floor + throttled rate, P2
throttle-off comparison, F2 no-tick-after-terminal, F5 quiet-producer guard,
P4 F4 non-vacuity, P3 stored-tick staleness, F3 reload-folds-to-terminal,
X7/X8 counter transport + predicate tripwire, and F4 sibling-pull
non-interaction. Plus the collectAgentTicks toolName-filtered frame collector.

See change: reduce-bridge-tick-bandwidth (tasks 4.3-4.4, 5.1-5.9).

* docs(openspec): D1 measurement fires the 2.2 STOP gate; ship-it blocked

Measured Agent-tick rate on tool_execution_update is ~0.36 frames/s (~350 B/s),
two orders of magnitude below the 2 Hz kill switch. The carrier is a single
~250ms burst of ~9 frames at subagent start, not a sustained stream — which
falsifies the proposal's and design.md's Context premise.

Consequences recorded in measurement.md + SHIP_IT_BLOCKED.md:
 - the throttle is net-harmful at this frame shape (9 -> 1 forwarded)
 - it REGRESSES the parent change's F4 e2e (green at 0, red at 500)
 - the >=10s sustained fixture F1/P1/P3/P4 need is not constructible

See change: reduce-bridge-tick-bandwidth (tasks 2.1, 2.2, 4.3, 4.4).

* feat(e2e): synthetic Agent-tick producer + PI_SYNTH_AGENT_TICKS arm for throttle L3

Root-caused the D1 STOP as a dead-subagent artifact (@fast -> claude-opus-4-8,
never faux). Re-measured live: ~32 fps >> 2 Hz; design premise validated. Nested
faux subagents cannot sustain a >=10s tick stream (empty inner faux queue), so
the throttle cadence rows now run on a synthetic same-shape producer.

- qa/fixtures/faux-agent-ticks.ext.ts: Agent tool streaming tool_execution_update
  at a [[ticks:N@Mms]] cadence (proven OFF 19.6fps -> ON(500) 2.00fps on /ws)
- qa/fixtures/faux-scenarios.ts: synthetic-agent-ticks(+ -quiet) scenarios
- docker: PI_SYNTH_AGENT_TICKS=1 arm (stage producer, skip subagents)
- tests/e2e/subagent-tick-throttle.spec.ts: F1/P1/P2/F2/F5/P3 (arm-gated, self-skip)
- migrated cadence rows out of subagent-detail-dialog + replay-delta
- packages/server L1 parseTickPlan test
- measurement.md/tasks.md/test-plan.md corrected; SHIP_IT_BLOCKED.md removed

* test(throttle): reclassify F4-sibling (5.8) to L1 — resync carrier untouched

The L3 e2e was structurally unconstructible: the faux subagent dies in ~400 ms
(Bug 2) before an inspector-open can trigger a resync, and the synthetic
producer emits no subagents:* frames. The invariant (resync/subagents:* pass the
throttle 1:1 and move no counter — a carrier isSubagentTick never sees) is now
owned at L1 in bridge-queue-update-forward.test.ts. Removed the unconstructible
L3 test; updated test-plan F4 (L3->L1) + tasks.md 5.8.

* chore(knip): ignore pi-forms-bpmn skill assets + root cost-estimator bins

Two pre-existing knip config gaps surfaced when ship-it's knip gate first ran on
a tree containing pi-forms-bpmn (added to develop 2026-08-16, after the 08-13
baseline; knip is not per-PR CI-gated so it never triggered):

- ignore packages/pi-forms-bpmn/.pi/skills/** — vendored bpmn-js/dmn-js/yaml +
  skill tooling, never product code (other skills already ignored)
- root packages/cost-estimator/src/bin/*.ts — real CLI entry points (shebang +
  package.json bin), previously unrooted -> false-positive 'unused files'

Fixes the knip 'files' class. The residual +9 exports/+1 type is develop's
incremental debt above the stale baseline and needs a develop-side re-measure
(a feature PR cannot raise the baseline; --check-baseline-diff rejects it).

* fix(throttle): count coalesced pending on leading-edge past window; review polish

Local @review (deepseek-v4-pro) verdict SHIP/0-blocking. Opportunistic minors:
- throttle: leading-edge branch now cancels a due-but-unfired trailing timer and
  counts its still-held pending as tickCoalesced (production I/O race where offer
  beats the timer); + E3b regression test (fails without the fix)
- remove orphaned subagent-sustained-long / subagent-slow-inner-long fixtures
  (superseded by the synthetic producer; nested faux can't sustain >=10s)
- tasks.md: mark 5.7 (F3, verified green in the local harness) done; reconcile 1.1

* docs(openspec): 6.3 AGENTS.md rows + ship-dormant decision (6.1)

- add throttle source-file AGENTS.md rows (extension/src subagent-tick-throttle.ts,
  shared/src config.ts + protocol.ts, server/routes system-routes.ts)
- 6.1: ship with default 0 (dormant); flip to 500 deferred to a post-merge
  follow-up gated on the manual UX check (7.1)
- 6.2: measurement recorded at W=500 (OFF 19.6fps -> ON 2.00fps)

* feat(reduce-bridge-tick-bandwidth): bridge-side subagent Agent-tick throttle

Implements OpenSpec change reduce-bridge-tick-bandwidth. Archives + syncs specs
(catch-all-event-forwarding updated, subagent-live-cadence created).

Ships the throttle mechanism + config knob (default 0 = dormant, byte-identical
rollback); the default-on flip to 500 is deferred to a post-merge follow-up gated
on the manual UX liveness check. QA/manual tasks (7.1/7.2) deferred to post-merge.

* fix: apply CodeRabbit feedback for reduce-bridge-tick-bandwidth

- spec (Major): subagent-live-cadence "stored tick" scenario → DELIVERED-wire
  cadence (collapse trims stored events; matches the P3 test) [#2]
- faux-agent-ticks: clamp tick-plan values (Number()→Infinity/0 guard) + L1 test;
  re-check abort after the quiet gap so no extra tick is emitted [#4,#5]
- collectAgentTicks gains sessionId; F1/P1/P2/P3/F5 isolate their OWN run's
  frames (shared harness: a prior producer may still stream) [#10]
- F5: require >=2 ticks so Math.max over empty gaps can't mislead [#11]
- X7: assert the tested session's per-session counters, not the racy aggregate
  sum (a sibling session ending between reads could lower it) [#7]
- AGENTS.md row ordering (qa/fixtures, tests/e2e) + markdown fence language [#1,#3,#6]

Verified: synthetic-arm cadence 5/5, X7/X8 2/2, L1 33/33.
Disputed (reply): #8 (F3 small run does not virtualize; post-settle re-check is
intentional), #9 (2.2 fps is the spec ceiling; widening would weaken it, and
session-filtering removes the spurious frames that narrowed the margin).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants