Skip to content

Commit 991ed05

Browse files
Merge remote-tracking branch 'origin/feat/credential-v2-api' into feat/sim-cli
# Conflicts: # apps/sim/lib/copilot/tools/handlers/oauth.ts
2 parents 7d17fc9 + b413183 commit 991ed05

435 files changed

Lines changed: 11174 additions & 10977 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.agents/skills/migrate-application-operation/SKILL.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,43 @@ Classify each as `migrate`, `defer`, or `non-goal`. Do not migrate adjacent oper
7878

7979
Preserve behavior unless the task explicitly changes it. Stop and report a decision when surfaces currently disagree on security or compatibility behavior; do not silently choose one.
8080

81+
## Freeze observable behavior before editing
82+
83+
Treat the legacy route or tool as an ordered program, not merely a bag of business logic. Before moving code, write a compact baseline for every in-scope entry point and add focused characterization tests for behavior not already pinned down.
84+
85+
Capture all of these when they apply:
86+
87+
- Accepted inputs, including trimming, blank omission, duplicate query keys, aliases, defaults, and bounds.
88+
- Authentication and authorization order, minimum roles, resource membership, concealment, and exact error/status mapping.
89+
- Exact success bodies, optional fields, status codes, redirects, cookies, headers, and binary or stream behavior.
90+
- Mutation ordering, transaction boundaries, idempotency, no-ops, and observable state after each possible partial failure.
91+
- Audit, notification, analytics, and billing timing plus exact semantic dimensions and attribution.
92+
- Browser or protocol state ownership, concurrency isolation, expiry, callback ordering, and cleanup behavior.
93+
- Every value newly crossing into HTML, JavaScript, SQL, URLs, logs, provider payloads, or another encoding context.
94+
95+
Compare the old statement order with the proposed application lifecycle explicitly:
96+
97+
```text
98+
legacy parse/normalize
99+
-> legacy authorization checks
100+
-> branch-specific canonical lookup
101+
-> mutation(s)
102+
-> per-step side effects
103+
-> response or redirect catch
104+
```
105+
106+
Moving those steps under a wrapper may change behavior even when each individual call is reused. In particular:
107+
108+
- `projectAudit` and `afterSuccess` run only after `execute` returns. They cannot describe earlier committed mutations when a later step throws. Make the compound mutation atomic or define explicit partial-result/failure projection semantics before migrating it.
109+
- Operation metadata is executable policy. Adding a resource role to a workspace-only legacy read is an authorization change, not an architectural cleanup.
110+
- A shared error policy does not automatically preserve route-local concealment, subclass ordering, browser redirects, or branch-specific messages.
111+
- A shared contract does not automatically preserve manual `URLSearchParams` normalization or exact legacy response unions.
112+
- A shared use case may own domain behavior while separate surface presenters still preserve different wire shapes.
113+
- Per-flow identity is insufficient when another part of the flow remains in browser-global state such as one cookie.
114+
- Passing a newly supported parameter through old rendering code creates a new security boundary even when the renderer itself is unchanged.
115+
116+
Fail fast if the baseline cannot be established from code, tests, or an explicit product decision. Do not infer that behavior is unimportant because it was previously implicit.
117+
81118
## Keep the layers distinct
82119

83120
Use these responsibilities:
@@ -270,6 +307,10 @@ Add focused tests for every migrated surface and principal kind allowed by the o
270307
- Public API: personal and workspace keys, rate and rollout behavior, concealment, exact external envelope, and rate headers.
271308
- Copilot or tools: trusted context, exact registered operation membership, rejected forged scope, aliases and resume paths, permission re-check, safe errors, and unchanged tool result shapes.
272309
- Side effects: audit derives from authoritative results; shared notifications follow audit; neither occurs for rejection or no-op.
310+
- Compatibility characterization: legacy normalization, exact response/redirect/cookie behavior, concealment, error subclass precedence, and branch-specific output.
311+
- Failure sequencing: inject a failure after each independently committing step and assert persisted state plus audit, analytics, and notification effects.
312+
- Concurrency: overlap stateful browser or provider flows and prove each callback consumes only its own state and return destination.
313+
- Rendering boundaries: exercise hostile values for every newly connected input that reaches HTML, inline JavaScript, URLs, logs, or provider requests.
273314

274315
Run at minimum:
275316

.claude/commands/migrate-application-operation.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,43 @@ Classify each as `migrate`, `defer`, or `non-goal`. Do not migrate adjacent oper
7777

