@stigmer/react 3.12.7 → 3.12.8
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/composer/ComposerToolbar.d.ts +1 -19
- package/composer/ComposerToolbar.d.ts.map +1 -1
- package/composer/ComposerToolbar.js +2 -7
- package/composer/ComposerToolbar.js.map +1 -1
- package/composer/SessionComposer.d.ts +0 -10
- package/composer/SessionComposer.d.ts.map +1 -1
- package/composer/SessionComposer.js +2 -2
- package/composer/SessionComposer.js.map +1 -1
- package/composer/index.d.ts +0 -1
- package/composer/index.d.ts.map +1 -1
- package/composer/index.js.map +1 -1
- package/execution/ResultView.d.ts.map +1 -1
- package/execution/ResultView.js +6 -0
- package/execution/ResultView.js.map +1 -1
- package/execution/ToolCallItem.d.ts.map +1 -1
- package/execution/ToolCallItem.js +13 -2
- package/execution/ToolCallItem.js.map +1 -1
- package/execution/tool-categories.d.ts +1 -1
- package/execution/tool-categories.d.ts.map +1 -1
- package/execution/tool-categories.js +6 -0
- package/execution/tool-categories.js.map +1 -1
- package/identity-account/AccountPreferencesPanel.d.ts +2 -1
- package/identity-account/AccountPreferencesPanel.d.ts.map +1 -1
- package/identity-account/AccountPreferencesPanel.js +41 -3
- package/identity-account/AccountPreferencesPanel.js.map +1 -1
- package/identity-account/useAccountExecutionDefaults.d.ts +7 -0
- package/identity-account/useAccountExecutionDefaults.d.ts.map +1 -1
- package/identity-account/useAccountExecutionDefaults.js +5 -2
- package/identity-account/useAccountExecutionDefaults.js.map +1 -1
- package/index.d.ts +4 -4
- package/index.d.ts.map +1 -1
- package/index.js +1 -1
- package/index.js.map +1 -1
- package/internal/MemoryEnabledRow.d.ts +37 -0
- package/internal/MemoryEnabledRow.d.ts.map +1 -0
- package/internal/MemoryEnabledRow.js +25 -0
- package/internal/MemoryEnabledRow.js.map +1 -0
- package/memory/MemoryProposalCard.d.ts +35 -0
- package/memory/MemoryProposalCard.d.ts.map +1 -0
- package/memory/MemoryProposalCard.js +73 -0
- package/memory/MemoryProposalCard.js.map +1 -0
- package/memory/index.d.ts +2 -0
- package/memory/index.d.ts.map +1 -1
- package/memory/index.js +2 -0
- package/memory/index.js.map +1 -1
- package/memory/useMemory.d.ts +39 -0
- package/memory/useMemory.d.ts.map +1 -0
- package/memory/useMemory.js +43 -0
- package/memory/useMemory.js.map +1 -0
- package/organization/OrgPreferencesPanel.d.ts.map +1 -1
- package/organization/OrgPreferencesPanel.js +36 -4
- package/organization/OrgPreferencesPanel.js.map +1 -1
- package/package.json +4 -4
- package/session/AutoApproveIndicator.d.ts +18 -0
- package/session/AutoApproveIndicator.d.ts.map +1 -0
- package/session/AutoApproveIndicator.js +23 -0
- package/session/AutoApproveIndicator.js.map +1 -0
- package/session/NewSessionViewer.d.ts.map +1 -1
- package/session/NewSessionViewer.js +10 -9
- package/session/NewSessionViewer.js.map +1 -1
- package/session/SessionViewer.d.ts +21 -9
- package/session/SessionViewer.d.ts.map +1 -1
- package/session/SessionViewer.js +31 -21
- package/session/SessionViewer.js.map +1 -1
- package/session/facets/SetupTab.d.ts +43 -6
- package/session/facets/SetupTab.d.ts.map +1 -1
- package/session/facets/SetupTab.js +32 -36
- package/session/facets/SetupTab.js.map +1 -1
- package/session/facets/UsageTab.d.ts +2 -1
- package/session/facets/UsageTab.d.ts.map +1 -1
- package/session/facets/UsageTab.js +11 -5
- package/session/facets/UsageTab.js.map +1 -1
- package/session/facets/index.d.ts +1 -1
- package/session/facets/index.d.ts.map +1 -1
- package/session/facets/primitives.d.ts +58 -0
- package/session/facets/primitives.d.ts.map +1 -0
- package/session/facets/primitives.js +59 -0
- package/session/facets/primitives.js.map +1 -0
- package/session/index.d.ts +1 -1
- package/session/index.d.ts.map +1 -1
- package/session/index.js.map +1 -1
- package/session/useNewSessionFlow.d.ts +9 -4
- package/session/useNewSessionFlow.d.ts.map +1 -1
- package/session/useNewSessionFlow.js +20 -9
- package/session/useNewSessionFlow.js.map +1 -1
- package/session/useSessionPageFlow.d.ts +28 -10
- package/session/useSessionPageFlow.d.ts.map +1 -1
- package/session/useSessionPageFlow.js +16 -10
- package/session/useSessionPageFlow.js.map +1 -1
- package/src/attachment/__tests__/prepare-image.test.ts +12 -6
- package/src/composer/ComposerToolbar.tsx +0 -57
- package/src/composer/SessionComposer.tsx +1 -13
- package/src/composer/index.ts +0 -1
- package/src/execution/ResultView.tsx +6 -0
- package/src/execution/ToolCallItem.tsx +18 -1
- package/src/execution/tool-categories.ts +7 -0
- package/src/identity-account/AccountPreferencesPanel.tsx +89 -2
- package/src/identity-account/__tests__/AccountPreferencesPanel.test.tsx +112 -0
- package/src/identity-account/__tests__/useAccountExecutionDefaults.test.tsx +34 -1
- package/src/identity-account/useAccountExecutionDefaults.ts +12 -2
- package/src/index.ts +5 -1
- package/src/internal/MemoryEnabledRow.tsx +92 -0
- package/src/memory/MemoryProposalCard.tsx +181 -0
- package/src/memory/__tests__/MemoryProposalCard.test.tsx +236 -0
- package/src/memory/__tests__/memoryHooks.test.tsx +63 -0
- package/src/memory/index.ts +5 -0
- package/src/memory/useMemory.ts +80 -0
- package/src/organization/OrgPreferencesPanel.tsx +52 -3
- package/src/organization/__tests__/OrgPreferencesPanel.test.tsx +65 -0
- package/src/session/AutoApproveIndicator.tsx +45 -0
- package/src/session/NewSessionViewer.tsx +18 -15
- package/src/session/SessionViewer.tsx +70 -32
- package/src/session/__tests__/NewSessionViewer.test.tsx +32 -0
- package/src/session/__tests__/SessionViewer-autoApprove.test.tsx +244 -0
- package/src/session/__tests__/SessionViewer-transcriptExport.test.tsx +60 -22
- package/src/session/__tests__/useNewSessionFlow.test.tsx +56 -0
- package/src/session/__tests__/useSessionPageFlow.autoApprove.test.tsx +87 -0
- package/src/session/facets/SetupTab.tsx +193 -157
- package/src/session/facets/UsageTab.tsx +38 -38
- package/src/session/facets/index.ts +1 -0
- package/src/session/facets/primitives.tsx +169 -0
- package/src/session/index.ts +1 -0
- package/src/session/useNewSessionFlow.ts +30 -15
- package/src/session/useSessionPageFlow.ts +44 -20
- package/src/switch/Switch.tsx +4 -0
- package/src/workflow/__tests__/useWorkflowCanvas.dirty.test.tsx +7 -2
- package/src/workflow/__tests__/useWorkflowCanvas.drag.test.tsx +7 -2
- package/src/workspace/WorkspaceSurface.tsx +26 -3
- package/styles.css +1 -1
- package/switch/Switch.d.ts +3 -1
- package/switch/Switch.d.ts.map +1 -1
- package/switch/Switch.js +2 -2
- package/switch/Switch.js.map +1 -1
- package/workspace/WorkspaceSurface.js +11 -2
- package/workspace/WorkspaceSurface.js.map +1 -1
- package/src/composer/__tests__/ComposerToolbar-autoApprove.test.tsx +0 -80
- package/src/session/__tests__/SessionViewer-autoApproveToggle.test.tsx +0 -178
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
// Shared visual vocabulary for the session-panel facets (Config / Changes /
|
|
4
|
+
// Artifacts / Usage): one dense, VS Code-style row-and-section language so the
|
|
5
|
+
// facets read as one surface instead of three eras of styling. The Artifacts
|
|
6
|
+
// facet's `ArtifactRowView` set the idiom — compact rows, quiet metadata,
|
|
7
|
+
// hover/focus-revealed actions — and these primitives carry it to the
|
|
8
|
+
// non-file-list facets. All visual properties flow through `--stgm-*`
|
|
9
|
+
// tokens (DD-005).
|
|
10
|
+
|
|
11
|
+
import { cn } from "@stigmer/theme";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* A titled facet section: uppercase micro-heading over flush content.
|
|
15
|
+
* `count` renders the "(N)" suffix the retired inspector used; `annotation`
|
|
16
|
+
* renders a normal-case, muted trailing note (e.g. "next message only").
|
|
17
|
+
*/
|
|
18
|
+
export function FacetSection({
|
|
19
|
+
heading,
|
|
20
|
+
count,
|
|
21
|
+
annotation,
|
|
22
|
+
children,
|
|
23
|
+
}: {
|
|
24
|
+
readonly heading: string;
|
|
25
|
+
readonly count?: number;
|
|
26
|
+
readonly annotation?: string;
|
|
27
|
+
readonly children: React.ReactNode;
|
|
28
|
+
}) {
|
|
29
|
+
return (
|
|
30
|
+
<section className="stg:flex stg:flex-col stg:gap-1">
|
|
31
|
+
<h3 className="stg:px-2 stg:text-[0.65rem] stg:font-semibold stg:uppercase stg:tracking-wider stg:text-muted-foreground">
|
|
32
|
+
{heading}
|
|
33
|
+
{count != null && count > 0 && (
|
|
34
|
+
<span className="stg:ml-1 stg:text-muted-foreground-faint">({count})</span>
|
|
35
|
+
)}
|
|
36
|
+
{annotation && (
|
|
37
|
+
<span className="stg:ml-1 stg:font-normal stg:normal-case stg:tracking-normal stg:text-muted-foreground-faint">
|
|
38
|
+
({annotation})
|
|
39
|
+
</span>
|
|
40
|
+
)}
|
|
41
|
+
</h3>
|
|
42
|
+
{children}
|
|
43
|
+
</section>
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* One dense, non-interactive facet row: leading content, optional
|
|
49
|
+
* right-aligned metadata, and hover/focus-revealed trailing actions
|
|
50
|
+
* (the `group` the actions' reveal keys on). Interactive rows (whole-row
|
|
51
|
+
* buttons) build on {@link FACET_ROW_BUTTON} instead.
|
|
52
|
+
*/
|
|
53
|
+
export function FacetRow({
|
|
54
|
+
children,
|
|
55
|
+
meta,
|
|
56
|
+
actions,
|
|
57
|
+
className,
|
|
58
|
+
}: {
|
|
59
|
+
readonly children: React.ReactNode;
|
|
60
|
+
/** Right-aligned quiet metadata (counts, sizes, values). */
|
|
61
|
+
readonly meta?: React.ReactNode;
|
|
62
|
+
/** Hover/focus-revealed trailing controls — siblings, never nested. */
|
|
63
|
+
readonly actions?: React.ReactNode;
|
|
64
|
+
readonly className?: string;
|
|
65
|
+
}) {
|
|
66
|
+
return (
|
|
67
|
+
<div
|
|
68
|
+
className={cn(
|
|
69
|
+
"stg:group stg:flex stg:items-center stg:gap-2 stg:px-2 stg:py-1 stg:text-xs",
|
|
70
|
+
className,
|
|
71
|
+
)}
|
|
72
|
+
>
|
|
73
|
+
<span className="stg:flex stg:min-w-0 stg:flex-1 stg:items-center stg:gap-2 stg:text-foreground">
|
|
74
|
+
{children}
|
|
75
|
+
</span>
|
|
76
|
+
{meta && (
|
|
77
|
+
<span className="stg:shrink-0 stg:text-[0.65rem] stg:text-muted-foreground">
|
|
78
|
+
{meta}
|
|
79
|
+
</span>
|
|
80
|
+
)}
|
|
81
|
+
{actions}
|
|
82
|
+
</div>
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Class string for a whole-row interactive facet action (the
|
|
88
|
+
* `ArtifactRowView` open-button idiom): dense row metrics plus hover and
|
|
89
|
+
* focus-visible treatments. A string constant (not a component) so callers
|
|
90
|
+
* keep their own element type and extra classes.
|
|
91
|
+
*/
|
|
92
|
+
export const FACET_ROW_BUTTON = cn(
|
|
93
|
+
"stg:flex stg:w-full stg:min-w-0 stg:items-center stg:gap-2 stg:px-2 stg:py-1 stg:text-left stg:text-xs stg:text-muted-foreground stg:transition-colors",
|
|
94
|
+
"stg:hover:bg-muted stg:hover:text-foreground",
|
|
95
|
+
"stg:focus-visible:outline-none stg:focus-visible:ring-2 stg:focus-visible:ring-inset stg:focus-visible:ring-ring",
|
|
96
|
+
"stg:disabled:pointer-events-none stg:disabled:opacity-50",
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Hover/focus-revealed remove control for a {@link FacetRow} — the
|
|
101
|
+
* `ArtifactRowView` download-button reveal pattern applied to removal.
|
|
102
|
+
* Always reachable by keyboard (focus reveals it without hover).
|
|
103
|
+
*/
|
|
104
|
+
export function FacetRemoveButton({
|
|
105
|
+
onClick,
|
|
106
|
+
label,
|
|
107
|
+
}: {
|
|
108
|
+
readonly onClick: () => void;
|
|
109
|
+
readonly label: string;
|
|
110
|
+
}) {
|
|
111
|
+
return (
|
|
112
|
+
<button
|
|
113
|
+
type="button"
|
|
114
|
+
onClick={onClick}
|
|
115
|
+
aria-label={label}
|
|
116
|
+
className={cn(
|
|
117
|
+
"stg:flex stg:shrink-0 stg:items-center stg:text-muted-foreground stg:opacity-0 stg:transition-opacity",
|
|
118
|
+
"stg:group-hover:opacity-100 stg:focus-visible:opacity-100",
|
|
119
|
+
"stg:hover:text-destructive",
|
|
120
|
+
"stg:focus-visible:outline-none stg:focus-visible:ring-2 stg:focus-visible:ring-inset stg:focus-visible:ring-ring",
|
|
121
|
+
)}
|
|
122
|
+
>
|
|
123
|
+
<FacetXIcon />
|
|
124
|
+
</button>
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/** Muted empty-state line for a facet section with nothing to list. */
|
|
129
|
+
export function FacetEmptyHint({ children }: { readonly children: React.ReactNode }) {
|
|
130
|
+
return (
|
|
131
|
+
<p className="stg:px-2 stg:text-xs stg:text-muted-foreground-faint">{children}</p>
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* A key→value config row ("Harness Native"): muted label left, value
|
|
137
|
+
* right — the dense inverse of a definition list, sized like every other
|
|
138
|
+
* facet row. `children` is the value; pass a control (e.g. a Switch) for
|
|
139
|
+
* interactive config rows.
|
|
140
|
+
*/
|
|
141
|
+
export function FacetKeyValueRow({
|
|
142
|
+
label,
|
|
143
|
+
labelId,
|
|
144
|
+
children,
|
|
145
|
+
}: {
|
|
146
|
+
readonly label: string;
|
|
147
|
+
/** Optional id for the label span — point a control's `aria-labelledby` here. */
|
|
148
|
+
readonly labelId?: string;
|
|
149
|
+
readonly children: React.ReactNode;
|
|
150
|
+
}) {
|
|
151
|
+
return (
|
|
152
|
+
<div className="stg:flex stg:items-center stg:justify-between stg:gap-2 stg:px-2 stg:py-1 stg:text-xs">
|
|
153
|
+
<span id={labelId} className="stg:shrink-0 stg:text-muted-foreground">
|
|
154
|
+
{label}
|
|
155
|
+
</span>
|
|
156
|
+
<span className="stg:flex stg:min-w-0 stg:items-center stg:gap-1.5 stg:truncate stg:text-foreground">
|
|
157
|
+
{children}
|
|
158
|
+
</span>
|
|
159
|
+
</div>
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function FacetXIcon() {
|
|
164
|
+
return (
|
|
165
|
+
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
|
|
166
|
+
<path d="M4 4L10 10M10 4L4 10" />
|
|
167
|
+
</svg>
|
|
168
|
+
);
|
|
169
|
+
}
|
package/src/session/index.ts
CHANGED
|
@@ -116,6 +116,9 @@ export interface UseNewSessionFlowOptions {
|
|
|
116
116
|
* - model: stored per-harness choice > the account's model for the
|
|
117
117
|
* active harness (validated against the registry; a stale model
|
|
118
118
|
* silently falls through) > the harness default.
|
|
119
|
+
* - autoApprove: explicit in-session flip > the account's
|
|
120
|
+
* `default_auto_approve` > the host's `approvalDefaults` (derived,
|
|
121
|
+
* so a late-arriving value applies without a touched-ref effect).
|
|
119
122
|
*
|
|
120
123
|
* Seeded values are never persisted to localStorage — the account
|
|
121
124
|
* preference keeps applying until the user decides. Ignored for the
|
|
@@ -221,10 +224,12 @@ export interface UseNewSessionFlowReturn {
|
|
|
221
224
|
/**
|
|
222
225
|
* Pre-arm "auto-approve tool calls" for the session this surface will
|
|
223
226
|
* create (stigmer/stigmer#816, the walk-away scenario). Seeded from the
|
|
224
|
-
*
|
|
225
|
-
*
|
|
226
|
-
*
|
|
227
|
-
*
|
|
227
|
+
* account's `default_auto_approve` preference and the host's
|
|
228
|
+
* `StigmerProvider` `approvalDefaults` (#302) — guests inherit neither;
|
|
229
|
+
* the user's explicit flip (the Config facet switch) wins from then on.
|
|
230
|
+
* Carried into the bootstrap create as `spec.auto_approve_all` — the
|
|
231
|
+
* whole-run server-side bypass — so the first run stays covered even if
|
|
232
|
+
* the user closes the tab.
|
|
228
233
|
*/
|
|
229
234
|
readonly autoApproveAll: boolean;
|
|
230
235
|
/** Set the user's explicit auto-approve choice for the created session. */
|
|
@@ -323,18 +328,28 @@ export function useNewSessionFlow(
|
|
|
323
328
|
const contextTarget = useExecutionTarget();
|
|
324
329
|
const executionTarget = options.executionTarget ?? contextTarget;
|
|
325
330
|
const adapter = useRunnerAdapter();
|
|
326
|
-
// Auto-approve for the session about to be created (#816):
|
|
327
|
-
//
|
|
328
|
-
//
|
|
329
|
-
//
|
|
330
|
-
//
|
|
331
|
-
//
|
|
332
|
-
//
|
|
333
|
-
//
|
|
331
|
+
// Auto-approve for the session about to be created (#816): derived like
|
|
332
|
+
// useSessionPageFlow's — the user's explicit flip wins, otherwise the
|
|
333
|
+
// truth is computed from its seeds:
|
|
334
|
+
//
|
|
335
|
+
// effective = userChoice ?? (accountSeed || hostSeed)
|
|
336
|
+
//
|
|
337
|
+
// Derived rather than useState-initialized because the account preference
|
|
338
|
+
// (default_auto_approve) resolves async with whoAmI — a mount-time
|
|
339
|
+
// initializer would silently miss it (the harness seed's late-arrival
|
|
340
|
+
// problem, solved here by derivation instead of a touched-ref effect).
|
|
341
|
+
// Guests inherit neither seed — a share-link visitor is not the operator
|
|
342
|
+
// either trust judgment covers (the GUEST_HARNESS fixed-platform-policy
|
|
343
|
+
// reasoning). Carried into the bootstrap create as spec.auto_approve_all,
|
|
344
|
+
// the whole-run server-side bypass — the created run stays covered even
|
|
345
|
+
// if this tab dies before its first gate.
|
|
334
346
|
const approvalDefaults = useApprovalDefaults();
|
|
335
|
-
const [
|
|
336
|
-
|
|
337
|
-
|
|
347
|
+
const [autoApproveChoice, setAutoApproveAll] = useState<boolean | null>(null);
|
|
348
|
+
const autoApproveAll =
|
|
349
|
+
autoApproveChoice ??
|
|
350
|
+
(!isGuest &&
|
|
351
|
+
((accountDefaults?.autoApprove ?? false) ||
|
|
352
|
+
(approvalDefaults?.autoApproveAll ?? false)));
|
|
338
353
|
|
|
339
354
|
const [harness, setHarnessRaw] = useState<HarnessOption>(() => {
|
|
340
355
|
// Guests get the fixed platform policy (see GUEST_HARNESS) and never
|
|
@@ -22,6 +22,7 @@ import { toSessionUpdateInput } from "@stigmer/sdk";
|
|
|
22
22
|
import type { SessionAudience } from "./audience.js";
|
|
23
23
|
import { isChannelOriginSession } from "./channelOrigin.js";
|
|
24
24
|
import { assertValidRunConfig, type SessionRunConfig } from "./run-config.js";
|
|
25
|
+
import type { AccountExecutionDefaults } from "../identity-account/useAccountExecutionDefaults.js";
|
|
25
26
|
|
|
26
27
|
/**
|
|
27
28
|
* Well-known Daytona sandbox workspace root. Used as the SDK safety-net
|
|
@@ -69,6 +70,18 @@ export interface UseSessionPageFlowOptions {
|
|
|
69
70
|
* config). See {@link SessionRunConfig}.
|
|
70
71
|
*/
|
|
71
72
|
readonly runConfig?: SessionRunConfig;
|
|
73
|
+
/**
|
|
74
|
+
* The user's account-level execution defaults, typically from
|
|
75
|
+
* `useAccountExecutionDefaults()`. On the session page only
|
|
76
|
+
* `autoApprove` applies — it seeds the session-scoped auto-approve
|
|
77
|
+
* state so a user whose `default_auto_approve` preference is ON gets
|
|
78
|
+
* armed follow-ups on every session, not just newly created ones. An
|
|
79
|
+
* explicit in-session flip always wins for this session; the seed may
|
|
80
|
+
* arrive after mount (whoAmI resolves async) and still applies, being
|
|
81
|
+
* part of the derivation rather than an initializer. Ignored for the
|
|
82
|
+
* `"guest"` audience (guests inherit no identity-derived preference).
|
|
83
|
+
*/
|
|
84
|
+
readonly accountDefaults?: AccountExecutionDefaults;
|
|
72
85
|
}
|
|
73
86
|
|
|
74
87
|
/** Return value of {@link useSessionPageFlow}. */
|
|
@@ -146,28 +159,33 @@ export interface UseSessionPageFlowReturn {
|
|
|
146
159
|
* `false` by default. `true` when any of its sources arms it — the user's
|
|
147
160
|
* explicit choice always winning:
|
|
148
161
|
*
|
|
149
|
-
* 1. the user's
|
|
162
|
+
* 1. the user's Config facet switch ({@link setAutoApproveAll});
|
|
150
163
|
* 2. "Approve & don't ask again" at an approval gate (see
|
|
151
164
|
* {@link submitApproval});
|
|
152
|
-
* 3. the
|
|
165
|
+
* 3. the account's `default_auto_approve` preference
|
|
166
|
+
* (`UseSessionPageFlowOptions.accountDefaults`, guests excluded);
|
|
167
|
+
* 4. the host's app-wide `StigmerProvider` `approvalDefaults` (#302,
|
|
153
168
|
* guests excluded);
|
|
154
|
-
*
|
|
169
|
+
* 5. the active in-flight execution having been created with
|
|
155
170
|
* `spec.auto_approve_all` (e.g. armed on the new-session surface), so
|
|
156
171
|
* the state survives the launcher → session-page handoff.
|
|
157
172
|
*
|
|
158
173
|
* While `true`, follow-ups carry `auto_approve_all` ({@link handleSubmit})
|
|
159
174
|
* and gates appearing in the in-flight run are auto-released (never for
|
|
160
|
-
* guest/observer/channel-origin surfaces).
|
|
161
|
-
* reload back to the
|
|
175
|
+
* guest/observer/channel-origin surfaces). The explicit per-session flip is
|
|
176
|
+
* held in memory only — reset on reload back to the seeds; the account
|
|
177
|
+
* preference is the one persisted default, declared by the user in
|
|
178
|
+
* Account Preferences.
|
|
162
179
|
*/
|
|
163
180
|
readonly autoApproveAll: boolean;
|
|
164
181
|
/**
|
|
165
182
|
* Set the user's explicit session-scoped auto-approve choice. Wired to the
|
|
166
|
-
*
|
|
167
|
-
*
|
|
168
|
-
*
|
|
169
|
-
*
|
|
170
|
-
*
|
|
183
|
+
* Config facet's switch; an explicit `false` wins over both seeds and over
|
|
184
|
+
* an armed in-flight run for everything the client controls (follow-up
|
|
185
|
+
* carry, gate auto-release) — an already-armed run's server-side bypass
|
|
186
|
+
* cannot be revoked mid-run, exactly as with today's gate-time "Approve &
|
|
187
|
+
* don't ask again". Never written back to the account preference: the
|
|
188
|
+
* flip is scoped to THIS conversation.
|
|
171
189
|
*/
|
|
172
190
|
readonly setAutoApproveAll: (value: boolean) => void;
|
|
173
191
|
|
|
@@ -340,27 +358,33 @@ export function useSessionPageFlow(
|
|
|
340
358
|
// the user's explicit in-session decision wins, otherwise the truth is
|
|
341
359
|
// computed from its sources — never an effect-synced copy:
|
|
342
360
|
//
|
|
343
|
-
// effective = userChoice ?? (hostSeed || runArmed)
|
|
361
|
+
// effective = userChoice ?? (accountSeed || hostSeed || runArmed)
|
|
344
362
|
//
|
|
345
|
-
// - `userChoice`: the
|
|
346
|
-
// ask again" (which has always escalated the session preference).
|
|
363
|
+
// - `userChoice`: the Config facet's switch, or the gate-time "Approve &
|
|
364
|
+
// don't ask again" (which has always escalated the session preference).
|
|
365
|
+
// - `accountSeed`: the account's default_auto_approve preference — the
|
|
366
|
+
// user's own persisted walk-away default. Resolves async with whoAmI;
|
|
367
|
+
// being part of the derivation (not an initializer), a late arrival
|
|
368
|
+
// still applies unless the user has already flipped this session.
|
|
347
369
|
// - `hostSeed`: the host's provider-level approvalDefaults (#302) — an
|
|
348
|
-
// app-level trust judgment. Guests
|
|
349
|
-
// visitor is not the operator
|
|
370
|
+
// app-level trust judgment. Guests inherit neither seed (a share-link
|
|
371
|
+
// visitor is not the operator either trust judgment covers).
|
|
350
372
|
// - `runArmed`: the ACTIVE execution was created with
|
|
351
|
-
// spec.auto_approve_all, so the
|
|
373
|
+
// spec.auto_approve_all, so the switch reflects an armed in-flight run —
|
|
352
374
|
// this is what carries the state across the new-session → session-page
|
|
353
375
|
// handoff. Deliberately derived from the active execution ONLY, never
|
|
354
376
|
// from history: deriving from past executions would silently survive a
|
|
355
|
-
// reload
|
|
377
|
+
// reload independent of the seeds above.
|
|
356
378
|
//
|
|
357
|
-
//
|
|
358
|
-
// re-applies the
|
|
379
|
+
// The explicit choice lives only in memory for the life of this page —
|
|
380
|
+
// reset on reload re-applies the seeds (the account preference now being
|
|
381
|
+
// the persisted one the user actually declared), never a per-session flip.
|
|
359
382
|
const approvalDefaults = useApprovalDefaults();
|
|
360
383
|
const [autoApproveChoice, setAutoApproveChoice] = useState<boolean | null>(null);
|
|
384
|
+
const accountSeed = !isGuest && (options.accountDefaults?.autoApprove ?? false);
|
|
361
385
|
const hostSeed = !isGuest && (approvalDefaults?.autoApproveAll ?? false);
|
|
362
386
|
const runArmed = conv.activeStreamExecution?.spec?.autoApproveAll === true;
|
|
363
|
-
const autoApproveAll = autoApproveChoice ?? (hostSeed || runArmed);
|
|
387
|
+
const autoApproveAll = autoApproveChoice ?? (accountSeed || hostSeed || runArmed);
|
|
364
388
|
const setAutoApproveAll = useCallback((value: boolean) => {
|
|
365
389
|
setAutoApproveChoice(value);
|
|
366
390
|
}, []);
|
package/src/switch/Switch.tsx
CHANGED
|
@@ -17,6 +17,8 @@ export interface SwitchProps {
|
|
|
17
17
|
readonly "aria-label"?: string;
|
|
18
18
|
/** ID of the element that labels this switch. */
|
|
19
19
|
readonly "aria-labelledby"?: string;
|
|
20
|
+
/** ID of the element that describes this switch (helper copy). */
|
|
21
|
+
readonly "aria-describedby"?: string;
|
|
20
22
|
/** Element ID, for association with an external `<label htmlFor>`. */
|
|
21
23
|
readonly id?: string;
|
|
22
24
|
/** Additional CSS classes for the root button. */
|
|
@@ -54,6 +56,7 @@ export function Switch({
|
|
|
54
56
|
disabled,
|
|
55
57
|
"aria-label": ariaLabel,
|
|
56
58
|
"aria-labelledby": ariaLabelledby,
|
|
59
|
+
"aria-describedby": ariaDescribedby,
|
|
57
60
|
id,
|
|
58
61
|
className,
|
|
59
62
|
}: SwitchProps) {
|
|
@@ -65,6 +68,7 @@ export function Switch({
|
|
|
65
68
|
aria-checked={checked}
|
|
66
69
|
aria-label={ariaLabel}
|
|
67
70
|
aria-labelledby={ariaLabelledby}
|
|
71
|
+
aria-describedby={ariaDescribedby}
|
|
68
72
|
disabled={disabled}
|
|
69
73
|
onClick={() => onCheckedChange(!checked)}
|
|
70
74
|
className={cn(
|
|
@@ -2,7 +2,7 @@ import { describe, it, expect } from "vitest";
|
|
|
2
2
|
import { renderHook, act } from "@testing-library/react";
|
|
3
3
|
import type { ReactNode } from "react";
|
|
4
4
|
import { ReactFlowProvider } from "@xyflow/react";
|
|
5
|
-
import type { Node } from "@xyflow/react";
|
|
5
|
+
import type { Node, OnNodeDrag } from "@xyflow/react";
|
|
6
6
|
import { useWorkflowCanvas } from "../useWorkflowCanvas";
|
|
7
7
|
|
|
8
8
|
// Regression tests for oss#609: isDirty was a model-reference comparison
|
|
@@ -54,7 +54,12 @@ function renderCanvas() {
|
|
|
54
54
|
|
|
55
55
|
type CanvasResult = ReturnType<typeof renderCanvas>["result"];
|
|
56
56
|
|
|
57
|
-
|
|
57
|
+
// The drag fixture derives its type from the handler itself, so it tracks
|
|
58
|
+
// whatever event type the installed @xyflow/react declares (the pinned
|
|
59
|
+
// 12.10.2 takes the React synthetic event; newer majors take the native
|
|
60
|
+
// event) — a dependency bump can never strand this cast again (#821's
|
|
61
|
+
// hand-written native-MouseEvent cast did not compile under npm ci).
|
|
62
|
+
const DRAG_EVENT = {} as Parameters<OnNodeDrag>[0];
|
|
58
63
|
|
|
59
64
|
/** Drives one full drag gesture the way React Flow produces it. */
|
|
60
65
|
function drag(result: CanvasResult, id: string, to: { x: number; y: number }) {
|
|
@@ -2,7 +2,7 @@ import { describe, it, expect } from "vitest";
|
|
|
2
2
|
import { renderHook, act } from "@testing-library/react";
|
|
3
3
|
import type { ReactNode } from "react";
|
|
4
4
|
import { ReactFlowProvider } from "@xyflow/react";
|
|
5
|
-
import type { Node } from "@xyflow/react";
|
|
5
|
+
import type { Node, OnNodeDrag } from "@xyflow/react";
|
|
6
6
|
import { useWorkflowCanvas } from "../useWorkflowCanvas";
|
|
7
7
|
|
|
8
8
|
// Regression tests for oss#602: node drags updated only React Flow's copy
|
|
@@ -51,7 +51,12 @@ function renderCanvas() {
|
|
|
51
51
|
|
|
52
52
|
type CanvasResult = ReturnType<typeof renderCanvas>["result"];
|
|
53
53
|
|
|
54
|
-
|
|
54
|
+
// The drag fixture derives its type from the handler itself, so it tracks
|
|
55
|
+
// whatever event type the installed @xyflow/react declares (the pinned
|
|
56
|
+
// 12.10.2 takes the React synthetic event; newer majors take the native
|
|
57
|
+
// event) — a dependency bump can never strand this cast again (#821's
|
|
58
|
+
// hand-written native-MouseEvent cast did not compile under npm ci).
|
|
59
|
+
const DRAG_EVENT = {} as Parameters<OnNodeDrag>[0];
|
|
55
60
|
|
|
56
61
|
function canvasPosition(result: CanvasResult, id: string): { x: number; y: number } {
|
|
57
62
|
const node = result.current.nodes.find((n) => n.id === id);
|
|
@@ -695,8 +695,16 @@ function EditorArea({
|
|
|
695
695
|
<div className="stg:flex stg:h-full stg:min-h-0 stg:flex-col">
|
|
696
696
|
{/* Collapse control + tab strip. The far right is kept clear (pr-24):
|
|
697
697
|
the session viewer floats its top-right controls (host
|
|
698
|
-
`headerActions` and the panel chip) over this region.
|
|
699
|
-
|
|
698
|
+
`headerActions` and the panel chip) over this region. Fixed to the
|
|
699
|
+
shared HEADER_ROW_HEIGHT so this row's bottom border stays flush
|
|
700
|
+
with the sidebar facet header's — and so an empty tab strip (no
|
|
701
|
+
open editors) cannot collapse the row. */}
|
|
702
|
+
<div
|
|
703
|
+
className={cn(
|
|
704
|
+
HEADER_ROW_HEIGHT,
|
|
705
|
+
"stg:flex stg:shrink-0 stg:items-stretch stg:border-b stg:border-border stg:pr-24",
|
|
706
|
+
)}
|
|
707
|
+
>
|
|
700
708
|
<Tooltip>
|
|
701
709
|
<TooltipTrigger
|
|
702
710
|
render={
|
|
@@ -843,9 +851,24 @@ function Breadcrumbs({
|
|
|
843
851
|
// Shared sidebar chrome
|
|
844
852
|
// ---------------------------------------------------------------------------
|
|
845
853
|
|
|
854
|
+
/**
|
|
855
|
+
* One fixed height for every header row across the surface — the sidebar
|
|
856
|
+
* facet header AND the editor area's tab-strip row — so their bottom borders
|
|
857
|
+
* form a single continuous line across the panel. Fixed rather than
|
|
858
|
+
* padding-derived: the two rows have different content (micro-caps title vs
|
|
859
|
+
* text-xs tabs, sometimes no tabs at all), so padding math can never keep
|
|
860
|
+
* them aligned.
|
|
861
|
+
*/
|
|
862
|
+
const HEADER_ROW_HEIGHT = "stg:h-8";
|
|
863
|
+
|
|
846
864
|
function SidebarHeader({ title }: { readonly title: string }) {
|
|
847
865
|
return (
|
|
848
|
-
<div
|
|
866
|
+
<div
|
|
867
|
+
className={cn(
|
|
868
|
+
HEADER_ROW_HEIGHT,
|
|
869
|
+
"stg:flex stg:shrink-0 stg:items-center stg:border-b stg:border-border stg:px-3 stg:text-[0.65rem] stg:font-semibold stg:uppercase stg:tracking-wide stg:text-muted-foreground",
|
|
870
|
+
)}
|
|
871
|
+
>
|
|
849
872
|
{title}
|
|
850
873
|
</div>
|
|
851
874
|
);
|