@mattstack/rt-client 0.26.0 → 0.27.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.
@@ -108,6 +108,7 @@ export type GateOption = string | {
108
108
  value: string;
109
109
  label: string;
110
110
  recommended?: boolean;
111
+ description?: string;
111
112
  };
112
113
  export interface GateOrigin {
113
114
  paneId?: string;
@@ -117,11 +118,14 @@ export interface GateOrigin {
117
118
  surface?: string;
118
119
  presentation?: "form" | "wait";
119
120
  }
121
+ /** `context` is per-question material (what this one choice turns on);
122
+ the gate-level `context` on the open/ask payload is the whole ask's. */
120
123
  export interface GateQuestion {
121
124
  id: string;
122
125
  label: string;
123
126
  multi: boolean;
124
127
  options: GateOption[];
128
+ context?: string;
125
129
  }
126
130
  /** Implementations live in gate-options.ts (the browser-safe ./gate
127
131
  subpath); re-exported here so existing commands.ts/index.ts consumers
@@ -1506,9 +1510,10 @@ export interface Commands {
1506
1510
  worktree?: string;
1507
1511
  };
1508
1512
  };
1509
- /** `contextOmitted` appears only when the caller's context exceeded the
1510
- 8192-byte cap and was dropped: the gate still opened, but with none of
1511
- the material the reader needs. */
1513
+ /** `contextOmitted` appears only when the gate context plus every
1514
+ question's `context` exceeded their shared 8192-byte budget: the
1515
+ gate still opened, but question contexts were dropped, and the gate
1516
+ context too when it was over the budget on its own. */
1512
1517
  data: {
1513
1518
  id: string;
1514
1519
  presentation: "form" | "wait";
@@ -5,6 +5,9 @@ import type { GateOption, GateQuestion } from "./commands.ts";
5
5
  export interface GateOptionObject {
6
6
  value: string;
7
7
  label: string;
8
+ /** Per-option explanation, carried verbatim: never capitalized, never
9
+ suffixed, never filled in from value/label. */
10
+ description?: string;
8
11
  }
9
12
  export declare function gateOptionValue(o: GateOption): string;
10
13
  export declare function gateOptionLabel(o: GateOption): string;
@@ -17,8 +20,13 @@ export declare function gateOptionLabel(o: GateOption): string;
17
20
  word-like (see isWordLikeLabel), and an object form's `recommended:
18
21
  true` lifts into a " (Recommended)" label suffix -- guarded against
19
22
  double-appending -- since `recommended` itself does not survive into
20
- the returned object; the suffix IS its wire representation. Every
21
- returned entry is a full {value,label} pair -- callers may trust the
22
- return type without re-checking it. Pure and order-preserving. */
23
+ the returned object; the suffix IS its wire representation. An object
24
+ form's non-empty string `description` rides along untouched (no
25
+ capitalization, no suffix); any other description shape is dropped.
26
+ Every returned entry is a full {value,label} pair -- callers may trust
27
+ the return type without re-checking it. Pure and order-preserving. */
23
28
  export declare function normalizeGateOptions(options: GateOption[]): GateOptionObject[];
29
+ /** Options normalize per normalizeGateOptions; a question's `context` is
30
+ kept verbatim when it is a non-blank string and dropped otherwise, so a
31
+ stored row never carries an empty or non-string context key. */
24
32
  export declare function normalizeGateQuestions(questions: GateQuestion[]): GateQuestion[];
package/dist/gate.js CHANGED
@@ -33,11 +33,18 @@ function normalizeGateOptions(options) {
33
33
  label = capitalize(label);
34
34
  if (recommended && label && !HAS_RECOMMENDED_SUFFIX.test(label))
35
35
  label += RECOMMENDED_SUFFIX;
36
- return { value, label };
36
+ const d = o !== null && typeof o === "object" ? o.description : undefined;
37
+ return typeof d === "string" && d ? { value, label, description: d } : { value, label };
37
38
  });
38
39
  }
39
40
  function normalizeGateQuestions(questions) {
40
- return questions.map((q) => ({ ...q, options: normalizeGateOptions(q.options) }));
41
+ return questions.map((q) => {
42
+ const { context, ...rest } = q;
43
+ const out = { ...rest, options: normalizeGateOptions(q.options) };
44
+ if (typeof context === "string" && context.trim())
45
+ out.context = context;
46
+ return out;
47
+ });
41
48
  }
42
49
 
43
50
  // src/gate-answers.ts
package/dist/index.js CHANGED
@@ -493,11 +493,18 @@ function normalizeGateOptions(options) {
493
493
  label = capitalize(label);
494
494
  if (recommended && label && !HAS_RECOMMENDED_SUFFIX.test(label))
495
495
  label += RECOMMENDED_SUFFIX;
496
- return { value, label };
496
+ const d = o !== null && typeof o === "object" ? o.description : undefined;
497
+ return typeof d === "string" && d ? { value, label, description: d } : { value, label };
497
498
  });
498
499
  }
499
500
  function normalizeGateQuestions(questions) {
500
- return questions.map((q) => ({ ...q, options: normalizeGateOptions(q.options) }));
501
+ return questions.map((q) => {
502
+ const { context, ...rest } = q;
503
+ const out = { ...rest, options: normalizeGateOptions(q.options) };
504
+ if (typeof context === "string" && context.trim())
505
+ out.context = context;
506
+ return out;
507
+ });
501
508
  }
502
509
 
503
510
  // src/commands.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mattstack/rt-client",
3
- "version": "0.26.0",
3
+ "version": "0.27.0",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {
package/src/commands.ts CHANGED
@@ -97,7 +97,7 @@ export const GATE_BY_PANE = "pane";
97
97
  export type GateStatus = "open" | "answered" | "parked" | "closed";
98
98
  /** Reconciler's view of an agent's liveness; also the value `GateRow.executor` is stamped with. */
99
99
  export type ExecutorState = "live" | "blocked" | "hidden" | "gone" | "cleared" | "unknown";
100
- export type GateOption = string | { value: string; label: string; recommended?: boolean };
100
+ export type GateOption = string | { value: string; label: string; recommended?: boolean; description?: string };
101
101
  export interface GateOrigin {
102
102
  paneId?: string;
103
103
  tabId?: string;
@@ -106,7 +106,9 @@ export interface GateOrigin {
106
106
  surface?: string;
107
107
  presentation?: "form" | "wait";
108
108
  }
109
- export interface GateQuestion { id: string; label: string; multi: boolean; options: GateOption[] }
109
+ /** `context` is per-question material (what this one choice turns on);
110
+ the gate-level `context` on the open/ask payload is the whole ask's. */
111
+ export interface GateQuestion { id: string; label: string; multi: boolean; options: GateOption[]; context?: string }
110
112
  /** Implementations live in gate-options.ts (the browser-safe ./gate
111
113
  subpath); re-exported here so existing commands.ts/index.ts consumers
112
114
  are unaffected. */
@@ -711,9 +713,10 @@ export interface Commands {
711
713
  agent?: string;
712
714
  origin?: { surface?: string; tabId?: string; worktree?: string };
713
715
  };
714
- /** `contextOmitted` appears only when the caller's context exceeded the
715
- 8192-byte cap and was dropped: the gate still opened, but with none of
716
- the material the reader needs. */
716
+ /** `contextOmitted` appears only when the gate context plus every
717
+ question's `context` exceeded their shared 8192-byte budget: the
718
+ gate still opened, but question contexts were dropped, and the gate
719
+ context too when it was over the budget on its own. */
717
720
  data: { id: string; presentation: "form" | "wait"; subject: string; supersededId: string | null; contextOmitted?: true };
718
721
  };
719
722
  /**
@@ -6,6 +6,9 @@ import type { GateOption, GateQuestion } from "./commands.ts";
6
6
  export interface GateOptionObject {
7
7
  value: string;
8
8
  label: string;
9
+ /** Per-option explanation, carried verbatim: never capitalized, never
10
+ suffixed, never filled in from value/label. */
11
+ description?: string;
9
12
  }
10
13
 
11
14
  export function gateOptionValue(o: GateOption): string {
@@ -45,9 +48,11 @@ function capitalize(label: string): string {
45
48
  word-like (see isWordLikeLabel), and an object form's `recommended:
46
49
  true` lifts into a " (Recommended)" label suffix -- guarded against
47
50
  double-appending -- since `recommended` itself does not survive into
48
- the returned object; the suffix IS its wire representation. Every
49
- returned entry is a full {value,label} pair -- callers may trust the
50
- return type without re-checking it. Pure and order-preserving. */
51
+ the returned object; the suffix IS its wire representation. An object
52
+ form's non-empty string `description` rides along untouched (no
53
+ capitalization, no suffix); any other description shape is dropped.
54
+ Every returned entry is a full {value,label} pair -- callers may trust
55
+ the return type without re-checking it. Pure and order-preserving. */
51
56
  export function normalizeGateOptions(options: GateOption[]): GateOptionObject[] {
52
57
  return options.map((o) => {
53
58
  const recommended = o !== null && typeof o === "object" && (o as { recommended?: unknown }).recommended === true;
@@ -70,10 +75,19 @@ export function normalizeGateOptions(options: GateOption[]): GateOptionObject[]
70
75
  // downstream `label || value` fallback (gate-kit) must still see label
71
76
  // as absent, not as a non-empty "(Recommended)" that hides the value.
72
77
  if (recommended && label && !HAS_RECOMMENDED_SUFFIX.test(label)) label += RECOMMENDED_SUFFIX;
73
- return { value, label };
78
+ const d = o !== null && typeof o === "object" ? (o as { description?: unknown }).description : undefined;
79
+ return typeof d === "string" && d ? { value, label, description: d } : { value, label };
74
80
  });
75
81
  }
76
82
 
83
+ /** Options normalize per normalizeGateOptions; a question's `context` is
84
+ kept verbatim when it is a non-blank string and dropped otherwise, so a
85
+ stored row never carries an empty or non-string context key. */
77
86
  export function normalizeGateQuestions(questions: GateQuestion[]): GateQuestion[] {
78
- return questions.map((q) => ({ ...q, options: normalizeGateOptions(q.options) }));
87
+ return questions.map((q) => {
88
+ const { context, ...rest } = q;
89
+ const out: GateQuestion = { ...rest, options: normalizeGateOptions(q.options) };
90
+ if (typeof context === "string" && context.trim()) out.context = context;
91
+ return out;
92
+ });
79
93
  }