GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — Merge remote-tracking branch 'origin/staging' into feat-enhance-cmd-k · simstudioai/sim@9ad2d36

File tree

Expand file treeCollapse file tree
Open diff view settings
Filter options
  • README.md
  • apps
    • docs/content/docs/en
      • integrations
        • incidentio.mdx
        • salesforce-service-account.mdx
      • platform/self-hosting
        • docker.mdx
        • upgrades.mdx
    • sim
      • app/workspace/[workspaceId]
        • home
          • components/mothership-chat
            • mothership-chat.tsx
            • sizer-floor.test.ts
            • sizer-floor.ts
          • home.tsx
          • hooks
            • use-chat.mount-send.test.tsx
            • use-chat.ts
        • w/[workflowId]/components/panel
          • panel.tsx
      • blocks/blocks
        • incidentio.ts
      • lib
        • core/utils
          • browser-storage.ts
        • integrations
          • integrations.json
        • logs
          • execution
            • logger.test.ts
            • logger.ts
            • trace-store.test.ts
            • trace-store.ts
          • types.ts
        • mothership
          • events.ts
      • stores/mothership-queue
        • store.ts
        • types.ts
      • tools
        • generated
          • tool-ids.ts
          • tool-metadata.ts
          • tool-outputs.ts
        • incidentio
          • actions_create.ts
          • actions_update.ts
          • alert_events_create.ts
          • alerts_list.test.ts
          • alerts_list.ts
          • alerts_resolve.ts
          • alerts_show.ts
          • catalog_entries_list.ts
          • catalog_types_list.ts
          • escalations_cancel.ts
          • follow_ups_create.ts
          • follow_ups_update.ts
          • incident_alerts_list.ts
          • incident_memberships_create.ts
          • incident_memberships_revoke.ts
          • incident_participants_list.ts
          • index.ts
          • on_call_now.ts
          • schedule_overrides_list.ts
          • schedules_list.ts
          • schedules_show.ts
          • teams_list.ts
          • teams_show.ts
          • types.ts
        • registry.ts
  • scripts/setup
    • capability-config.test.ts
    • capability-config.ts
    • capability-setup.ts
    • index.ts
    • lifecycle.test.ts
    • lifecycle.ts
    • modes
      • compose.ts
      • dev.ts
      • k8s.ts
    • steps.test.ts
    • steps.ts
    • wizard.ts

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Dismiss banner
Expand file treeCollapse file tree
Open diff view settings
Collapse file

‎README.md‎

Copy file name to clipboardExpand all lines: README.md
+1Lines changed: 1 addition & 0 deletions
  • Display the source diff
  • Display the rich diff
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ Manage your install with `bun run sim`:
105105

106106
```bash
107107
bun run sim start | stop | restart # bring your install up / down / cycle
108+
bun run sim update # pull/rebuild and apply Compose images
108109
bun run sim status # what's installed and healthy
109110
bun run sim logs # follow logs
110111
bun run sim doctor # diagnose configuration problems
Collapse file

‎apps/docs/content/docs/en/integrations/incidentio.mdx‎

Copy file name to clipboardExpand all lines: apps/docs/content/docs/en/integrations/incidentio.mdx
+640Lines changed: 640 additions & 0 deletions
  • Display the source diff
  • Display the rich diff
Large diffs are not rendered by default.
Collapse file

‎apps/docs/content/docs/en/integrations/salesforce-service-account.mdx‎

Copy file name to clipboardExpand all lines: apps/docs/content/docs/en/integrations/salesforce-service-account.mdx
+23-6Lines changed: 23 additions & 6 deletions
  • Display the source diff
  • Display the rich diff
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ External Client Apps are Salesforce's current-generation connected apps and the
5656
{/* TODO(screenshot): New External Client App form with the basic details filled in */}
5757
</Step>
5858
<Step>
59-
In the OAuth settings section, enable OAuth (exact labels vary by Salesforce release)
59+
Open the app's **Edit Settings** → **API (Enable OAuth Settings)** section and turn on **Enable OAuth**
6060
</Step>
6161
<Step>
6262
Enter any placeholder **Callback URL** (e.g. `https://login.salesforce.com/services/oauth2/callback`) — it's required by the form but unused by this flow
@@ -81,7 +81,7 @@ External Client Apps are Salesforce's current-generation connected apps and the
8181
Open your app in **External Client App Manager** and edit its **Policies**
8282
</Step>
8383
<Step>
84-
Under **OAuth Policies** → **Client Credentials Flow**, check **Enable Client Credentials Flow** and set **Run As** to the integration user from step 1, then save
84+
Under **OAuth Policies** → **Client Credentials Flow**, set **Run As** to the integration user from step 1, then save. That page holds only the Run As picker — the **Enable Client Credentials Flow** checkbox itself lives in **Edit Settings** → **OAuth Settings**, where you set it in step 2
8585