7878
Preserve behavior unless the task explicitly changes it. Stop and report a decision when surfaces currently disagree on security or compatibility behavior; do not silently choose one.
7979

80+
## Freeze observable behavior before editing
81+
82+
Treat the legacy route or tool as an ordered program, not merely a bag of business logic. Before moving code, write a compact baseline for every in-scope entry point and add focused characterization tests for behavior not already pinned down.
83+
84+
Capture all of these when they apply:
85+
86+
- Accepted inputs, including trimming, blank omission, duplicate query keys, aliases, defaults, and bounds.
87+
- Authentication and authorization order, minimum roles, resource membership, concealment, and exact error/status mapping.
88+
- Exact success bodies, optional fields, status codes, redirects, cookies, headers, and binary or stream behavior.
89+
- Mutation ordering, transaction boundaries, idempotency, no-ops, and observable state after each possible partial failure.
90+
- Audit, notification, analytics, and billing timing plus exact semantic dimensions and attribution.
91+
- Browser or protocol state ownership, concurrency isolation, expiry, callback ordering, and cleanup behavior.
92+
- Every value newly crossing into HTML, JavaScript, SQL, URLs, logs, provider payloads, or another encoding context.
93+
94+
Compare the old statement order with the proposed application lifecycle explicitly:
95+
96+
```text
97+
legacy parse/normalize
98+
-> legacy authorization checks
99+
-> branch-specific canonical lookup
100+
-> mutation(s)
101+
-> per-step side effects
102+
-> response or redirect catch
103+
```
104+
105+
Moving those steps under a wrapper may change behavior even when each individual call is reused. In particular:
106+
107+
- `projectAudit` and `afterSuccess` run only after `execute` returns. They cannot describe earlier committed mutations when a later step throws. Make the compound mutation atomic or define explicit partial-result/failure projection semantics before migrating it.
108+
- Operation metadata is executable policy. Adding a resource role to a workspace-only legacy read is an authorization change, not an architectural cleanup.
109+
- A shared error policy does not automatically preserve route-local concealment, subclass ordering, browser redirects, or branch-specific messages.
110+
- A shared contract does not automatically preserve manual `URLSearchParams` normalization or exact legacy response unions.
111+
- A shared use case may own domain behavior while separate surface presenters still preserve different wire shapes.
112+
- Per-flow identity is insufficient when another part of the flow remains in browser-global state such as one cookie.
113+
- Passing a newly supported parameter through old rendering code creates a new security boundary even when the renderer itself is unchanged.
114+
115+
Fail fast if the baseline cannot be established from code, tests, or an explicit product decision. Do not infer that behavior is unimportant because it was previously implicit.
116+
80117
## Keep the layers distinct
81118

82119
Use these responsibilities:
@@ -269,6 +306,10 @@ Add focused tests for every migrated surface and principal kind allowed by the o
269306
- Public API: personal and workspace keys, rate and rollout behavior, concealment, exact external envelope, and rate headers.
270307
- Copilot or tools: trusted context, exact registered operation membership, rejected forged scope, aliases and resume paths, permission re-check, safe errors, and unchanged tool result shapes.
271308
- Side effects: audit derives from authoritative results; shared notifications follow audit; neither occurs for rejection or no-op.
309+
- Compatibility characterization: legacy normalization, exact response/redirect/cookie behavior, concealment, error subclass precedence, and branch-specific output.
310+
- Failure sequencing: inject a failure after each independently committing step and assert persisted state plus audit, analytics, and notification effects.
311+
- Concurrency: overlap stateful browser or provider flows and prove each callback consumes only its own state and return destination.
312+
- Rendering boundaries: exercise hostile values for every newly connected input that reaches HTML, inline JavaScript, URLs, logs, or provider requests.
272313

273314
Run at minimum:
274315

.cursor/commands/migrate-application-operation.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,43 @@ Classify each as `migrate`, `defer`, or `non-goal`. Do not migrate adjacent oper
7373

7474
Preserve behavior unless the task explicitly changes it. Stop and report a decision when surfaces currently disagree on security or compatibility behavior; do not silently choose one.
7575

