@xenosystem/blocks 0.9.2 → 0.10.1

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.
@@ -1,4 +1,4 @@
1
- import { X as XenoAgentSessionDelta, a as XenoAgentEvent } from '../types-C5T3uVwd.js';
1
+ import { X as XenoAgentSessionDelta, a as XenoAgentEvent } from '../types-CaBV2_q8.js';
2
2
 
3
3
  /**
4
4
  * The reference adapter: XENO Agent host runtime events → this panel's `session` input.
@@ -1,7 +1,8 @@
1
- import { PanelModule, PanelManifest } from '@xenosystem/block-sdk';
2
- import { a as XenoAgentEvent, b as XenoAgentTurnState, A as AgentViewState, X as XenoAgentSessionDelta, c as XenoAgentCatalog, d as XenoAgentConnection, e as AgentPanelState } from '../types-C5T3uVwd.js';
3
- export { f as XenoAgentAskEvent, g as XenoAgentAskWithdrawEvent, h as XenoAgentError, i as XenoAgentIntent, j as XenoAgentLane, k as XenoAgentMessageEvent, l as XenoAgentModel, m as XenoAgentPatchEvent, n as XenoAgentPatchFile, o as XenoAgentProvider, p as XenoAgentRole, q as XenoAgentSession, r as XenoAgentSessionClosedEvent, s as XenoAgentSessionEvent, t as XenoAgentStatus, u as XenoAgentTerminalEvent, v as XenoAgentToolEvent, w as XenoAgentTurnEvent, x as isBusy, y as isWaitingOnUser } from '../types-C5T3uVwd.js';
1
+ import { PanelModule, PanelManifest, BlockDeclaration } from '@xenosystem/block-sdk';
2
+ import { a as XenoAgentEvent, b as XenoAgentTurnState, A as AgentViewState, X as XenoAgentSessionDelta, c as XenoAgentCatalog, d as XenoAgentConnection, e as AgentPanelState, f as XenoAgentLane } from '../types-CaBV2_q8.js';
3
+ export { g as XenoAgentAskEvent, h as XenoAgentAskWithdrawEvent, i as XenoAgentError, j as XenoAgentIntent, k as XenoAgentMessageEvent, l as XenoAgentModel, m as XenoAgentPatchEvent, n as XenoAgentPatchFile, o as XenoAgentProvider, p as XenoAgentRole, q as XenoAgentSession, r as XenoAgentSessionClosedEvent, s as XenoAgentSessionEvent, t as XenoAgentStatus, u as XenoAgentTerminalEvent, v as XenoAgentToolEvent, w as XenoAgentTurnEvent, x as isBusy, y as isWaitingOnUser } from '../types-CaBV2_q8.js';
4
4
  import { ReactNode } from 'react';
5
+ import { PanelTone } from '@xenosystem/components/chrome';
5
6
 
6
7
  /**
7
8
  * The translation: ONE agent session-event stream → the canonical panels that already render it.
@@ -554,24 +555,105 @@ declare function countChanges(hunks: readonly XenoDiffHunk[]): {
554
555
  /** Props for {@link AgentPanelView}. */
555
556
  interface AgentPanelViewProps {
556
557
  controller: AgentController;
557
- /** Enter submits, Shift+Enter newlines. `false` swaps them. */
558
558
  submitOnEnter?: boolean;
559
- /** Render the lane badge. */
560
559
  showLane?: boolean;
561
- /** Render the session switcher. */
562
560
  showSessions?: boolean;
563
561
  emptyHint?: string;
564
562
  }
565
563
  /**
566
- * The composer field.
567
- *
568
- * 🔴 `outline: 'none'` is REQUIRED, not a preference. `DESIGN_SYSTEM.md` exempts text entry from
569
- * the global `:focus-visible` ring: `outline-offset` draws the ring OUTSIDE the field, where it
570
- * reads as a stray stroke over the input container and makes the control look broken on dark
571
- * chrome. The ring stays everywhere else — removing it globally would be a real keyboard-a11y
572
- * regression on buttons.
564
+ * The code view of the agent block. It renders the SAME view model the declaration binds
565
+ * (`agentPanelView` in `../declaration`), so the two cannot drift: labels, tones, row shapes and
566
+ * placeholders are decided once. `test/agent-agent/declaration.test.tsx` holds the markup equal.
573
567
  */
574
- /** The view. */
575
568
  declare function AgentPanelView({ controller, submitOnEnter, showLane, showSessions, emptyHint, }: AgentPanelViewProps): ReactNode;
576
569
 