8686
{/* TODO(screenshot): OAuth Policies with the Run As integration user set under Client Credentials Flow */}
8787
</Step>
@@ -133,9 +133,13 @@ The JWT Bearer Flow authenticates with an uploaded certificate rather than a sha
133133
```
134134

135135
Keep `server.key` somewhere safe — Sim stores it encrypted and never shows it again.
136+
137+
<Callout type="warn">
138+
Salesforce requires an **RSA** key of at least 2048 bits for this flow; an ECDSA key is rejected. The uploaded certificate must also stay under 4 KB, which a 2048-bit self-signed cert comfortably is.
139+
</Callout>
136140
</Step>
137141
<Step>
138-
In **External Client App Manager** → your app → **Edit Settings** → **OAuth Settings**, enable the **JWT Bearer Flow** toggle and upload `server.crt`. On a legacy Connected App the equivalent is **Use digital signatures** with the same file
142+
In **External Client App Manager** → your app → **Edit Settings** → **OAuth Settings**, turn on **Enable OAuth** (the JWT toggle does not appear until it is on), then **Enable JWT Bearer Flow**, and use **Upload Files** to upload `server.crt`. On a legacy Connected App the equivalent is **Use digital signatures** with the same file
139143
</Step>
140144
<Step>
141145
Edit the app's **Policies** → **OAuth Policies** and set **Permitted Users** to **Admin approved users are pre-authorized**
@@ -145,7 +149,11 @@ The JWT Bearer Flow authenticates with an uploaded certificate rather than a sha
145149
</Callout>
146150
</Step>
147151
<Step>
148-
Assign the integration user's **profile** or a **permission set** to the app (External Client App Manager → your app → **Policies** → manage profiles/permission sets), so that user is covered by the pre-authorization
152+
Assign the integration user's **profile** or a **permission set** to the app, so that user is covered by the pre-authorization
153+
154+
<Callout type="warn">
155+
Assign it through the **profile**, or through a **second permission set that does _not_ carry the Salesforce API Integration permission set license**. A permission set backed by that license cannot hold an **Assigned Connected Apps** / **Assigned External Client Apps** section at all, so the app can never be assigned from the same permission set that grants the user its object access. Getting this wrong produces exactly the `user hasn't approved this consumer` failure this step exists to prevent.
156+
</Callout>
149157
</Step>
150158
<Step>
151159
Copy the **Consumer Key** as in step 4. There is no consumer secret to copy — the JWT flow doesn't use one
@@ -158,7 +166,7 @@ Go to **Setup** and search for **My Domain**. The host is required — Salesforc
158166

159167
- **Production:** `yourorg.my.salesforce.com`
160168
- **Sandbox:** `yourorg--sandboxname.sandbox.my.salesforce.com`
161-
- **Developer Edition:** `yourorg-dev-ed.develop.my.salesforce.com`
169+
- **Developer Edition:** `yourorg.develop.my.salesforce.com` (Salesforce appends `-dev-ed` only when it generated the name for you)
162170

