Skip to content

Commit 6b9ecfb

Browse files
committed
Merge remote-tracking branch 'origin/staging' into feat/connector-service-account-auth
# Conflicts: # packages/db/migrations/meta/0322_snapshot.json # packages/db/migrations/meta/_journal.json
2 parents 6e07a0c + 7cfd00a commit 6b9ecfb

459 files changed

Lines changed: 56020 additions & 1948 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.

‎apps/desktop/src/main/browser-agent/session.test.ts‎

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4661,12 +4661,14 @@ describe('reopening a closed tab', () => {
46614661
})
46624662

46634663
describe('importAgentCookies', () => {
4664-
/** Points the mocked partition at a cookie jar and returns its `set` spy. */
4665-
function withCookieJar(set: ReturnType<typeof vi.fn>): SessionModule {
4664+
function withCookieJar(
4665+
set: ReturnType<typeof vi.fn>,
4666+
flushStore = vi.fn(async () => {})
4667+
): SessionModule {
46664668
// The partition is resolved per call, not captured at module load, so
46674669
// re-mocking it here is enough — no module reload required.
46684670
vi.mocked(electronSession.fromPartition).mockReturnValue({
4669-
cookies: { set },
4671+
cookies: { set, flushStore },
46704672
} as unknown as ReturnType<typeof electronSession.fromPartition>)
46714673
return sessionModule
46724674
}
@@ -4683,14 +4685,17 @@ describe('importAgentCookies', () => {
46834685

46844686
it('writes every cookie into the dedicated browser profile', async () => {
46854687
const set = vi.fn(async () => {})
4686-
const session = withCookieJar(set)
4688+
const flushStore = vi.fn(async () => {})
4689+
const session = withCookieJar(set, flushStore)
46874690

46884691
const result = await session.importAgentCookies([cookie('a'), cookie('b')])
46894692

46904693
expect(result).toEqual({ imported: 2, failed: 0 })
46914694
expect(electronSession.fromPartition).toHaveBeenCalledWith('persist:sim-browser-agent')
46924695
expect(set).toHaveBeenCalledTimes(2)
46934696
expect(set).toHaveBeenNthCalledWith(1, cookie('a'))
4697+
expect(flushStore).toHaveBeenCalledOnce()
4698+
expect(flushStore.mock.invocationCallOrder[0]).toBeGreaterThan(set.mock.invocationCallOrder[1])
46944699
})
46954700

46964701
it('counts a rejected cookie without losing the rest', async () => {
@@ -4709,9 +4714,22 @@ describe('importAgentCookies', () => {
47094714

47104715
it('does nothing when there is nothing to import', async () => {
47114716
const set = vi.fn(async () => {})
4712-
const session = withCookieJar(set)
4717+
const flushStore = vi.fn(async () => {})
4718+
const session = withCookieJar(set, flushStore)
47134719

47144720
await expect(session.importAgentCookies([])).resolves.toEqual({ imported: 0, failed: 0 })
47154721
expect(set).not.toHaveBeenCalled()
4722+
expect(flushStore).not.toHaveBeenCalled()
4723+
})
4724+
4725+
it('does not report a durable import when flushing to disk fails', async () => {
4726+
const session = withCookieJar(
4727+
vi.fn(async () => {}),
4728+
vi.fn(async () => {
4729+
throw new Error('Disk unavailable')
4730+
})
4731+
)
4732+
4733+
await expect(session.importAgentCookies([cookie('a')])).rejects.toThrow('Disk unavailable')
47164734
})
47174735
})

‎apps/desktop/src/main/browser-agent/session.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1196,6 +1196,7 @@ export async function importAgentCookies(
11961196
failed += 1
11971197
}
11981198
}
1199+
if (imported > 0) await jar.flushStore()
11991200
return { imported, failed }
12001201
}
12011202

‎apps/desktop/src/main/browser-credentials/vault.test.ts‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,25 @@ const CANDIDATES = [
3939
]
4040

4141
describe('CredentialVault', () => {
42+
it('retains imported logins when the vault is reopened and does not duplicate a re-import', async () => {
43+
const original = new CredentialVault(vaultPath, encryption())
44+
await original.importCredentials(CANDIDATES, 'replace')
45+
const metadata = await original.list()
46+
47+
const reopened = new CredentialVault(vaultPath, encryption())
48+
expect(await reopened.list()).toEqual(metadata)
49+
expect(await reopened.readForFill(metadata[0].id, metadata[0].origin)).toEqual({
50+
username: 'ada',
51+
password: 'hunter2',
52+
})
53+
expect(await reopened.importCredentials(CANDIDATES, 'replace')).toEqual({
54+
added: 0,
55+
updated: 0,
56+
skipped: 2,
57+
})
58+
expect(await reopened.list()).toEqual(metadata)
59+
})
60+
4261
it('stores and lists credentials without their passwords', async () => {
4362
const vault = new CredentialVault(vaultPath, encryption())
4463

‎apps/desktop/src/main/browser-import/import-service.test.ts‎

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -616,26 +616,33 @@ describe('importChromePasswords', () => {
616616
expect(importCredentials).toHaveBeenCalledWith([expect.any(Object)], 'replace')
617617
})
618618

619-
it('keeps credentials from one password store when the other is unreadable', async () => {
620-
const localPath = '/arc/Default/Login Data'
621-
const accountPath = '/arc/Default/Login Data For Account'
622-
const deps = createDeps({
623-
listProfiles: async () => [
624-
{ ...PROFILES[1], id: 'arc:Default', loginDataPaths: [localPath, accountPath] },
625-
],
626-
readPasswords: async (path) => {
627-
if (path === accountPath) {
628-
throw new ImportFailure('unsupported-schema', 'unknown account-store schema')
629-
}
630-
return readPasswords()
631-
},
632-
})
619+
it.each(['local', 'account'])(
620+
'reports a partial import when the %s password store is unreadable',
621+
async (failedStore) => {
622+
const localPath = '/arc/Default/Login Data'
623+
const accountPath = '/arc/Default/Login Data For Account'
624+
const deps = createDeps({
625+
listProfiles: async () => [
626+
{ ...PROFILES[1], id: 'arc:Default', loginDataPaths: [localPath, accountPath] },
627+
],
628+
readPasswords: async (path) => {
629+
if (path === (failedStore === 'local' ? localPath : accountPath)) {
630+
throw new ImportFailure('unsupported-schema', 'unknown account-store schema')
631+
}
632+
return readPasswords()
633+
},
634+
})
633635

634-
await expect(importChromePasswords('arc:Default', 'replace', deps)).resolves.toMatchObject({
635-
passwordsAdded: 1,
636-
passwordsSkipped: 0,
637-
})
638-
})
636+
await expect(importChromeData('arc:Default', 'replace', deps)).resolves.toMatchObject({
637+
cookies: { cookiesImported: 1 },
638+
passwords: {
639+
passwordsAdded: 1,
640+
passwordsSkipped: 0,
641+
error: 'unsupported-schema',
642+
},
643+
})
644+
}
645+
)
639646

640647
it('surfaces a failed password store when the other store only has unreadable rows', async () => {
641648
const localPath = '/arc/Default/Login Data'

‎apps/desktop/src/main/browser-import/import-service.ts‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,7 @@ async function runPasswordImport(
302302
passwordsAdded: outcome.added,
303303
passwordsUpdated: outcome.updated,
304304
passwordsSkipped: outcome.skipped + read.skipped,
305+
...(read.error ? { error: read.error } : {}),
305306
}
306307
logger.info('Chrome password import finished', {
307308
added: result.passwordsAdded,
@@ -321,14 +322,15 @@ async function runPasswordImport(
321322
* source order breaks ties deterministically before applying the vault policy.
322323
*
323324
* One damaged store does not discard credentials already read from the other.
325+
* A partial read carries its failure to the UI alongside the imported counts.
324326
* If no store can produce any useful signal, the first concrete reader error
325327
* is surfaced instead of reporting a misleading successful import of zero.
326328
*/
327329
async function readProfilePasswords(
328330
paths: readonly string[],
329331
key: Buffer,
330332
deps: ImportServiceDeps
331-
): Promise<ReadPasswordsResult> {
333+
): Promise<ReadPasswordsResult & { error?: BrowserPasswordImportResult['error'] }> {
332334
const combined: ReadPasswordsResult = { credentials: [], skipped: 0, rowsSeen: 0 }
333335
const credentialIndexes = new Map<string, number>()
334336
let successfulReads = 0
@@ -379,6 +381,7 @@ async function readProfilePasswords(
379381
if (firstFailure !== undefined) {
380382
// Category only: database names and paths are deliberately absent.
381383
logger.warn('Could not read every password store in the selected browser profile')
384+
return { ...combined, error: categorize(firstFailure, 'password') }
382385
}
383386
return combined
384387
}

‎apps/docs/components/icons.tsx‎

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2710,6 +2710,25 @@ export function BrexIcon(props: SVGProps<SVGSVGElement>) {
27102710
)
27112711
}
27122712

2713+
/**
2714+
* Official QuickBooks circular mark, cropped from the user-supplied
2715+
* Intuit_QuickBooks_logo.svg wordmark.
2716+
*/
2717+
export function QuickBooksIcon(props: SVGProps<SVGSVGElement>) {
2718+
return (
2719+
<svg {...props} viewBox='0 0 61.54 61.54' fill='none' xmlns='http://www.w3.org/2000/svg'>
2720+
<path
2721+
fill='#2CA01C'
2722+
d='M30.77 61.54c16.99 0 30.77-13.78 30.77-30.77S47.76 0 30.77 0 0 13.78 0 30.77s13.77 30.77 30.77 30.77Z'
2723+
/>
2724+
<path
2725+
fill='#FFF'
2726+
d='M20.51 18.8c-6.61 0-11.97 5.36-11.97 11.97s5.35 11.96 11.97 11.96h1.71v-4.44h-1.71c-4.15 0-7.52-3.37-7.52-7.52 0-4.15 3.37-7.52 7.52-7.52h4.11V46.5c0 2.45 1.99 4.44 4.44 4.44V18.8h-8.55Zm20.52 23.93c6.61 0 11.97-5.36 11.97-11.96S47.65 18.81 41.03 18.81h-1.71v4.44h1.71c4.15 0 7.52 3.37 7.52 7.52s-3.37 7.52-7.52 7.52h-4.11V15.04c0-2.45-1.99-4.44-4.44-4.44v32.13h8.55Z'
2727+
/>
2728+
</svg>
2729+
)
2730+
}
2731+
27132732
export function BrightDataIcon(props: SVGProps<SVGSVGElement>) {
27142733
return (
27152734
<svg
@@ -6845,6 +6864,32 @@ export function SecretsManagerIcon(props: SVGProps<SVGSVGElement>) {
68456864
)
68466865
}
68476866

6867+
export function SSMIcon(props: SVGProps<SVGSVGElement>) {
6868+
return (
6869+
<svg
6870+
{...props}
6871+
viewBox='5 5 70 70'
6872+
version='1.1'
6873+
xmlns='http://www.w3.org/2000/svg'
6874+
xmlnsXlink='http://www.w3.org/1999/xlink'
6875+
>
6876+
<g
6877+
id='Icon-Architecture/64/Arch_AWS-Systems-Manager_64'
6878+
stroke='none'
6879+
strokeWidth='1'
6880+
fill='none'
6881+
fillRule='evenodd'
6882+
>
6883+
<path
6884+
d='M47,54.998 L60,54.998 L60,56.998 L47,56.998 L47,58.999 L45,58.999 L45,56.998 L41,56.998 L41,54.998 L45,54.998 L45,53.998 L47,53.998 L47,54.998 Z M51,48.997 L60,48.997 L60,50.997 L51,50.997 L51,52.998 L49,52.998 L49,50.997 L41,50.997 L41,48.997 L49,48.997 L49,47.997 L51,47.997 L51,48.997 Z M56,42.996 L60,42.996 L60,44.997 L56,44.997 L56,46.997 L54,46.997 L54,44.997 L41,44.997 L41,42.996 L54,42.996 L54,41.996 L56,41.996 L56,42.996 Z M21,46.997 L30,46.997 L30,48.997 L21,48.997 C19.745,48.997 18.404,48.62 17.413,47.989 C15.393,46.71 12,43.715 12,38.042 C12,31.161 16.665,28.635 19.38,27.75 L19.326,26.834 C19.324,21.166 23.074,15.354 28.046,13.257 C33.869,10.781 40.036,12.008 44.545,16.537 C45.944,17.939 47.096,19.648 47.978,21.631 C49.749,20.156 52.16,19.651 54.4,20.386 C57.247,21.32 59.019,23.951 59.227,27.494 C62.065,28.173 68,30.508 68,38.132 C68,38.417 67.989,38.692 67.978,38.955 L65.979,38.902 C65.989,38.635 66,38.389 66,38.132 C66,31.398 60.443,29.706 58.054,29.292 C57.784,29.245 57.546,29.091 57.394,28.864 C57.243,28.639 57.19,28.363 57.246,28.098 C57.217,25.117 55.956,23.001 53.776,22.286 C51.823,21.643 49.677,22.352 48.434,24.044 C48.214,24.341 47.853,24.497 47.482,24.44 C47.116,24.387 46.81,24.135 46.686,23.786 C45.853,21.443 44.656,19.48 43.129,17.951 C39.216,14.019 33.867,12.955 28.826,15.099 C24.618,16.873 21.324,22.002 21.324,26.775 L21.423,28.429 C21.451,28.907 21.136,29.338 20.671,29.456 C18.18,30.09 14,32.049 14,38.042 C14,42.521 16.438,45.005 18.485,46.3 C19.16,46.731 20.123,46.997 21,46.997 L21,46.997 Z M66,52.318 L64.236,52.217 C63.763,52.192 63.312,52.518 63.204,52.996 C62.866,54.494 62.278,55.914 61.456,57.216 C61.195,57.63 61.271,58.172 61.637,58.498 L62.954,59.672 L59.673,62.954 L58.502,61.641 C58.176,61.274 57.633,61.2 57.222,61.461 C55.92,62.283 54.499,62.872 52.997,63.211 C52.521,63.319 52.191,63.756 52.22,64.244 L52.32,66 L47.68,66 L47.78,64.242 C47.809,63.754 47.479,63.317 47.003,63.209 C45.505,62.871 44.084,62.281 42.78,61.458 C42.367,61.196 41.825,61.271 41.5,61.638 L40.326,62.953 L37.046,59.672 L38.361,58.5 C38.726,58.174 38.802,57.632 38.541,57.219 C37.72,55.917 37.132,54.497 36.794,52.996 C36.687,52.518 36.209,52.192 35.762,52.217 L34,52.318 L34,47.677 L35.768,47.778 C36.233,47.804 36.691,47.477 36.8,47 C37.139,45.505 37.728,44.086 38.55,42.785 C38.811,42.371 38.734,41.829 38.37,41.504 L37.046,40.323 L40.327,37.041 L41.508,38.365 C41.834,38.729 42.376,38.804 42.787,38.544 C44.087,37.724 45.505,37.137 47.003,36.799 C47.479,36.691 47.809,36.254 47.78,35.766 L47.68,33.995 L52.32,33.995 L52.22,35.768 C52.191,36.256 52.521,36.692 52.997,36.8 C54.492,37.139 55.909,37.726 57.211,38.547 C57.622,38.808 58.165,38.732 58.49,38.368 L59.673,37.041 L62.954,40.323 L61.633,41.501 C61.269,41.827 61.192,42.368 61.453,42.782 C62.275,44.083 62.864,45.503 63.202,47 C63.31,47.476 63.763,47.804 64.234,47.778 L66,47.677 L66,52.318 Z M66.943,45.62 L64.942,45.734 C64.617,44.589 64.16,43.487 63.579,42.445 L65.076,41.11 C65.281,40.927 65.402,40.668 65.41,40.392 C65.418,40.118 65.312,39.851 65.117,39.657 L60.339,34.878 C60.145,34.683 59.868,34.571 59.604,34.586 C59.328,34.594 59.069,34.714 58.886,34.919 L57.546,36.421 C56.505,35.841 55.406,35.386 54.263,35.06 L54.377,33.052 C54.393,32.777 54.295,32.508 54.105,32.308 C53.917,32.108 53.654,31.995 53.379,31.995 L46.621,31.995 C46.346,31.995 46.083,32.108 45.895,32.308 C45.705,32.508 45.607,32.777 45.623,33.052 L45.737,35.058 C44.592,35.383 43.492,35.839 42.452,36.418 L41.114,34.919 C40.931,34.714 40.672,34.594 40.396,34.586 C40.113,34.573 39.855,34.683 39.661,34.878 L34.883,39.657 C34.688,39.851 34.582,40.118 34.59,40.392 C34.598,40.667 34.719,40.927 34.924,41.11 L36.424,42.448 C35.843,43.49 35.386,44.59 35.06,45.734 L33.057,45.62 C32.789,45.602 32.513,45.703 32.313,45.891 C32.113,46.08 32,46.343 32,46.618 L32,53.377 C32,53.652 32.113,53.915 32.313,54.104 C32.513,54.292 32.79,54.39 33.057,54.375 L35.053,54.261 C35.378,55.409 35.834,56.511 36.415,57.554 L34.924,58.884 C34.719,59.067 34.598,59.327 34.59,59.602 C34.582,59.877 34.688,60.144 34.883,60.338 L39.661,65.117 C39.855,65.312 40.138,65.419 40.396,65.41 C40.672,65.402 40.932,65.281 41.114,65.076 L42.444,63.583 C43.487,64.166 44.59,64.624 45.736,64.951 L45.623,66.943 C45.607,67.217 45.705,67.486 45.895,67.687 C46.083,67.887 46.346,68 46.621,68 L53.379,68 C53.654,68 53.917,67.887 54.106,67.687 C54.295,67.486 54.393,67.217 54.377,66.943 L54.264,64.953 C55.412,64.625 56.515,64.168 57.558,63.586 L58.886,65.076 C59.068,65.281 59.328,65.402 59.604,65.41 C59.871,65.422 60.145,65.312 60.339,65.117 L65.117,60.338 C65.312,60.144 65.418,59.877 65.41,59.602 C65.402,59.327 65.281,59.067 65.075,58.884 L63.582,57.552 C64.163,56.509 64.619,55.407 64.945,54.261 L66.943,54.375 C67.213,54.39 67.487,54.292 67.687,54.104 C67.887,53.915 68,53.652 68,53.377 L68,46.618 C68,46.343 67.887,46.08 67.687,45.891 C67.487,45.703 67.214,45.603 66.943,45.62 L66.943,45.62 Z'
6885+
id='AWS-Systems-Manager_Icon_64_Squid'
6886+
fill='currentColor'
6887+
/>
6888+
</g>
6889+
</svg>
6890+
)
6891+
}
6892+
68486893
export function SQSIcon(props: SVGProps<SVGSVGElement>) {
68496894
return (
68506895
<svg
@@ -6953,6 +6998,33 @@ export function AthenaIcon(props: SVGProps<SVGSVGElement>) {
69536998
)
69546999
}
69557000

7001+
export function CloudTrailIcon(props: SVGProps<SVGSVGElement>) {
7002+
return (
7003+
<svg
7004+
{...props}
7005+
viewBox='5 5 70.002 70.002'
7006+
version='1.1'
7007+
xmlns='http://www.w3.org/2000/svg'
7008+
xmlnsXlink='http://www.w3.org/1999/xlink'
7009+
>
7010+
<g
7011+
id='Icon-Architecture/64/Arch_AWS-Cloud-Trail_64'
7012+
stroke='none'
7013+
strokeWidth='1'
7014+
fill='none'
7015+
fillRule='evenodd'
7016+
transform='translate(40, 40) scale(1.25) translate(-40, -40)'
7017+
>
7018+
<path
7019+
d='M25,52.996 L29,52.996 L29,50.994 L25,50.994 L25,52.996 Z M59.971,38.163 C59.746,35.126 58.261,32.89 55.902,32.1 C54.003,31.467 51.911,31.914 50.318,33.213 C49.352,31.308 47.9,29.442 46.702,28.26 C42.406,24.019 37.668,22.938 32.616,25.045 C28.106,26.922 24,33.087 24,37.981 L24,38.171 C21.293,39.086 19.109,41.074 18.074,43.609 L19.926,44.366 C21.245,41.135 24.332,40.122 25.247,39.889 C25.69,39.776 26,39.377 26,38.919 L26,37.981 C26,33.936 29.657,28.445 33.385,26.893 C37.68,25.103 41.578,26.011 45.298,29.685 C46.88,31.246 48.427,33.561 49.06,35.318 C49.184,35.664 49.488,35.913 49.852,35.968 C50.212,36.023 50.577,35.874 50.799,35.58 C51.904,34.11 53.696,33.474 55.269,33.999 C57.004,34.581 58,36.397 58,38.982 C58,39.472 58.354,39.889 58.836,39.969 C59.569,40.091 66,41.352 66,47.991 C66,54.868 59.281,54.996 59,54.998 L36,54.998 L36,57 L59.002,57 C62.114,56.994 68,55.104 68,47.991 C68,41.784 63.279,38.989 59.971,38.163 L59.971,38.163 Z M31,52.996 L45,52.996 L45,50.994 L31,50.994 L31,52.996 Z M27,57 L33,57 L33,54.998 L27,54.998 L27,57 Z M12,57 L15,57 L15,54.998 L12,54.998 L12,57 Z M15,48.992 L24,48.992 L24,46.99 L15,46.99 L15,48.992 Z M13,52.996 L23,52.996 L23,50.994 L13,50.994 L13,52.996 Z M27,48.992 L34,48.992 L34,46.99 L27,46.99 L27,48.992 Z M17,57 L25,57 L25,54.998 L17,54.998 L17,57 Z'
7020+
id='AWS-Cloud-Trail_Icon_64_Squid'
7021+
fill='currentColor'
7022+
/>
7023+
</g>
7024+
</svg>
7025+
)
7026+
}
7027+
69567028
export function CloudWatchIcon(props: SVGProps<SVGSVGElement>) {
69577029
return (
69587030
<svg

‎apps/docs/components/ui/icon-mapping.ts‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ import {
4444
ClickUpIcon,
4545
CloudFormationIcon,
4646
CloudflareIcon,
47+
CloudTrailIcon,
4748
CloudWatchIcon,
4849
CodePipelineIcon,
4950
ConfluenceIcon,
@@ -194,6 +195,7 @@ import {
194195
PulseIcon,
195196
QdrantIcon,
196197
QuartrIcon,
198+
QuickBooksIcon,
197199
QuiverIcon,
198200
RabbitmqIcon,
199201
RailwayIcon,
@@ -234,6 +236,7 @@ import {
234236
SportmonksIcon,
235237
SQSIcon,
236238
SquareIcon,
239+
SSMIcon,
237240
SshIcon,
238241
STSIcon,
239242
STTIcon,
@@ -317,6 +320,7 @@ export const blockTypeToIconMap: Record<string, IconComponent> = {
317320
clickup: ClickUpIcon,
318321
cloudflare: CloudflareIcon,
319322
cloudformation: CloudFormationIcon,
323+
cloudtrail: CloudTrailIcon,
320324
cloudwatch: CloudWatchIcon,
321325
codepipeline: CodePipelineIcon,
322326
confluence: ConfluenceIcon,
@@ -500,6 +504,7 @@ export const blockTypeToIconMap: Record<string, IconComponent> = {
500504
pulse_v2: PulseIcon,
501505
qdrant: QdrantIcon,
502506
quartr: QuartrIcon,
507+
quickbooks: QuickBooksIcon,
503508
quiver: QuiverIcon,
504509
rabbitmq: RabbitmqIcon,
505510
railway: RailwayIcon,
@@ -546,6 +551,7 @@ export const blockTypeToIconMap: Record<string, IconComponent> = {
546551
sqs: SQSIcon,
547552
square: SquareIcon,
548553
ssh: SshIcon,
554+
ssm: SSMIcon,
549555
stagehand: StagehandIcon,
550556
stripe: StripeIcon,
551557
sts: STSIcon,

0 commit comments

Comments
 (0)