@xenosystem/blocks 0.9.1 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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,15 +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
- /** The view. */
563
+ /**
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.
567
+ */
566
568
  declare function AgentPanelView({ controller, submitOnEnter, showLane, showSessions, emptyHint, }: AgentPanelViewProps): ReactNode;
567
569
 
568
- 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,8 @@ var agentManifest = {
1037
1037
  import { useSyncExternalStore } from "react";
1038
1038
  import {
1039
1039
  Badge,
1040
+ Column,
1041
+ Composer,
1040
1042
  EmptyState,
1041
1043
  Row,
1042
1044
  RowList,
@@ -1047,12 +1049,19 @@ import {
1047
1049
  Toolbar,
1048
1050
  ToolbarGroup
1049
1051
  } from "@xenosystem/components/chrome";
1050
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
1051
- var LANE_LABEL = {
1052
- cloud: "Cloud",
1053
- local: "Local",
1054
- 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: []
1055
1063
  };
1064
+ var LANE_LABEL = { cloud: "Cloud", local: "Local", acp: "ACP" };
1056
1065
  var TURN = {
1057
1066
  idle: { label: "Idle", tone: "neutral" },
1058
1067
  queued: { label: "Queued", tone: "neutral" },
@@ -1063,18 +1072,157 @@ var TURN = {
1063
1072
  failed: { label: "Failed", tone: "error" },
1064
1073
  cancelled: { label: "Cancelled", tone: "neutral" }
1065
1074
  };
1066
- var COLUMN = { display: "flex", flexDirection: "column", height: "100%", minHeight: 0 };
1067
- var COMPOSER = {
1068
- width: "100%",
1069
- minHeight: 64,
1070
- resize: "vertical",
1071
- background: "transparent",
1072
- color: "inherit",
1073
- border: "none",
1074
- outline: "none",
1075
- font: "inherit",
1076
- padding: "8px 10px"
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
+ }
1077
1222
  };
1223
+
1224
+ // src/agent/agent/react/AgentPanelView.tsx
1225
+ import { jsx, jsxs } from "react/jsx-runtime";
1078
1226
  function AgentPanelView({
1079
1227
  controller,
1080
1228
  submitOnEnter = true,
@@ -1083,96 +1231,74 @@ function AgentPanelView({
1083
1231
  emptyHint
1084
1232
  }) {
1085
1233
  const state = useSyncExternalStore(controller.subscribe, controller.getState, controller.getState);
1086
- if (state.connection === "failed") {
1087
- return /* @__PURE__ */ jsx(ErrorPane, { message: state.message });
1088
- }
1089
- if (state.connection === "connecting") {
1090
- return /* @__PURE__ */ jsx(EmptyState, { title: "Connecting\u2026", hint: "Waiting for the agent host." });
1091
- }
1092
- if (state.sessions.length === 0) {
1093
- return /* @__PURE__ */ jsxs("div", { style: COLUMN, children: [
1094
- /* @__PURE__ */ jsx(EmptyState, { title: "No sessions", hint: emptyHint ?? "Start a session to talk to an agent." }),
1095
- /* @__PURE__ */ jsx(
1096
- Toolbar,
1097
- {
1098
- right: /* @__PURE__ */ jsx(ToolbarGroup, { end: true, children: /* @__PURE__ */ jsx(TextButton, { onClick: () => controller.newSession(), children: "New session" }) })
1099
- }
1100
- )
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 })
1101
1242
  ] });
1102
1243
  }
1103
- const turn = TURN[state.turn];
1104
- const lane = state.activeProvider?.lane;
1105
- return /* @__PURE__ */ jsxs("div", { style: COLUMN, children: [
1244
+ return /* @__PURE__ */ jsxs(Column, { children: [
1106
1245
  /* @__PURE__ */ jsx(
1107
1246
  Toolbar,
1108
1247
  {
1109
1248
  left: /* @__PURE__ */ jsxs(ToolbarGroup, { children: [
1110
- /* @__PURE__ */ jsx(StatusBadge, { tone: turn.tone, children: turn.label }),
1111
- showLane && lane ? /* @__PURE__ */ jsx(Badge, { children: LANE_LABEL[lane] ?? lane }) : null,
1112
- 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
1113
1252
  ] }),
1114
- right: /* @__PURE__ */ jsx(ToolbarGroup, { end: true, children: /* @__PURE__ */ jsx(TextButton, { onClick: () => controller.newSession(), children: "New session" }) })
1253
+ right: newSession
1115
1254
  }
1116
1255
  ),
1117
- 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(
1118
1257
  Row,
1119
1258
  {
1120
1259
  noIcon: true,
1121
- label: session.title ?? session.id,
1122
- selected: session.id === state.active?.id,
1260
+ label: session.label,
1261
+ selected: session.selected,
1123
1262
  onClick: () => controller.selectSession(session.id),
1124
- trailing: /* @__PURE__ */ jsx(Badge, { children: TURN[session.turn ?? "idle"].label })
1263
+ trailing: /* @__PURE__ */ jsx(Badge, { children: session.turnLabel })
1125
1264
  },
1126
1265
  session.id
1127
1266
  )) }) }) : null,
1128
- 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(
1129
1268
  Row,
1130
1269
  {
1131
1270
  noIcon: true,
1132
1271
  label: provider.label,
1133
- meta: provider.unavailable ?? (showLane ? LANE_LABEL[provider.lane] ?? provider.lane : void 0),
1134
- disabled: provider.unavailable !== void 0,
1135
- selected: provider.id === state.activeProvider?.id,
1272
+ meta: provider.meta,
1273
+ disabled: provider.disabled,
1274
+ selected: provider.selected,
1136
1275
  onClick: () => controller.selectProvider(provider.id)
1137
1276
  },
1138
1277
  provider.id
1139
1278
  )) }) : null,
1140
1279
  /* @__PURE__ */ jsx(
1141
- "textarea",
1280
+ Composer,
1142
1281
  {
1143
- style: COMPOSER,
1144
- value: state.draft,
1145
- placeholder: state.busy ? "Steer the running turn\u2026" : "Ask the agent\u2026",
1146
- onChange: (event) => controller.setDraft(event.target.value),
1147
- onKeyDown: (event) => {
1148
- if (event.key !== "Enter") return;
1149
- const wantsSubmit = submitOnEnter ? !event.shiftKey : event.shiftKey;
1150
- if (!wantsSubmit) return;
1151
- event.preventDefault();
1152
- if (state.busy) controller.steer();
1153
- else controller.submit();
1154
- }
1282
+ value: v.draft,
1283
+ placeholder: v.placeholder,
1284
+ submitOnEnter,
1285
+ onChange: (draft) => controller.setDraft(draft),
1286
+ onSubmit: () => v.busy ? controller.steer() : controller.submit()
1155
1287
  }
1156
1288
  ),
1157
1289
  /* @__PURE__ */ jsx(
1158
1290
  StatusBar,
1159
1291
  {
1160
- left: state.message ?? state.active?.cwd ?? void 0,
1161
- right: /* @__PURE__ */ jsx(ToolbarGroup, { end: true, children: state.busy ? /* @__PURE__ */ jsxs(Fragment, { children: [
1162
- /* @__PURE__ */ jsx(TextButton, { onClick: () => controller.steer(), children: "Steer" }),
1163
- /* @__PURE__ */ jsx(TextButton, { onClick: () => controller.cancel(), children: "Stop" })
1164
- ] }) : (
1165
- // `disabled` derives from the SAME predicate `submit()` enforces, so an enabled
1166
- // button can never be a button that refuses.
1167
- /* @__PURE__ */ jsx(TextButton, { disabled: !state.canSubmit, onClick: () => controller.submit(), children: "Send" })
1168
- ) })
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
+ ] })
1169
1298
  }