76+
## Freeze observable behavior before editing
77+
78+
Treat the legacy route or tool as an ordered program, not merely a bag of business logic. Before moving code, write a compact baseline for every in-scope entry point and add focused characterization tests for behavior not already pinned down.
79+
80+
Capture all of these when they apply:
81+
82+
- Accepted inputs, including trimming, blank omission, duplicate query keys, aliases, defaults, and bounds.
83+
- Authentication and authorization order, minimum roles, resource membership, concealment, and exact error/status mapping.
84+
- Exact success bodies, optional fields, status codes, redirects, cookies, headers, and binary or stream behavior.
85+
- Mutation ordering, transaction boundaries, idempotency, no-ops, and observable state after each possible partial failure.
86+
- Audit, notification, analytics, and billing timing plus exact semantic dimensions and attribution.
87+
- Browser or protocol state ownership, concurrency isolation, expiry, callback ordering, and cleanup behavior.
88+
- Every value newly crossing into HTML, JavaScript, SQL, URLs, logs, provider payloads, or another encoding context.
89+
90+
Compare the old statement order with the proposed application lifecycle explicitly:
91+
92+
```text
93+
legacy parse/normalize
94+
-> legacy authorization checks
95+
-> branch-specific canonical lookup
96+
-> mutation(s)
97+
-> per-step side effects
98+
-> response or redirect catch
99+
```
100+
101+
Moving those steps under a wrapper may change behavior even when each individual call is reused. In particular:
102+
103+
- `projectAudit` and `afterSuccess` run only after `execute` returns. They cannot describe earlier committed mutations when a later step throws. Make the compound mutation atomic or define explicit partial-result/failure projection semantics before migrating it.
104+
- Operation metadata is executable policy. Adding a resource role to a workspace-only legacy read is an authorization change, not an architectural cleanup.
105+
- A shared error policy does not automatically preserve route-local concealment, subclass ordering, browser redirects, or branch-specific messages.
106+
- A shared contract does not automatically preserve manual `URLSearchParams` normalization or exact legacy response unions.
107+
- A shared use case may own domain behavior while separate surface presenters still preserve different wire shapes.
108+
- Per-flow identity is insufficient when another part of the flow remains in browser-global state such as one cookie.
109+
- Passing a newly supported parameter through old rendering code creates a new security boundary even when the renderer itself is unchanged.
110+
111+
Fail fast if the baseline cannot be established from code, tests, or an explicit product decision. Do not infer that behavior is unimportant because it was previously implicit.
112+
76113
## Keep the layers distinct
77114

78115
Use these responsibilities:
@@ -265,6 +302,10 @@ Add focused tests for every migrated surface and principal kind allowed by the o
265302
- Public API: personal and workspace keys, rate and rollout behavior, concealment, exact external envelope, and rate headers.
266303
- Copilot or tools: trusted context, exact registered operation membership, rejected forged scope, aliases and resume paths, permission re-check, safe errors, and unchanged tool result shapes.
267304
- Side effects: audit derives from authoritative results; shared notifications follow audit; neither occurs for rejection or no-op.
305+
- Compatibility characterization: legacy normalization, exact response/redirect/cookie behavior, concealment, error subclass precedence, and branch-specific output.
306+
- Failure sequencing: inject a failure after each independently committing step and assert persisted state plus audit, analytics, and notification effects.
307+
- Concurrency: overlap stateful browser or provider flows and prove each callback consumes only its own state and return destination.
308+
- Rendering boundaries: exercise hostile values for every newly connected input that reaches HTML, inline JavaScript, URLs, logs, or provider requests.
268309

269310
Run at minimum:
270311

apps/desktop/src/main/browser-agent/driver.ts

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ import type { BrowserDownloadsState, BrowserToolbarCommand } from '@sim/desktop-
2929
import { createLogger } from '@sim/logger'
3030
import { getErrorMessage } from '@sim/utils/errors'
3131
import { sleep } from '@sim/utils/helpers'
32-
import { isRecordLike, omit } from '@sim/utils/object'
32+
import { isRecordLike, omit, toRecord } from '@sim/utils/object'
3333
import type { BrowserWindow, MenuItemConstructorOptions, WebContents, WebFrameMain } from 'electron'
3434
import { Menu } from 'electron'
3535
import * as cdp from '@/main/browser-agent/cdp'
@@ -1015,7 +1015,7 @@ function raceAgainstWatchdog<T>(
10151015
*/
10161016
async function activeElementState(target: PageExecutionTarget): Promise<Record<string, unknown>> {
10171017
const state = await execInPage(target, readActiveElementState, []).catch(() => null)
1018-
return isRecordLike(state) ? state : {}
1018+
return toRecord(state)
10191019
}
10201020

10211021
function requireSnapshotForElementAction(): void {
@@ -1191,7 +1191,7 @@ async function pageActionState(
11911191
resetMutationRevision,
11921192
elementId,
11931193
]).catch(() => null)
1194-
return isRecordLike(state) ? state : {}
1194+
return toRecord(state)
11951195
}
11961196