577
- export { AGENT_CATALOG_SCHEMA, AGENT_FANOUT_PORTS, AGENT_INTENT_SCHEMA, AGENT_PANEL_ID, AGENT_PANEL_WIRING, AGENT_SESSION_SCHEMA, AGENT_WIRING_TARGETS, AgentController, type AgentControllerOptions, type AgentEmission, type AgentFanoutPort, type AgentHostBridge, AgentPanelState, AgentPanelView, type AgentPanelViewProps, AgentProjector, type AgentProjectorOptions, type AgentRenderContext, AgentViewState, type AgentWire, type AgentWireEnd, CONSENT_ELICITATION_RESULT_SCHEMA, CONSENT_ELICITATION_SCHEMA, type CreateAgentPanelOptions, XenoAgentCatalog, XenoAgentConnection, XenoAgentEvent, XenoAgentSessionDelta, XenoAgentTurnState, type XenoDiffHunk, type XenoDiffLine, type XenoDiffLineKind, agentManifest, agentPanel, countChanges, createAgentPanel, parseUnifiedDiff, turnStatusToRunStatus, wiringFor };
570
+ /**
571
+ * The agent panel AS A DECLARATION — the second block written the way `xeno-apps/SPEC.md` §8d says every
572
+ * block is (the auth gate was the first): chrome units + bindings + emits, with ONE behaviour
573
+ * (`agent/agentPanelView`) for the only logic the view has — labels, tones and row shapes derived from
574
+ * `AgentViewState`. The code view (`AgentPanelView`) and this declaration render the same panel from the
575
+ * same behaviour; `test/agent-agent/declaration.test.tsx` holds them equal in every connection/turn state.
576
+ *
577
+ * Where the state lives: the block's `AgentController` is its runtime — it consumes the host ports
578
+ * (`session`, `catalog`, `status`, …) and derives `AgentViewState`. The declaration is the PRESENTATION of
579
+ * that state: input `view` (an `AgentViewState` push), output `ui` (`{ kind, id?, draft? }`), which the
580
+ * controller applies (`newSession`, `selectSession`, `selectProvider`, `setDraft`, `submit`, `steer`,
581
+ * `cancel`). The declaration holds no state of its own — a draft keystroke is a `ui` emit and comes back
582
+ * as `view.draft`, which is exactly how the auth gate's intents round-trip.
583
+ *
584
+ * Node-valued props (`{ node: … }`, block-sdk 0.3.0) carry the toolbar sides, the row trailers and the
585
+ * status bar — the parts chrome units take as element props rather than children.
586
+ */
587
+
588
+ type AgentUiIntent = {
589
+ kind: 'newSession';
590
+ } | {
591
+ kind: 'selectSession';
592
+ id: string;
593
+ } | {
594
+ kind: 'selectProvider';
595
+ id: string;
596
+ } | {
597
+ kind: 'setDraft';
598
+ draft: string;
599
+ } | {
600
+ kind: 'submit';
601
+ } | {
602
+ kind: 'steer';
603
+ } | {
604
+ kind: 'cancel';
605
+ };
606
+ /** The manifest the declaration validates against — the agent panel's id, its PRESENTATION ports. */
607
+ declare const agentViewManifest: PanelManifest;
608
+ declare const LANE_LABEL: Record<XenoAgentLane, string>;
609
+ declare const TURN: Record<XenoAgentTurnState, {
610
+ label: string;
611
+ tone: PanelTone;
612
+ }>;
613
+ interface AgentPanelViewModel {
614
+ failed: boolean;
615
+ connecting: boolean;
616
+ empty: boolean;
617
+ ready: boolean;
618
+ failedHint: string;
619
+ emptyHint: string;
620
+ turnLabel: string;
621
+ turnTone: PanelTone;
622
+ lane?: string;
623
+ waiting?: string;
624
+ showSessions: boolean;
625
+ sessions: {
626
+ id: string;
627
+ label: string;
628
+ selected: boolean;
629
+ turnLabel: string;
630
+ }[];
631
+ showProviders: boolean;
632
+ providers: {
633
+ id: string;
634
+ label: string;
635
+ meta?: string;
636
+ disabled: boolean;
637
+ selected: boolean;
638
+ }[];
639
+ draft: string;
640
+ placeholder: string;
641
+ status?: string;
642
+ busy: boolean;
643
+ idle: boolean;
644
+ canSubmit: boolean;
645
+ cannotSubmit: boolean;
646
+ submitKind: 'submit' | 'steer';
647
+ }
648
+ interface AgentPanelViewOptions {
649
+ showLane?: boolean;
650
+ showSessions?: boolean;
651
+ emptyHint?: string;
652
+ }
653
+ declare function agentPanelView(state: AgentViewState, options?: AgentPanelViewOptions): AgentPanelViewModel;
654
+ declare const BEHAVIOURS: {
655
+ 'agent/agentPanelView': (inputs: Record<string, unknown>, config: Readonly<Record<string, unknown>>) => AgentPanelViewModel;
656
+ };
657
+ declare const AGENT_DECLARATION: BlockDeclaration;
658
+
659
+ export { AGENT_CATALOG_SCHEMA, AGENT_DECLARATION, AGENT_FANOUT_PORTS, AGENT_INTENT_SCHEMA, AGENT_PANEL_ID, AGENT_PANEL_WIRING, AGENT_SESSION_SCHEMA, AGENT_WIRING_TARGETS, AgentController, type AgentControllerOptions, type AgentEmission, type AgentFanoutPort, type AgentHostBridge, AgentPanelState, AgentPanelView, type AgentPanelViewModel, type AgentPanelViewOptions, type AgentPanelViewProps, AgentProjector, type AgentProjectorOptions, type AgentRenderContext, type AgentUiIntent, AgentViewState, type AgentWire, type AgentWireEnd, BEHAVIOURS, CONSENT_ELICITATION_RESULT_SCHEMA, CONSENT_ELICITATION_SCHEMA, type CreateAgentPanelOptions, LANE_LABEL, TURN, XenoAgentCatalog, XenoAgentConnection, XenoAgentEvent, XenoAgentLane, XenoAgentSessionDelta, XenoAgentTurnState, type XenoDiffHunk, type XenoDiffLine, type XenoDiffLineKind, agentManifest, agentPanel, agentPanelView, agentViewManifest, countChanges, createAgentPanel, parseUnifiedDiff, turnStatusToRunStatus, wiringFor };
@@ -1037,6 +1037,7 @@ var agentManifest = {
1037
1037
  import { useSyncExternalStore } from "react";
1038
1038
  import {
1039
1039
  Badge,
1040
+ Column,
1040
1041
  Composer,
1041
1042
  EmptyState,
1042
1043
  Row,
@@ -1048,12 +1049,19 @@ import {
1048
1049
  Toolbar,
1049
1050
  ToolbarGroup
1050
1051
  } from "@xenosystem/components/chrome";
1051
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
1052
- var LANE_LABEL = {
1053
- cloud: "Cloud",
1054
- local: "Local",
1055
- acp: "ACP"
1052
+
1053
+ // src/agent/agent/declaration.ts
1054
+ var agentViewManifest = {
1055
+ id: AGENT_PANEL_ID,
1056
+ version: "1.0.0",
1057
+ title: "Agent",
1058
+ category: "agent",
1059
+ layout: { slot: "main" },
1060
+ inputs: [{ id: "view", type: "object", label: "View state", description: "The AgentViewState the controller derives from the host ports." }],
1061
+ outputs: [{ id: "ui", type: "object", label: "UI intent", description: "{ kind, id?, draft? } \u2014 applied by the controller." }],
1062
+ commands: []
1056
1063
  };
1064
+ var LANE_LABEL = { cloud: "Cloud", local: "Local", acp: "ACP" };
1057
1065
  var TURN = {
1058
1066
  idle: { label: "Idle", tone: "neutral" },
1059
1067
  queued: { label: "Queued", tone: "neutral" },
@@ -1064,7 +1072,157 @@ var TURN = {
1064
1072
  failed: { label: "Failed", tone: "error" },
1065
1073
  cancelled: { label: "Cancelled", tone: "neutral" }
1066
1074
  };
1067
- var COLUMN = { display: "flex", flexDirection: "column", height: "100%", minHeight: 0 };
1075
+ function agentPanelView(state, options = {}) {
1076
+ const showLane = options.showLane ?? true;
1077
+ const showSessions = options.showSessions ?? true;
1078
+ const turn = TURN[state.turn];
1079
+ const lane = state.activeProvider?.lane;
1080
+ return {
1081
+ failed: state.connection === "failed",
1082
+ connecting: state.connection === "connecting",
1083
+ empty: state.connection !== "failed" && state.connection !== "connecting" && state.sessions.length === 0,
1084
+ ready: state.connection !== "failed" && state.connection !== "connecting" && state.sessions.length > 0,
1085
+ failedHint: state.message ?? "The agent host reported a failure.",
1086
+ emptyHint: options.emptyHint ?? "Start a session to talk to an agent.",
1087
+ turnLabel: turn.label,
1088
+ turnTone: turn.tone,
1089
+ lane: showLane && lane ? LANE_LABEL[lane] ?? lane : void 0,
1090
+ waiting: state.pendingAsks > 0 ? `${state.pendingAsks} waiting` : void 0,
1091
+ showSessions,
1092
+ sessions: state.sessions.map((s) => ({ id: s.id, label: s.title ?? s.id, selected: s.id === state.active?.id, turnLabel: TURN[s.turn ?? "idle"].label })),
1093
+ showProviders: state.providers.length > 1,
1094
+ providers: state.providers.map((p) => ({
1095
+ id: p.id,
1096
+ label: p.label,
1097
+ meta: p.unavailable ?? (showLane ? LANE_LABEL[p.lane] ?? p.lane : void 0),
1098
+ disabled: p.unavailable !== void 0,
1099
+ selected: p.id === state.activeProvider?.id
1100
+ })),
1101
+ draft: state.draft,
1102
+ placeholder: state.busy ? "Steer the running turn\u2026" : "Ask the agent\u2026",
1103
+ status: state.message ?? state.active?.cwd ?? void 0,
1104
+ busy: state.busy,
1105
+ idle: !state.busy,
1106
+ canSubmit: state.canSubmit,
1107
+ cannotSubmit: !state.canSubmit,
1108
+ submitKind: state.busy ? "steer" : "submit"
1109
+ };
1110
+ }
1111
+ var EMPTY_VIEW = { sessions: [], active: null, turn: "idle", connection: "connecting", message: null, providers: [], activeProvider: null, activeModelId: null, draft: "", canSubmit: false, busy: false, pendingAsks: 0 };
1112
+ var BEHAVIOURS = {
1113
+ "agent/agentPanelView": (inputs, config) => agentPanelView(inputs.view ?? EMPTY_VIEW, {
1114
+ showLane: typeof config.showLane === "boolean" ? config.showLane : void 0,
1115
+ showSessions: typeof config.showSessions === "boolean" ? config.showSessions : void 0,
1116
+ emptyHint: typeof config.emptyHint === "string" ? config.emptyHint : void 0
1117
+ })
1118
+ };
1119
+ var ui = (kind) => ({ emit: "ui", value: { object: { kind: { value: kind } } } });
1120
+ var uiWithItem = (kind) => ({ emit: "ui", value: { object: { kind: { value: kind }, id: { item: "id" } } } });
1121
+ var newSessionButton = { component: "chrome/TextButton", on: { onClick: ui("newSession") }, children: [{ component: "text", props: { text: { value: "New session" } } }] };
1122
+ var AGENT_DECLARATION = {
1123
+ format: "xeno.block@1",
1124
+ manifest: agentViewManifest,
1125
+ behaviour: "agent/agentPanelView",
1126
+ composition: {
1127
+ component: "fragment",
1128
+ children: [
1129
+ { component: "chrome/EmptyState", when: { input: "view.failed" }, props: { title: { value: "Not connected" }, hint: { input: "view.failedHint" } } },
1130
+ { component: "chrome/EmptyState", when: { input: "view.connecting" }, props: { title: { value: "Connecting\u2026" }, hint: { value: "Waiting for the agent host." } } },
1131
+ {
1132
+ component: "chrome/Column",
1133
+ when: { input: "view.empty" },
1134
+ children: [
1135
+ { component: "chrome/EmptyState", props: { title: { value: "No sessions" }, hint: { input: "view.emptyHint" } } },
1136
+ { component: "chrome/Toolbar", props: { right: { node: { component: "chrome/ToolbarGroup", props: { end: { value: true } }, children: [newSessionButton] } } } }
1137
+ ]
1138
+ },
1139
+ {
1140
+ component: "chrome/Column",
1141
+ when: { input: "view.ready" },
1142
+ children: [
1143
+ {
1144
+ component: "chrome/Toolbar",
1145
+ props: {
1146
+ left: {
1147
+ node: {
1148
+ component: "chrome/ToolbarGroup",
1149
+ children: [
1150
+ { component: "chrome/StatusBadge", props: { tone: { input: "view.turnTone" } }, children: [{ component: "text", props: { text: { input: "view.turnLabel" } } }] },
1151
+ { component: "chrome/Badge", when: { input: "view.lane" }, children: [{ component: "text", props: { text: { input: "view.lane" } } }] },
1152
+ { component: "chrome/Badge", when: { input: "view.waiting" }, children: [{ component: "text", props: { text: { input: "view.waiting" } } }] }
1153
+ ]
1154
+ }
1155
+ },
1156
+ right: { node: { component: "chrome/ToolbarGroup", props: { end: { value: true } }, children: [newSessionButton] } }
1157
+ }
1158
+ },
1159
+ {
1160
+ component: "chrome/ScrollArea",
1161
+ when: { input: "view.showSessions" },
1162
+ children: [
1163
+ {
1164
+ component: "chrome/RowList",
1165
+ children: [
1166
+ {
1167
+ component: "chrome/Row",
1168
+ each: { input: "view.sessions", key: "id" },
1169
+ props: {
1170
+ noIcon: { value: true },
1171
+ label: { item: "label" },
1172
+ selected: { item: "selected" },
1173
+ trailing: { node: { component: "chrome/Badge", children: [{ component: "text", props: { text: { item: "turnLabel" } } }] } }
1174
+ },
1175
+ on: { onClick: uiWithItem("selectSession") }
1176
+ }
1177
+ ]
1178
+ }
1179
+ ]
1180
+ },
1181
+ {
1182
+ component: "chrome/RowList",
1183
+ when: { input: "view.showProviders" },
1184
+ children: [
1185
+ {
1186
+ component: "chrome/Row",
1187
+ each: { input: "view.providers", key: "id" },
1188
+ props: { noIcon: { value: true }, label: { item: "label" }, meta: { item: "meta" }, disabled: { item: "disabled" }, selected: { item: "selected" } },
1189
+ on: { onClick: uiWithItem("selectProvider") }
1190
+ }
1191
+ ]
1192
+ },
1193
+ {
1194
+ component: "chrome/Composer",
1195
+ props: { value: { input: "view.draft" }, placeholder: { input: "view.placeholder" } },
1196
+ on: {
1197
+ onChange: { emit: "ui", value: { object: { kind: { value: "setDraft" }, draft: { arg: "" } } } },
1198
+ onSubmit: { emit: "ui", value: { object: { kind: { input: "view.submitKind" } } } }
1199
+ }
1200
+ },
1201
+ {
1202
+ component: "chrome/StatusBar",
1203
+ props: {
1204
+ left: { input: "view.status" },
1205
+ right: {
1206
+ node: {
1207
+ component: "chrome/ToolbarGroup",
1208
+ props: { end: { value: true } },
1209
+ children: [
1210
+ { component: "chrome/TextButton", when: { input: "view.busy" }, on: { onClick: ui("steer") }, children: [{ component: "text", props: { text: { value: "Steer" } } }] },
1211
+ { component: "chrome/TextButton", when: { input: "view.busy" }, on: { onClick: ui("cancel") }, children: [{ component: "text", props: { text: { value: "Stop" } } }] },
1212
+ { component: "chrome/TextButton", when: { input: "view.idle" }, props: { disabled: { input: "view.cannotSubmit" } }, on: { onClick: ui("submit") }, children: [{ component: "text", props: { text: { value: "Send" } } }] }
1213
+ ]
1214
+ }
1215
+ }
1216
+ }
1217
+ }
1218
+ ]
1219
+ }
1220
+ ]
1221
+ }
1222
+ };
1223
+
1224
+ // src/agent/agent/react/AgentPanelView.tsx
1225
+ import { jsx, jsxs } from "react/jsx-runtime";
1068
1226
  function AgentPanelView({
1069
1227
  controller,
1070
1228
  submitOnEnter = true,
@@ -1073,56 +1231,47 @@ function AgentPanelView({
1073
1231
  emptyHint
1074
1232
  }) {
1075
1233
  const state = useSyncExternalStore(controller.subscribe, controller.getState, controller.getState);
1076
- if (state.connection === "failed") {
1077
- return /* @__PURE__ */ jsx(ErrorPane, { message: state.message });
1078
- }
1079
- if (state.connection === "connecting") {
1080
- return /* @__PURE__ */ jsx(EmptyState, { title: "Connecting\u2026", hint: "Waiting for the agent host." });
1081
- }
1082
- if (state.sessions.length === 0) {
1083
- return /* @__PURE__ */ jsxs("div", { style: COLUMN, children: [
1084
- /* @__PURE__ */ jsx(EmptyState, { title: "No sessions", hint: emptyHint ?? "Start a session to talk to an agent." }),
1085
- /* @__PURE__ */ jsx(
1086
- Toolbar,
1087
- {
1088
- right: /* @__PURE__ */ jsx(ToolbarGroup, { end: true, children: /* @__PURE__ */ jsx(TextButton, { onClick: () => controller.newSession(), children: "New session" }) })
1089
- }
1090
- )
1234
+ const v = agentPanelView(state, { showLane, showSessions, emptyHint });
1235
+ if (v.failed) return /* @__PURE__ */ jsx(EmptyState, { title: "Not connected", hint: v.failedHint });
1236
+ if (v.connecting) return /* @__PURE__ */ jsx(EmptyState, { title: "Connecting\u2026", hint: "Waiting for the agent host." });
1237
+ const newSession = /* @__PURE__ */ jsx(ToolbarGroup, { end: true, children: /* @__PURE__ */ jsx(TextButton, { onClick: () => controller.newSession(), children: "New session" }) });
1238
+ if (v.empty) {
1239
+ return /* @__PURE__ */ jsxs(Column, { children: [
1240
+ /* @__PURE__ */ jsx(EmptyState, { title: "No sessions", hint: v.emptyHint }),
1241
+ /* @__PURE__ */ jsx(Toolbar, { right: newSession })
1091
1242
  ] });
1092
1243
  }
1093
- const turn = TURN[state.turn];
1094
- const lane = state.activeProvider?.lane;
1095
- return /* @__PURE__ */ jsxs("div", { style: COLUMN, children: [
1244
+ return /* @__PURE__ */ jsxs(Column, { children: [
1096
1245
  /* @__PURE__ */ jsx(
1097
1246
  Toolbar,
1098
1247
  {
1099
1248
  left: /* @__PURE__ */ jsxs(ToolbarGroup, { children: [
1100
- /* @__PURE__ */ jsx(StatusBadge, { tone: turn.tone, children: turn.label }),
1101
- showLane && lane ? /* @__PURE__ */ jsx(Badge, { children: LANE_LABEL[lane] ?? lane }) : null,
1102
- state.pendingAsks > 0 ? /* @__PURE__ */ jsx(Badge, { children: `${state.pendingAsks} waiting` }) : null
1249
+ /* @__PURE__ */ jsx(StatusBadge, { tone: v.turnTone, children: v.turnLabel }),
1250
+ v.lane ? /* @__PURE__ */ jsx(Badge, { children: v.lane }) : null,
1251
+ v.waiting ? /* @__PURE__ */ jsx(Badge, { children: v.waiting }) : null
1103
1252
  ] }),
1104
- right: /* @__PURE__ */ jsx(ToolbarGroup, { end: true, children: /* @__PURE__ */ jsx(TextButton, { onClick: () => controller.newSession(), children: "New session" }) })
1253
+ right: newSession
1105
1254
  }
1106
1255
  ),
1107
- showSessions ? /* @__PURE__ */ jsx(ScrollArea, { children: /* @__PURE__ */ jsx(RowList, { children: state.sessions.map((session) => /* @__PURE__ */ jsx(
1256
+ v.showSessions ? /* @__PURE__ */ jsx(ScrollArea, { children: /* @__PURE__ */ jsx(RowList, { children: v.sessions.map((session) => /* @__PURE__ */ jsx(
1108
1257
  Row,
1109
1258
  {
1110
1259
  noIcon: true,
1111
- label: session.title ?? session.id,
1112
- selected: session.id === state.active?.id,
1260
+ label: session.label,
1261
+ selected: session.selected,
1113
1262
  onClick: () => controller.selectSession(session.id),
1114
- trailing: /* @__PURE__ */ jsx(Badge, { children: TURN[session.turn ?? "idle"].label })
1263
+ trailing: /* @__PURE__ */ jsx(Badge, { children: session.turnLabel })
1115
1264
  },
1116
1265
  session.id
1117
1266
  )) }) }) : null,
1118
- state.providers.length > 1 ? /* @__PURE__ */ jsx(RowList, { children: state.providers.map((provider) => /* @__PURE__ */ jsx(
1267
+ v.showProviders ? /* @__PURE__ */ jsx(RowList, { children: v.providers.map((provider) => /* @__PURE__ */ jsx(
1119
1268
  Row,
1120
1269
  {
1121
1270
  noIcon: true,
1122
1271
  label: provider.label,
1123
- meta: provider.unavailable ?? (showLane ? LANE_LABEL[provider.lane] ?? provider.lane : void 0),
1124
- disabled: provider.unavailable !== void 0,
1125
- selected: provider.id === state.activeProvider?.id,
1272
+ meta: provider.meta,
1273
+ disabled: provider.disabled,
1274
+ selected: provider.selected,
1126
1275
  onClick: () => controller.selectProvider(provider.id)
1127
1276
  },
1128
1277
  provider.id
@@ -1130,32 +1279,26 @@ function AgentPanelView({
1130
1279
  /* @__PURE__ */ jsx(
1131
1280
  Composer,
1132
1281
  {
1133
- value: state.draft,
1134
- placeholder: state.busy ? "Steer the running turn\u2026" : "Ask the agent\u2026",
1282
+ value: v.draft,
1283
+ placeholder: v.placeholder,
1135
1284
  submitOnEnter,
1136
1285
  onChange: (draft) => controller.setDraft(draft),
1137
- onSubmit: () => state.busy ? controller.steer() : controller.submit()
1286
+ onSubmit: () => v.busy ? controller.steer() : controller.submit()
1138
1287
  }
1139
1288
  ),
1140
1289
  /* @__PURE__ */ jsx(
1141
1290
  StatusBar,
1142
1291
  {
1143
- left: state.message ?? state.active?.cwd ?? void 0,
1144
- right: /* @__PURE__ */ jsx(ToolbarGroup, { end: true, children: state.busy ? /* @__PURE__ */ jsxs(Fragment, { children: [
1145
- /* @__PURE__ */ jsx(TextButton, { onClick: () => controller.steer(), children: "Steer" }),
1146
- /* @__PURE__ */ jsx(TextButton, { onClick: () => controller.cancel(), children: "Stop" })
1147
- ] }) : (
1148
- // `disabled` derives from the SAME predicate `submit()` enforces, so an enabled
1149
- // button can never be a button that refuses.
1150
- /* @__PURE__ */ jsx(TextButton, { disabled: !state.canSubmit, onClick: () => controller.submit(), children: "Send" })
1151
- ) })
1292
+ left: v.status,
1293
+ right: /* @__PURE__ */ jsxs(ToolbarGroup, { end: true, children: [
1294
+ v.busy ? /* @__PURE__ */ jsx(TextButton, { onClick: () => controller.steer(), children: "Steer" }) : null,
1295
+ v.busy ? /* @__PURE__ */ jsx(TextButton, { onClick: () => controller.cancel(), children: "Stop" }) : null,
1296
+ v.idle ? /* @__PURE__ */ jsx(TextButton, { disabled: v.cannotSubmit, onClick: () => controller.submit(), children: "Send" }) : null
1297
+ ] })
1152
1298
  }
1153
1299
  )
1154
1300
  ] });
1155
1301
  }
1156
- function ErrorPane({ message }) {
1157
- return /* @__PURE__ */ jsx(EmptyState, { title: "Not connected", hint: message ?? "The agent host reported a failure." });
1158
- }
1159
1302
 
1160
1303
  // src/agent/agent/panel.ts
1161
1304
  var CONNECTIONS = ["idle", "connecting", "ready", "failed"];
@@ -1399,6 +1542,7 @@ function wiringFor(panelId) {
1399
1542
  }
1400
1543
  export {
1401
1544
  AGENT_CATALOG_SCHEMA,
1545
+ AGENT_DECLARATION,
1402
1546
  AGENT_FANOUT_PORTS,
1403
1547
  AGENT_INTENT_SCHEMA,
1404
1548
  AGENT_PANEL_ID,
@@ -1408,10 +1552,15 @@ export {
1408
1552
  AgentController,
1409
1553
  AgentPanelView,
1410
1554
  AgentProjector,
1555
+ BEHAVIOURS,
1411
1556
  CONSENT_ELICITATION_RESULT_SCHEMA,
1412
1557
  CONSENT_ELICITATION_SCHEMA,
1558
+ LANE_LABEL,
1559
+ TURN,
1413
1560
  agentManifest,
1414
1561
  agentPanel,
1562
+ agentPanelView,
1563
+ agentViewManifest,
1415
1564
  countChanges,
1416
1565
  createAgentPanel,
1417
1566
  isBusy,
@@ -698,18 +698,21 @@ var accountManifest = {
698
698
  import { useSyncExternalStore } from "react";
699
699
  import {
700
700
  Badge,
701
+ Column,
701
702
  EmptyState,
702
703
  Row,
703
704
  RowList,
704
705
  ScrollArea,
705
706
  Section,
706
707
  StatTile,
708
+ Stack,
707
709
  StatusBar,
710
+ Text,
708
711
  TextButton,
709
712
  Toolbar,
710
713
  ToolbarGroup
711
714
  } from "@xenosystem/components/chrome";
712
- import { Fragment as Fragment2, jsx as jsx2, jsxs } from "react/jsx-runtime";
715
+ import { jsx as jsx2, jsxs } from "react/jsx-runtime";
713
716
  var STATUS_LABEL = {
714
717
  unknown: "Loading",
715
718
  signedOut: "Signed out",
@@ -748,11 +751,11 @@ function AccountPanelView({
748
751
  }
749
752
  const { identity, plan, credits } = state;
750
753
  const unit = credits?.unit ?? "credits";
751
- return /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", height: "100%", minHeight: 0 }, children: [
754
+ return /* @__PURE__ */ jsxs(Column, { children: [
752
755
  /* @__PURE__ */ jsx2(
753
756
  Toolbar,
754
757
  {
755
- left: /* @__PURE__ */ jsxs(Fragment2, { children: [
758
+ left: /* @__PURE__ */ jsxs(ToolbarGroup, { children: [
756
759
  /* @__PURE__ */ jsx2(Badge, { tone: STATUS_TONE[state.status], children: STATUS_LABEL[state.status] }),
757
760
  plan ? /* @__PURE__ */ jsx2(Badge, { title: `Plan: ${plan.label}`, children: plan.label }) : null
758
761
  ] }),
@@ -760,12 +763,12 @@ function AccountPanelView({
760
763
  }
761
764
  ),
762
765
  /* @__PURE__ */ jsxs(ScrollArea, { children: [
763
- /* @__PURE__ */ jsxs("div", { style: { padding: 8, display: "flex", flexDirection: "column", gap: 2 }, children: [
764
- /* @__PURE__ */ jsx2("div", { style: { fontSize: 12, fontWeight: 600 }, children: identity?.name ?? identity?.sub }),
765
- identity?.email ? /* @__PURE__ */ jsx2("div", { style: { fontSize: 10, opacity: 0.65 }, children: identity.email }) : null,
766
- state.message ? /* @__PURE__ */ jsx2("div", { style: { fontSize: 10, opacity: 0.75, marginTop: 4 }, children: state.message }) : null
766
+ /* @__PURE__ */ jsxs(Stack, { children: [
767
+ /* @__PURE__ */ jsx2(Text, { role: "title", children: identity?.name ?? identity?.sub }),
768
+ identity?.email ? /* @__PURE__ */ jsx2(Text, { role: "meta", children: identity.email }) : null,
769
+ state.message ? /* @__PURE__ */ jsx2(Text, { role: "meta", children: state.message }) : null
767
770
  ] }),
768
- credits ? /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: 6, padding: "0 8px 8px" }, children: [
771
+ credits ? /* @__PURE__ */ jsxs(Stack, { direction: "row", pad: "inset", children: [
769
772
  /* @__PURE__ */ jsx2(
770
773
  StatTile,
771
774
  {
@@ -825,16 +828,16 @@ function AccountPanelView({
825
828
  noIcon: true,
826
829
  label: entry.description,
827
830
  meta: entry.source,
828
- trailing: /* @__PURE__ */ jsx2("span", { style: { fontVariantNumeric: "tabular-nums", fontSize: 11 }, children: formatAmount(entry.amount) })
831
+ trailing: /* @__PURE__ */ jsx2(Text, { role: "number", children: formatAmount(entry.amount) })
829
832
  },
830
833
  entry.id
831
834
  )) }),
832
- state.ledgerHasMore ? /* @__PURE__ */ jsx2("div", { style: { padding: "2px 8px", fontSize: 9, opacity: 0.6 }, children: "Older entries are not held by this panel." }) : null
835
+ state.ledgerHasMore ? /* @__PURE__ */ jsx2(Stack, { pad: "inset", children: /* @__PURE__ */ jsx2(Text, { role: "caption", children: "Older entries are not held by this panel." }) }) : null
833
836
  ]
834
837
  }
835
838
  ) : null
836
839
  ] }),
837
- /* @__PURE__ */ jsx2("div", { style: { padding: "0 8px", fontSize: 9, opacity: 0.55 }, children: "Billing and sign-out ask you to confirm who you are." }),
840
+ /* @__PURE__ */ jsx2(Stack, { pad: "inset", children: /* @__PURE__ */ jsx2(Text, { role: "caption", children: "Billing and sign-out ask you to confirm who you are." }) }),
838
841
  /* @__PURE__ */ jsx2(
839
842
  Toolbar,
840
843
  {
@@ -422,4 +422,4 @@ declare function isBusy(turn: XenoAgentTurnState): boolean;
422
422
  */
423
423
  declare function isWaitingOnUser(turn: XenoAgentTurnState): boolean;
424
424
 
425
- export { type AgentViewState as A, type XenoAgentSessionDelta as X, type XenoAgentEvent as a, type XenoAgentTurnState as b, type XenoAgentCatalog as c, type XenoAgentConnection as d, type AgentPanelState as e, type XenoAgentAskEvent as f, type XenoAgentAskWithdrawEvent as g, type XenoAgentError as h, type XenoAgentIntent as i, type XenoAgentLane as j, type XenoAgentMessageEvent as k, type XenoAgentModel as l, type XenoAgentPatchEvent as m, type XenoAgentPatchFile as n, type XenoAgentProvider as o, type XenoAgentRole as p, type XenoAgentSession as q, type XenoAgentSessionClosedEvent as r, type XenoAgentSessionEvent as s, type XenoAgentStatus as t, type XenoAgentTerminalEvent as u, type XenoAgentToolEvent as v, type XenoAgentTurnEvent as w, isBusy as x, isWaitingOnUser as y };
425
+ export { type AgentViewState as A, type XenoAgentSessionDelta as X, type XenoAgentEvent as a, type XenoAgentTurnState as b, type XenoAgentCatalog as c, type XenoAgentConnection as d, type AgentPanelState as e, type XenoAgentLane as f, type XenoAgentAskEvent as g, type XenoAgentAskWithdrawEvent as h, type XenoAgentError as i, type XenoAgentIntent as j, type XenoAgentMessageEvent as k, type XenoAgentModel as l, type XenoAgentPatchEvent as m, type XenoAgentPatchFile as n, type XenoAgentProvider as o, type XenoAgentRole as p, type XenoAgentSession as q, type XenoAgentSessionClosedEvent as r, type XenoAgentSessionEvent as s, type XenoAgentStatus as t, type XenoAgentTerminalEvent as u, type XenoAgentToolEvent as v, type XenoAgentTurnEvent as w, isBusy as x, isWaitingOnUser as y };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@xenosystem/blocks",
3
- "version": "0.9.2",
4
- "description": "XENO Blocks \u2014 rung 3 of the front ladder: components composed into a contract-bearing unit (manifest: ports, intents, commands, agent surface), rendered by @xenosystem/workbench. ONE package, one subpath per family (/auth, /edit, /data, /time, /ops, /trust, /agent), one named export per block \u2014 XENO PACKAGE NAMING - STANDARD.md.",
3
+ "version": "0.10.1",
4
+ "description": "XENO Blocks — rung 3 of the front ladder: components composed into a contract-bearing unit (manifest: ports, intents, commands, agent surface), rendered by @xenosystem/workbench. ONE package, one subpath per family (/auth, /edit, /data, /time, /ops, /trust, /agent), one named export per block — XENO PACKAGE NAMING - STANDARD.md.",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",
7
7
  "sideEffects": false,
@@ -58,38 +58,38 @@
58
58
  "test": "vitest run"
59
59
  },
60
60
  "peerDependencies": {
61
- "@xenosystem/components": ">=0.9.1 <1",
61
+ "@duckdb/duckdb-wasm": ">=1.28.0",
62
+ "@xenosystem/block-sdk": "^0.3.0",
63
+ "@xenosystem/components": ">=0.9.3 <1",
64
+ "@xenosystem/data-core": "^0.1.0",
62
65
  "@xenosystem/elements-react": ">=0.0.1",
63
- "@xenosystem/workbench": "^1.0.0",
64
- "react": ">=18.0.0",
65
- "react-dom": ">=18.0.0",
66
- "@xenosystem/block-sdk": "^0.2.0",
66
+ "@xenosystem/time-core": "^0.1.0",
67
67
  "@xenosystem/tree-core": "^0.1.0",
68
- "@xterm/xterm": ">=5.5.0",
68
+ "@xenosystem/workbench": "^1.0.0",
69
69
  "@xterm/addon-fit": ">=0.10.0",
70
- "@xenosystem/time-core": "^0.1.0",
71
- "@xenosystem/data-core": "^0.1.0",
72
- "@duckdb/duckdb-wasm": ">=1.28.0"
70
+ "@xterm/xterm": ">=5.5.0",
71
+ "react": ">=18.0.0",
72
+ "react-dom": ">=18.0.0"
73
73
  },
74
74
  "devDependencies": {
75
75
  "@types/node": "^22.0.0",
76
76
  "@types/react": "^19.0.0",
77
77
  "@types/react-dom": "^19.0.0",
78
- "@xenosystem/components": "^0.9.1",
78
+ "@xenosystem/block-sdk": "^0.3.1",
79
+ "@xenosystem/components": "^0.9.3",
80
+ "@xenosystem/data-core": "^0.1.0",
79
81
  "@xenosystem/elements-react": "0.0.1",
80
- "@xenosystem/workbench": "^1.2.0",
82
+ "@xenosystem/time-core": "^0.1.0",
83
+ "@xenosystem/tree-core": "^0.1.0",
84
+ "@xenosystem/workbench": "^1.2.1",
85
+ "@xterm/addon-fit": "^0.11.0",
86
+ "@xterm/xterm": "^6.0.0",
81
87
  "jsdom": "^26.0.0",
82
88
  "react": "^19.0.0",
83
89
  "react-dom": "^19.0.0",
84
90
  "tsup": "^8.0.0",
85
91
  "typescript": "^5.4.0",
86
- "vitest": "^4.1.0",
87
- "@xenosystem/block-sdk": "^0.2.0",
88
- "@xenosystem/tree-core": "^0.1.0",
89
- "@xterm/xterm": "^6.0.0",
90
- "@xterm/addon-fit": "^0.11.0",
91
- "@xenosystem/time-core": "^0.1.0",
92
- "@xenosystem/data-core": "^0.1.0"
92
+ "vitest": "^4.1.0"
93
93
  },
94
94
  "publishConfig": {
95
95
  "access": "public"