1170
1299
  )
1171
1300
  ] });
1172
1301
  }
1173
- function ErrorPane({ message }) {
1174
- return /* @__PURE__ */ jsx(EmptyState, { title: "Not connected", hint: message ?? "The agent host reported a failure." });
1175
- }
1176
1302
 
1177
1303
  // src/agent/agent/panel.ts
1178
1304
  var CONNECTIONS = ["idle", "connecting", "ready", "failed"];
@@ -1416,6 +1542,7 @@ function wiringFor(panelId) {
1416
1542
  }
1417
1543
  export {
1418
1544
  AGENT_CATALOG_SCHEMA,
1545
+ AGENT_DECLARATION,
1419
1546
  AGENT_FANOUT_PORTS,
1420
1547
  AGENT_INTENT_SCHEMA,
1421
1548
  AGENT_PANEL_ID,
@@ -1425,10 +1552,15 @@ export {
1425
1552
  AgentController,
1426
1553
  AgentPanelView,
1427
1554
  AgentProjector,
1555
+ BEHAVIOURS,
1428
1556
  CONSENT_ELICITATION_RESULT_SCHEMA,
1429
1557
  CONSENT_ELICITATION_SCHEMA,
1558
+ LANE_LABEL,
1559
+ TURN,
1430
1560
  agentManifest,
1431
1561
  agentPanel,
1562
+ agentPanelView,
1563
+ agentViewManifest,
1432
1564
  countChanges,
1433
1565
  createAgentPanel,
1434
1566
  isBusy,
@@ -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.1",
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.0",
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.0 <1",
61
+ "@duckdb/duckdb-wasm": ">=1.28.0",
62
+ "@xenosystem/block-sdk": "^0.3.0",
63
+ "@xenosystem/components": ">=0.9.2 <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.0",
78
+ "@xenosystem/block-sdk": "^0.3.1",
79
+ "@xenosystem/components": "^0.9.2",
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"