163171
Sim also accepts other partitioned My Domain hosts (`scratch`, `demo`, `patch`, `trailblaze`, `free`).
164172

@@ -176,6 +184,15 @@ There's no scope picking beyond the **api** and **openid** scopes on the app —
176184

177185
A permissions gap surfaces at run time as a Salesforce API error; fix it on the integration user's permission sets — no changes are needed in Sim.
178186

187+
<Callout type="warn">
188+
On the **Salesforce Integration** (API-only) license specifically, SOQL and CRUD on standard objects are well supported, but two areas are not safe to assume:
189+
190+
- **Reports and dashboards** are unverified on this license. Salesforce documents neither a grant nor a prohibition. Test them in a sandbox before depending on them, and remember the user also needs access to the report or dashboard **folder**.
191+
- **Anything Apex-related is blocked** — Apex Class Access is one of the permissions this license cannot hold, so Tooling API calls touching `ApexClass` will fail. Custom field and custom object management is unaffected.
192+
193+
If a workflow must run reports, a standard-seat integration user is the safe choice.
194+
</Callout>
195+
179196
## Adding the Service Account to Sim
180197

181198
<Steps>
@@ -230,7 +247,7 @@ Deactivating or freezing the integration user — the Run As user for client cre
230247
{ question: "Setup → App Manager → New Connected App is greyed out — why?", answer: "Salesforce disabled new Connected App creation by default (new orgs since Summer '25, all orgs since Spring '26); re-enabling it requires a Salesforce Support request. You don't need it — create an External Client App instead (Setup → External Client App Manager), which supports the same Client Credentials Flow and produces the same consumer key and secret." },
231248
{ question: "Why do I have to enter a My Domain host instead of login.salesforce.com?", answer: "Salesforce only supports the Client Credentials Flow at your org's My Domain URL — login.salesforce.com and test.salesforce.com are explicitly rejected for this flow. Find yours under Setup → My Domain." },
232249
{ question: "The credential validates but a specific tool fails with a permission error — why?", answer: "Every call runs as the Run As user, so the failing tool needs a permission that user doesn't have. Common gaps: Customize Application for custom field/object tools, Run Reports plus folder access for report tools, and object or field permissions for the records involved. Fix it on the integration user's permission sets and re-run." },
233-
{ question: "Does this work with sandboxes and Developer Edition orgs?", answer: "Yes — enter the sandbox host (yourorg--sandboxname.sandbox.my.salesforce.com) or Developer Edition host (yourorg-dev-ed.develop.my.salesforce.com) as the My Domain host. Government/military domains (*.my.salesforce.mil) aren't currently supported." },
250+
{ question: "Does this work with sandboxes and Developer Edition orgs?", answer: "Yes — enter the sandbox host (yourorg--sandboxname.sandbox.my.salesforce.com) or Developer Edition host (yourorg.develop.my.salesforce.com, with a -dev-ed suffix only if Salesforce generated the name for you) as the My Domain host. Government/military domains (*.my.salesforce.mil) aren't currently supported." },
234251
{ question: "How do I rotate the credentials?", answer: "For client credentials, rotate the Consumer Secret from the app's OAuth settings (External Client App: Settings → OAuth Settings → Consumer Key and Secret; legacy Connected App: Manage Consumer Details), then update the credential in Sim with the new secret. For JWT bearer, generate a new key pair, upload the new certificate to the app, and paste the new private key into Sim. Either way, reconnecting asks you to restate the authentication method — Sim never returns a stored secret, so it cannot pre-select it for you." },
235252
{ question: "What happens if the integration user is deactivated or frozen?", answer: "All token minting fails with invalid_grant and every workflow using the credential stops. Reactivate the user (or point Run As at a new integration user) and runs resume — no changes needed in Sim." },
236253
]} />
Collapse file

‎apps/docs/content/docs/en/platform/self-hosting/docker.mdx‎