11971197
function pageEffect(
@@ -2565,7 +2565,7 @@ async function executeToolInner(
25652565
},
25662566
}
25672567
return {
2568-
...(isRecordLike(fallback) ? fallback : {}),
2568+
...fallback,
25692569
trusted,
25702570
...state,
25712571
...combinedObservation,
@@ -2849,12 +2849,11 @@ async function executeToolInner(
28492849
await sleep(50)
28502850
const state = unwrapPageResult(await execInPage(target, readSelectElementState, [elementId]))
28512851
const effectObserved =
2852-
isRecordLike(selected) &&
28532852
isRecordLike(state) &&
28542853
selected.selected === state.selected &&
28552854
selected.value === state.value
28562855
return {
2857-
...(isRecordLike(selected) ? selected : {}),
2856+
...selected,
28582857
effectObserved,
28592858
readback: state,
28602859
...(!effectObserved
@@ -2994,7 +2993,7 @@ async function executeToolInner(
29942993
: {}),
29952994
}
29962995
return {
2997-
...(isRecordLike(result) ? result : {}),
2996+
...result,
29982997
trusted,
29992998
effect,
30002999
possibleEffectObserved,

apps/desktop/src/main/browser-import/browser-sources.ts

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -77,23 +77,6 @@ export function userDataDirFor(source: BrowserSource, home: string = homedir()):
7777
return join(home, ...source.userDataSegments)
7878
}
7979

80-
/**
81-
* Splits a bridge profile id back into its browser and profile directory.
82-
*
83-
* Ids are namespaced (`arc:Profile 1`) because profile directory names repeat
84-
* across browsers — every one of them has a `Default`. Returns null for
85-
* anything malformed; the caller then resolves against discovered profiles
86-
* anyway, so a bad id can never become a path.
87-
*/
88-
export function parseProfileId(profileId: string): { sourceId: string; directory: string } | null {
89-
const separator = profileId.indexOf(':')
90-
if (separator <= 0 || separator === profileId.length - 1) return null
91-
return {
92-
sourceId: profileId.slice(0, separator),
93-
directory: profileId.slice(separator + 1),
94-
}
95-
}
96-
9780
export function formatProfileId(sourceId: string, directory: string): string {
9881
return `${sourceId}:${directory}`
9982
}

apps/desktop/src/main/browser-import/chromium-profiles.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { constants } from 'node:fs'
22
import { access, lstat, readdir, readFile, realpath } from 'node:fs/promises'
33
import { homedir } from 'node:os'
44
import { join } from 'node:path'
5+
import { isRecordLike } from '@sim/utils/object'
56
import {
67
BROWSER_SOURCES,
78
type BrowserSource,
@@ -134,7 +135,7 @@ async function readProfileDisplayNames(userDataDir: string): Promise<Map<string,
134135
const raw = await readFile(join(userDataDir, 'Local State'), 'utf8')
135136
const infoCache = (JSON.parse(raw) as { profile?: { info_cache?: unknown } }).profile
136137
?.info_cache
137-
if (infoCache && typeof infoCache === 'object' && !Array.isArray(infoCache)) {
138+
if (isRecordLike(infoCache)) {
138139
for (const [dir, info] of Object.entries(infoCache as Record<string, unknown>)) {
139140
if (!PROFILE_DIR_PATTERN.test(dir)) continue
140141
const name = (info as { name?: unknown })?.name

apps/desktop/src/main/terminal/index.ts

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ import {
3232
type TerminalToolResponse,
3333
} from '@sim/terminal-protocol'
3434
import { sleep } from '@sim/utils/helpers'
35-
import { isRecordLike } from '@sim/utils/object'
3635
import type { BrowserWindow, WebContents } from 'electron'
3736
import {
3837
type FocusedResourceShortcut,
@@ -1201,8 +1200,3 @@ export class TerminalService {
12011200
function unknownTerminal(terminalId: string): string {
12021201
return `No terminal with id ${terminalId}. Call terminal_list for the open ones.`
12031202
}
1204-
1205-
/** Narrows an IPC payload to the tool-call shape without trusting the sender. */
1206-
export function parseToolParams(value: unknown): Record<string, unknown> {
1207-
return isRecordLike(value) ? value : {}
1208-
}

apps/docs/content/docs/en/integrations/logrocket.mdx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,4 +188,3 @@ Register a release version in LogRocket so uploaded source maps can decode stack
188188
| --------- | ---- | ----------- |
189189
| `version` | string | Release version that was registered |
190190

191-

0 commit comments

Comments
 (0)