Copy file name to clipboardExpand all lines: apps/docs/content/docs/en/platform/self-hosting/docker.mdx
+2-3Lines changed: 2 additions & 3 deletions
  • Display the source diff
  • Display the rich diff
Original file line numberDiff line numberDiff line change
@@ -149,8 +149,8 @@ docker compose -f docker-compose.prod.yml logs migrations
149149
# Is the scheduler firing?
150150
docker compose -f docker-compose.prod.yml logs -f cron
151151

152-
# Upgrade: bump SIM_VERSION in .env, then
153-
docker compose -f docker-compose.prod.yml pull && docker compose -f docker-compose.prod.yml up -d
152+
# Upgrade: bump SIM_VERSION in .env when pinned, then
153+
bun run sim update
154154
```
155155

156156
<FAQ items={[
@@ -159,4 +159,3 @@ docker compose -f docker-compose.prod.yml pull && docker compose -f docker-compo
159159
{ question: "How do I back up and restore the database?", answer: "Back up with: docker compose -f docker-compose.prod.yml exec db pg_dump -U postgres simstudio > backup.sql. Restore with: docker compose -f docker-compose.prod.yml exec -T db psql -U postgres simstudio < backup.sql. The database data is persisted in a Docker volume named postgres_data."},
160160
{ question: "Can I customize the PostgreSQL credentials?", answer: "Yes. The docker-compose.prod.yml uses environment variable defaults: POSTGRES_USER (default: postgres), POSTGRES_PASSWORD (default: postgres), POSTGRES_DB (default: simstudio), and POSTGRES_PORT (default: 5432). Set these in your .env file to override them." },
161161
]} />
162-
Collapse file

‎apps/docs/content/docs/en/platform/self-hosting/upgrades.mdx‎

Copy file name to clipboardExpand all lines: apps/docs/content/docs/en/platform/self-hosting/upgrades.mdx
+5-2Lines changed: 5 additions & 2 deletions
  • Display the source diff
  • Display the rich diff
Original file line numberDiff line numberDiff line change
@@ -142,11 +142,14 @@ kubectl logs -n simstudio deploy/sim-app -c migrations --tail=100
142142
<Tab value="Docker Compose">
143143

144144
```bash
145-
docker compose -f docker-compose.prod.yml pull
146-
docker compose -f docker-compose.prod.yml up -d
145+
bun run sim update
147146
docker compose -f docker-compose.prod.yml logs migrations
148147
```
149148

149+
`bun run sim update` pulls the versions configured by `SIM_VERSION` (or `latest` when it is
150+
unset), recreates the changed services, and keeps data volumes. It is equivalent to running
151+
`docker compose pull` followed by `docker compose up -d`.
152+
150153
There is a short window where the app is unavailable while containers restart. Compose has no rolling-update mechanism — plan a maintenance window, or run Kubernetes if you need zero-downtime upgrades.
151154

152155
</Tab>
Collapse file

‎apps/sim/app/workspace/[workspaceId]/home/components/mothership-chat/mothership-chat.tsx‎

Copy file name to clipboardExpand all lines: apps/sim/app/workspace/[workspaceId]/home/components/mothership-chat/mothership-chat.tsx
+37-13Lines changed: 37 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import {
2929
parseLastCredentialTag,
3030
parseLastQuestionTag,
3131
} from '@/app/workspace/[workspaceId]/home/components/message-content/components/special-tags'
32+
import { nextSizerFloor } from '@/app/workspace/[workspaceId]/home/components/mothership-chat/sizer-floor'
3233
import { QueuedMessages } from '@/app/workspace/[workspaceId]/home/components/queued-messages'
3334
import {
3435
UserInput,
@@ -328,6 +329,8 @@ export function MothershipChat({
328329
const sizerRef = useRef<HTMLDivElement | null>(null)
329330
const scrollerPaddingRef = useRef<{ top: number; bottom: number } | null>(null)
330331
const sizerFloorAppliedRef = useRef(0)
332+
const heldHighWaterRef = useRef(0)
333+
const floorChatRef = useRef<string | undefined>(undefined)
331334
const floorDrainRafRef = useRef(0)
332335
useEffect(() => () => cancelAnimationFrame(floorDrainRafRef.current), [])
333336

@@ -337,11 +340,11 @@ export function MothershipChat({
337340
* row-height shrinks; when they pull scrollHeight under
338341
* `scrollTop + clientHeight`, the browser clamps `scrollTop` and the pinned
339342
* transcript visibly drops, then the chase glides it back. Flooring the
340-
* sizer at exactly the scrolled-to extent prevents that clamp while never
341-
* ADDING space — the floor cannot exceed what is already on screen. So an
342-
* estimate correction (a fresh row measuring smaller than
343-
* ROW_HEIGHT_ESTIMATE) releases immediately instead of holding phantom space
344-
* the chase would scroll into and bounce back out of.
343+
* sizer prevents that clamp while never ADDING space, so an estimate
344+
* correction (a fresh row measuring smaller than ROW_HEIGHT_ESTIMATE)
345+
* releases immediately instead of holding phantom space the chase would
346+
* scroll into and bounce back out of. {@link nextSizerFloor} owns the value
347+
* and the invariant that keeps it honest.
345348
*
346349
* Active on the same signal as auto-scroll: the reveal keeps re-parsing
347350
* markdown (and shrinking) after the network stream closes, so the floor
@@ -361,7 +364,26 @@ export function MothershipChat({
361364
const sizer = sizerRef.current
362365
const el = scrollElementRef.current
363366
if (!sizer || !el) return
367+
// A chat switch replaces the entire transcript, so a floor held for the
368+
// previous one is meaningless — and its high-water mark would otherwise
369+
// hand a short chat the tall chat's space for as long as the outgoing
370+
// turn's `lastRowAnimating` keeps the floor engaged. Released outright
371+
// rather than drained: the switch re-lands the viewport anyway, so there
372+
// is no eased settle to preserve. A pending chat adopting its id is the
373+
// SAME conversation, so it must not release mid-turn.
374+
if (floorChatRef.current !== chatId) {
375+
const isPendingPersist = floorChatRef.current === undefined && chatId !== undefined
376+
floorChatRef.current = chatId
377+
if (!isPendingPersist) {
378+
cancelAnimationFrame(floorDrainRafRef.current)
379+
floorDrainRafRef.current = 0
380+
sizerFloorAppliedRef.current = 0
381+
heldHighWaterRef.current = 0
382+
sizer.style.minHeight = ''
383+
}
384+
}
364385
if (!floorActive) {
386+
heldHighWaterRef.current = 0
365387
if (sizerFloorAppliedRef.current === 0) return
366388
// A drain already in flight keeps its own rAF cadence — settle-burst
367389
// commits re-enter this branch and must not add extra steps in layout,
@@ -405,14 +427,16 @@ export function MothershipChat({
405427
}
406428
}
407429
const padding = scrollerPaddingRef.current
408-
// Math.floor, not the raw float: a fractional min-height can round
409-
// scrollHeight 1px ABOVE the scrolled-to extent, and that phantom 1px gap
410-
// re-derives 1px higher after every chase step — a visible 1px/frame
411-
// upward creep whenever the floor is what's holding scrollHeight.
412-
const floor = Math.max(
413-
0,
414-
Math.floor(el.scrollTop + el.clientHeight - padding.top - padding.bottom)
415-
)
430+
const { floor, highWater } = nextSizerFloor({
431+
previousHighWater: heldHighWaterRef.current,
432+
appliedFloor: sizerFloorAppliedRef.current,
433+
contentHeight: virtualizer.getTotalSize(),
434+
scrollTop: el.scrollTop,
435+
clientHeight: el.clientHeight,
436+
paddingTop: padding.top,
437+
paddingBottom: padding.bottom,
438+
})
439+
heldHighWaterRef.current = highWater
416440
// Dead-band: the floor feeds back into its own inputs (a floored value can
417441
// land a fraction BELOW the extent, the browser clamps scrollTop, and the
418442
// next commit re-derives from the clamped position — a visible ~1px×N
Collapse file

‎apps/sim/app/workspace/[workspaceId]/home/components/mothership-chat/sizer-floor.test.ts‎

Copy file name to clipboard
+90Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
/**
2+
* @vitest-environment node
3+
*/
4+
import { describe, expect, it } from 'vitest'
5+
import { nextSizerFloor } from '@/app/workspace/[workspaceId]/home/components/mothership-chat/sizer-floor'
6+
7+
/** Matches the transcript scroller's `pt-4 pb-2`. */
8+
const PADDING = { paddingTop: 16, paddingBottom: 8 }
9+
/** A viewport scrolled to the bottom of 2000px of content: extent resolves to 2000. */
10+
const PINNED = { scrollTop: 1424, clientHeight: 600, ...PADDING }
11+
12+
describe('nextSizerFloor', () => {
13+
it('follows the scrolled-to extent while it stays under the high-water mark', () => {
14+
const { floor } = nextSizerFloor({
15+
...PINNED,
16+
previousHighWater: 5000,
17+
appliedFloor: 0,
18+
contentHeight: 5000,
19+
})
20+
expect(floor).toBe(2000)
21+
})
22+
23+
it('floors fractional scroll offsets down so the sizer cannot round above the extent', () => {
24+
const { floor } = nextSizerFloor({
25+
scrollTop: 100.7,
26+
clientHeight: 600,
27+
...PADDING,
28+
previousHighWater: 5000,
29+
appliedFloor: 0,
30+
contentHeight: 5000,
31+
})
32+
expect(floor).toBe(676)
33+
})
34+
35+
it('never returns a negative floor for a container smaller than its padding', () => {
36+
const { floor } = nextSizerFloor({
37+
scrollTop: 0,
38+
clientHeight: 8,
39+
...PADDING,
40+
previousHighWater: 500,
41+
appliedFloor: 0,
42+
contentHeight: 500,
43+
})
44+
expect(floor).toBe(0)
45+
})
46+
47+
it('never exceeds the content height when the transcript is shorter than the viewport', () => {
48+
const { floor } = nextSizerFloor({
49+
scrollTop: 0,
50+
clientHeight: 600,
51+
...PADDING,
52+
previousHighWater: 0,
53+
appliedFloor: 0,
54+
contentHeight: 180,
55+
})
56+
expect(floor).toBe(180)
57+
})
58+
59+
it('holds the high-water mark when content re-measures smaller mid-turn', () => {
60+
const { floor, highWater } = nextSizerFloor({
61+
...PINNED,
62+
previousHighWater: 2000,
63+
appliedFloor: 2000,
64+
contentHeight: 1940,
65+
})
66+
expect(highWater).toBe(2000)
67+
expect(floor).toBe(2000)
68+
})
69+
70+
it('carries undrained debt across a turn boundary that interrupts the drain', () => {
71+
const { floor, highWater } = nextSizerFloor({
72+
...PINNED,
73+
previousHighWater: 0,
74+
appliedFloor: 1985,
75+
contentHeight: 1940,
76+
})
77+
expect(highWater).toBe(1985)
78+
expect(floor).toBe(1985)
79+
})
80+
81+
it('raises the high-water mark as content grows', () => {
82+
const { highWater } = nextSizerFloor({
83+
...PINNED,
84+
previousHighWater: 1200,
85+
appliedFloor: 1200,
86+
contentHeight: 1600,
87+
})
88+
expect(highWater).toBe(1600)
89+
})
90+
})

0 commit comments

Comments
0 (0)
You are visitor 01402520 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.