@applitools/core 4.61.0 → 4.61.1-debug.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@applitools/core",
3
- "version": "4.61.0",
3
+ "version": "4.61.1-debug.0",
4
4
  "homepage": "https://applitools.com",
5
5
  "bugs": {
6
6
  "url": "https://github.com/applitools/eyes.sdk.javascript1/issues"
@@ -56,20 +56,21 @@
56
56
  "test:it": "MOCHA_GROUP=it run --top-level mocha './test/it/**/*.spec.ts' --require ./test/mocha-global-setup.js",
57
57
  "test:e2e:sync": "MOCHA_GROUP=e2e SYNC=true run --top-level mocha './test/e2e/mocha-sync/**/*.spec.ts' --exit --require ./test/mocha-global-setup.js",
58
58
  "test:unit": "MOCHA_GROUP=unit run --top-level mocha './test/unit/**/*.spec.ts' --require ./test/mocha-global-setup.js",
59
- "setup": "run --top-level browsers:setup && run --top-level xvfb:setup",
59
+ "setup": "run --top-level browsers:setup && run --top-level xvfb:setup && run playwright:setup",
60
+ "playwright:setup": "node -e \"var v=parseInt(process.version.slice(1));if(v>=18){require('child_process').execSync('yarn playwright install --with-deps firefox',{stdio:'inherit'})}else{console.log('Skipping playwright install (Node '+process.version+')')}\"",
60
61
  "setup:standalone": "sh -c 'yarn chromedriver --port=4444 --verbose &'"
61
62
  },
62
63
  "dependencies": {
63
64
  "@applitools/core-base": "1.33.0",
64
- "@applitools/dom-capture": "11.7.1",
65
- "@applitools/dom-snapshot": "4.16.4",
66
- "@applitools/driver": "1.25.5",
67
- "@applitools/ec-client": "1.12.26",
65
+ "@applitools/dom-capture": "11.8.0",
66
+ "@applitools/dom-snapshot": "4.17.0",
67
+ "@applitools/driver": "1.26.0",
68
+ "@applitools/ec-client": "1.12.28",
68
69
  "@applitools/logger": "2.2.11",
69
- "@applitools/nml-client": "1.11.25",
70
+ "@applitools/nml-client": "1.11.26",
70
71
  "@applitools/req": "1.10.0",
71
- "@applitools/screenshoter": "3.12.18",
72
- "@applitools/snippets": "2.8.2",
72
+ "@applitools/screenshoter": "3.12.19",
73
+ "@applitools/snippets": "2.9.0",
73
74
  "@applitools/socket": "1.3.12",
74
75
  "@applitools/ufg-client": "1.22.0",
75
76
  "@applitools/utils": "1.14.4",
@@ -81,11 +82,12 @@
81
82
  },
82
83
  "devDependencies": {
83
84
  "@applitools/bongo": "^5.10.0",
84
- "@applitools/spec-driver-puppeteer": "^1.7.5",
85
- "@applitools/spec-driver-selenium": "^1.7.16",
85
+ "@applitools/spec-driver-playwright": "^1.9.0",
86
+ "@applitools/spec-driver-puppeteer": "^1.8.0",
87
+ "@applitools/spec-driver-selenium": "^1.8.0",
86
88
  "@applitools/test-server": "^1.4.3",
87
89
  "@applitools/test-utils": "^1.5.17",
88
- "@applitools/tunnel-client": "^1.11.11",
90
+ "@applitools/tunnel-client": "^1.11.12",
89
91
  "@types/mocha": "^10.0.7",
90
92
  "@types/node": "^12.20.55",
91
93
  "@types/selenium-webdriver": "^4.1.2",
@@ -93,6 +95,7 @@
93
95
  "chromedriver": "^131.0.5",
94
96
  "crypto": "^1.0.1",
95
97
  "nock": "^13.3.2",
98
+ "playwright": "1.47.0",
96
99
  "png-async": "^0.9.4",
97
100
  "puppeteer": "^24.11.1",
98
101
  "selenium-webdriver": "^4.15.0"
@@ -179,4 +179,5 @@ export type TestResult = BaseCore.TestResult & {
179
179
  export type OpenSettings = BaseCore.OpenSettings & {
180
180
  disableBrokerUrlCache?: boolean;
181
181
  environments?: Environment[];
182
+ bypassCSP?: boolean;
182
183
  };
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
@@ -0,0 +1,9 @@
1
+ /// <reference types="node" />
2
+ import { type Options } from './core-server';
3
+ import { type ForkOptions } from 'child_process';
4
+ export declare function makeCoreServerProcess(options: Options & {
5
+ forkOptions?: ForkOptions;
6
+ }): Promise<{
7
+ port: number;
8
+ close: () => void;
9
+ }>;
@@ -0,0 +1,18 @@
1
+ import { type ServerOptions } from './ws-server';
2
+ import { type Logger } from '@applitools/logger';
3
+ export type Options = ServerOptions & {
4
+ environment?: Record<string, any>;
5
+ agentIdPrefix?: string;
6
+ debug?: boolean;
7
+ shutdownMode?: 'lazy' | 'stdin';
8
+ idleTimeout?: number;
9
+ printStdout?: boolean;
10
+ isProcess?: boolean;
11
+ maskLog?: boolean;
12
+ logger?: Logger;
13
+ };
14
+ export declare function makeCoreServer({ environment: defaultEnvironment, agentIdPrefix, debug, shutdownMode, idleTimeout, // 15min
15
+ printStdout, isProcess, maskLog, logger, ...handlerOptions }?: Options): Promise<{
16
+ port: number;
17
+ close?: () => void;
18
+ }>;
@@ -0,0 +1,2 @@
1
+ import { type Socket } from '@applitools/socket';
2
+ export declare function withHistory<TSocket extends Socket>(socket: TSocket): () => Record<string, any>;
@@ -0,0 +1,8 @@
1
+ import type { Ref } from './types';
2
+ export interface Refer {
3
+ isRef<TValue = any>(ref: any): ref is Ref<TValue>;
4
+ ref<TValue>(value: TValue, parentRef?: Ref<unknown>): Ref<TValue>;
5
+ deref<TValue>(ref: Ref<TValue>): TValue;
6
+ destroy(ref: Ref<any>): void;
7
+ }
8
+ export declare function makeRefer(): Refer;
@@ -0,0 +1,15 @@
1
+ import type { Ref, ServerSocket, UniversalSpecDriver } from './types';
2
+ import type { SpecType, SpecDriver as BaseSpecDriver, CommonSelector } from '@applitools/driver';
3
+ export type Driver = Ref;
4
+ export type Context = Ref;
5
+ export type Element = Ref;
6
+ export type Selector = string | CommonSelector | Ref;
7
+ export type UserFunction = Ref;
8
+ export type PrimarySpecType = SpecType<Driver, Context, Element, Selector, never, UserFunction>;
9
+ export type SpecDriver = BaseSpecDriver<PrimarySpecType>;
10
+ type CommandName = keyof UniversalSpecDriver<PrimarySpecType>;
11
+ export declare function makeSpec({ socket, spec, }: {
12
+ socket: ServerSocket<PrimarySpecType, any>;
13
+ spec: CommandName[];
14
+ }): SpecDriver;
15
+ export {};
@@ -0,0 +1,205 @@
1
+ import type { Size, Region } from '@applitools/utils';
2
+ import type { Emitter, Listener, Client, Server } from '@applitools/socket';
3
+ import type { SpecType, DriverInfo, Cookie, WaitOptions } from '@applitools/driver';
4
+ import type * as MainCore from '../types';
5
+ /**
6
+ * Wraps the type with a ref if it vas to be refed
7
+ */
8
+ type Refify<TValue> = TValue extends string | number | boolean | null | undefined ? TValue : TValue extends Array<infer TItem> ? Refify<TItem>[] : Extract<TValue[keyof TValue], (...args: any) => any> extends never ? TValue : Ref<TValue>;
9
+ /**
10
+ * Creates universalized object out of an ordinary interface:
11
+ * - Filters out properties that are not of async function type
12
+ * - Adds domain to the method names (`Domain.methodName`)
13
+ * - Keep only first (`options`) argument of the methods
14
+ * - Introduces additional option to the methods with a ref of the current instance
15
+ * - Refifies return values of the methods
16
+ */
17
+ type Universalize<TTarget extends Record<string, any>, TDomain extends string, TRefKey extends string = never> = {
18
+ [TKey in keyof TTarget as NonNullable<TTarget[TKey]> extends (...args: any[]) => Promise<any> ? `${TDomain}.${TKey & string}` : never]: NonNullable<TTarget[TKey]> extends (options: infer TOptions) => Promise<infer TResult> ? (options: TOptions & {
19
+ [TKey in TRefKey]: Ref<TTarget>;
20
+ }) => Promise<Refify<TResult>> : never;
21
+ };
22
+ export type Ref<TValue = never> = {
23
+ 'applitools-ref-id': string;
24
+ type?: string;
25
+ };
26
+ export type ClientSocket<TSpec extends SpecType, TType extends 'classic' | 'ufg'> = unknown & Emitter<Universalize<UniversalCore<TSpec, TType>, 'Core'>> & Client<Universalize<MainCore.Core<TSpec, TType>, 'Core'>> & Client<Universalize<MainCore.EyesManager<TSpec, TType>, 'EyesManager', 'manager'>> & Client<Universalize<MainCore.Eyes<TSpec, TType>, 'Eyes', 'eyes'>> & Client<Universalize<UniversalDebug<TSpec>, 'Debug'>> & Server<Universalize<UniversalSpecDriver<TSpec>, 'Driver'>>;
27
+ export type ServerSocket<TSpec extends SpecType, TType extends 'classic' | 'ufg'> = unknown & Listener<Universalize<UniversalCore<TSpec, TType>, 'Core'>> & Emitter<Universalize<UniversalLogger, 'Logger'>> & Server<Universalize<MainCore.Core<TSpec, TType>, 'Core'>> & Server<Universalize<MainCore.EyesManager<TSpec, TType>, 'EyesManager', 'manager'>> & Server<Universalize<MainCore.Eyes<TSpec, TType>, 'Eyes', 'eyes'>> & Server<Universalize<UniversalDebug<TSpec>, 'Debug'>> & Client<Universalize<UniversalSpecDriver<TSpec>, 'Driver'>>;
28
+ export interface UniversalCore<TSpec extends SpecType, TType extends 'classic' | 'ufg'> {
29
+ makeCore(options: {
30
+ spec: 'webdriver' | (keyof UniversalSpecDriver<TSpec>)[];
31
+ agentId: string;
32
+ environment?: Record<string, any>;
33
+ cwd: string;
34
+ }): Promise<MainCore.Core<TSpec, TType>>;
35
+ }
36
+ export interface UniversalLogger {
37
+ log(options: {
38
+ level: string;
39
+ message: string;
40
+ }): Promise<void>;
41
+ }
42
+ export interface UniversalDebug<TSpec extends SpecType> {
43
+ getHistory(): Promise<any>;
44
+ checkSpecDriver(options: {
45
+ driver: TSpec['driver'];
46
+ commands: (keyof UniversalSpecDriver<TSpec>)[];
47
+ }): Promise<any>;
48
+ }
49
+ /**
50
+ * Ideally would be transform SpecDriver type to the type with single object argument
51
+ * but typescript doesn't have a possibility to convert named tuples to object types at the moment
52
+ */
53
+ export interface UniversalSpecDriver<T extends SpecType> {
54
+ isEqualElements(options: {
55
+ context: T['context'];
56
+ element1: T['element'];
57
+ element2: T['element'];
58
+ }): Promise<boolean>;
59
+ executeScript(options: {
60
+ context: T['context'];
61
+ script: string;
62
+ arg?: any;
63
+ }): Promise<any>;
64
+ findElement(options: {
65
+ context: T['context'];
66
+ selector: T['selector'];
67
+ parent?: T['element'];
68
+ }): Promise<T['element'] | null>;
69
+ findElements(options: {
70
+ context: T['context'];
71
+ selector: T['selector'];
72
+ parent?: T['element'];
73
+ }): Promise<T['element'][]>;
74
+ waitForSelector(options: {
75
+ context: T['context'];
76
+ selector: T['selector'];
77
+ parent?: T['element'];
78
+ options?: WaitOptions;
79
+ }): Promise<T['element'] | null>;
80
+ getElementRegion(options: {
81
+ context: T['context'];
82
+ element: T['element'];
83
+ }): Promise<Region>;
84
+ getElementAttribute(options: {
85
+ context: T['context'];
86
+ element: T['element'];
87
+ attr: string;
88
+ }): Promise<string>;
89
+ setElementText(options: {
90
+ context: T['context'];
91
+ element: T['element'];
92
+ text: string;
93
+ }): Promise<void>;
94
+ getElementText(options: {
95
+ context: T['context'];
96
+ element: T['element'];
97
+ }): Promise<string>;
98
+ hover(options: {
99
+ context: T['context'];
100
+ element: T['element'];
101
+ }): Promise<void>;
102
+ click(options: {
103
+ context: T['context'];
104
+ element: T['element'];
105
+ }): Promise<void>;
106
+ mainContext(options: {
107
+ context: T['context'];
108
+ }): Promise<T['context']>;
109
+ parentContext(options: {
110
+ context: T['context'];
111
+ }): Promise<T['context']>;
112
+ childContext(options: {
113
+ context: T['context'];
114
+ element: T['element'];
115
+ }): Promise<T['context']>;
116
+ getDriverInfo(options: {
117
+ driver: T['driver'];
118
+ }): Promise<DriverInfo>;
119
+ getCapabilities(options: {
120
+ driver: T['driver'];
121
+ }): Promise<Record<string, any>>;
122
+ setWindowSize(options: {
123
+ driver: T['driver'];
124
+ size: Size;
125
+ }): Promise<void>;
126
+ getWindowSize(options: {
127
+ driver: T['driver'];
128
+ }): Promise<Size>;
129
+ setViewportSize(options: {
130
+ driver: T['driver'];
131
+ size: Size;
132
+ }): Promise<void>;
133
+ getViewportSize(options: {
134
+ driver: T['driver'];
135
+ }): Promise<Size>;
136
+ getSystemBars(options: {
137
+ driver: T['driver'];
138
+ }): Promise<{
139
+ statusBar: {
140
+ visible: boolean;
141
+ x: number;
142
+ y: number;
143
+ height: number;
144
+ width: number;
145
+ };
146
+ navigationBar: {
147
+ visible: boolean;
148
+ x: number;
149
+ y: number;
150
+ height: number;
151
+ width: number;
152
+ };
153
+ }>;
154
+ getOrientation(options: {
155
+ driver: T['driver'];
156
+ }): Promise<'portrait' | 'landscape' | 'portrait-secondary' | 'landscape-secondary'>;
157
+ setOrientation(options: {
158
+ driver: T['driver'];
159
+ orientation: 'portrait' | 'landscape' | 'portrait-secondary' | 'landscape-secondary';
160
+ }): Promise<void>;
161
+ getCookies(options: {
162
+ driver: T['driver'] | T['context'];
163
+ context?: boolean;
164
+ }): Promise<Cookie[]>;
165
+ getTitle(options: {
166
+ driver: T['driver'];
167
+ }): Promise<string>;
168
+ getUrl(options: {
169
+ driver: T['driver'];
170
+ }): Promise<string>;
171
+ takeScreenshot(options: {
172
+ driver: T['driver'];
173
+ }): Promise<string>;
174
+ performAction(options: {
175
+ driver: T['driver'];
176
+ steps: any[];
177
+ }): Promise<void>;
178
+ visit(options: {
179
+ driver: T['driver'];
180
+ url: string;
181
+ }): Promise<void>;
182
+ getCurrentWorld(options: {
183
+ driver: T['driver'];
184
+ }): Promise<string>;
185
+ getWorlds(options: {
186
+ driver: T['driver'];
187
+ }): Promise<string[]>;
188
+ switchWorld(options: {
189
+ driver: T['driver'];
190
+ name: string;
191
+ }): Promise<void>;
192
+ reload(options: {
193
+ driver: T['driver'];
194
+ }): Promise<void>;
195
+ isUserFunction(ref: any): Promise<boolean>;
196
+ executeUserFunction(userFunction: Ref): Promise<any>;
197
+ executeBrowserCommands(options: {
198
+ driver?: T['driver'];
199
+ commands: any[];
200
+ }): Promise<any>;
201
+ bringToFront(options: {
202
+ driver: T['driver'];
203
+ }): Promise<void>;
204
+ }
205
+ export {};
@@ -0,0 +1,15 @@
1
+ /// <reference types="node" />
2
+ import { Server as WsServer } from 'ws';
3
+ import { Logger } from '@applitools/logger';
4
+ export type ServerOptions = {
5
+ port?: number;
6
+ singleton?: boolean;
7
+ portResolutionMode?: 'next' | 'random' | 'lazy';
8
+ debug?: boolean;
9
+ key?: string | Buffer;
10
+ cert?: string | Buffer;
11
+ };
12
+ export declare function makeServer(options: ServerOptions | undefined, logger: Logger): Promise<{
13
+ server?: WsServer;
14
+ port: number;
15
+ }>;
@@ -30,6 +30,81 @@ export declare const getPrimaryRemoteName: (({ execOptions, logger }: {
30
30
  clearCache(): void;
31
31
  TTL?: number | undefined;
32
32
  };
33
+ export type GitEnvironmentResult = {
34
+ /** `git` binary is on PATH and executable. */
35
+ gitInstalled: boolean;
36
+ /** Current working directory is inside a git work tree. */
37
+ insideRepo: boolean;
38
+ /** A primary remote is configured AND reachable. */
39
+ remoteAccessible: boolean;
40
+ /**
41
+ * `gitInstalled && insideRepo` — sufficient for local-only git operations
42
+ * (commit lookups, local branch detection, local merge-base). Does NOT
43
+ * imply remote ops will succeed — callers that need the remote must
44
+ * additionally check `remoteAccessible`.
45
+ */
46
+ ok: boolean;
47
+ /** Human-readable explanation covering every sub-check; used in skip-logs. */
48
+ reason: string;
49
+ /** Resolved primary remote name, when one is configured. */
50
+ remoteName?: string;
51
+ };
52
+ /**
53
+ * One-shot, cached probe of the full git environment, staged from cheapest
54
+ * to most expensive:
55
+ * 1. is `git` installed and on PATH? (`git --version`)
56
+ * 2. are we inside a git work tree? (`git rev-parse --is-inside-work-tree`)
57
+ * 3. is a primary remote configured? (`git remote`)
58
+ * 4. is that remote reachable? (`git ls-remote <r> HEAD`)
59
+ *
60
+ * Use this as the outermost guard for any code path that shells out to git.
61
+ * Each step short-circuits later ones: missing binary skips repo/remote
62
+ * checks; non-repo skips remote checks; no remote configured skips the
63
+ * reachability probe. Callers should consult `ok` for local-only git
64
+ * features and `remoteAccessible` for anything that talks to the network.
65
+ *
66
+ * Cached per `cwd`. The first invocation emits a clearly-visible banner so
67
+ * support can grep one distinctive line — `APPLITOOLS GIT ENVIRONMENT CHECK`
68
+ * — and immediately tell which sub-check failed. Subsequent invocations
69
+ * return the cached verdict silently.
70
+ */
71
+ export declare const checkGitEnvironment: (({ execOptions, logger, }: {
72
+ execOptions?: ExecOptions | undefined;
73
+ logger?: Logger | undefined;
74
+ }) => Promise<GitEnvironmentResult>) & {
75
+ getCachedValues(): Promise<GitEnvironmentResult>[];
76
+ setCachedValue(key: any, value: Promise<GitEnvironmentResult>): void;
77
+ clearCache(): void;
78
+ TTL?: number | undefined;
79
+ };
80
+ /**
81
+ * Programmatically detect the default branch of the current repository.
82
+ *
83
+ * Fallback chain (each step short-circuits on success; never throws):
84
+ * 1. `APPLITOOLS_DEFAULT_BRANCH` env var — explicit user override.
85
+ * 2. `git symbolic-ref --short refs/remotes/<remote>/HEAD` — authoritative
86
+ * source on any clone that has fetched at least once. Returns e.g.
87
+ * `origin/master`; the `<remote>/` prefix is stripped.
88
+ * 3. `git ls-remote --symref <remote> HEAD` — works even when the local
89
+ * `refs/remotes/<remote>/HEAD` symref was never set up (single-branch
90
+ * clones, older git on CI).
91
+ * 4. `git config --get init.defaultBranch` — honors a user-global preference
92
+ * if everything else fails.
93
+ * 5. Literal `'main'` — last resort.
94
+ *
95
+ * Steps 2 and 3 catch non-standard defaults (e.g. JFrog's
96
+ * `JFROG/artifactory-mfe/preRelease/jfmfe-1.995.x-rc`). Cached per `cwd`
97
+ * to match `getPrimaryRemoteName`.
98
+ */
99
+ export declare const extractDefaultBranch: (({ execOptions, logger }: {
100
+ execOptions?: ExecOptions | undefined;
101
+ logger?: Logger | undefined;
102
+ }) => Promise<string>) & {
103
+ getCachedValues(): Promise<string>[];
104
+ setCachedValue(key: any, value: Promise<string>): void;
105
+ clearCache(): void;
106
+ TTL?: number | undefined;
107
+ };
33
108
  export declare const extractLatestCommitInfo: (({ execOptions, logger, }: ExtractCurrentCommitTimestampOptions) => Promise<{
34
109
  timestamp: string;
35
110
  sha: string;
@@ -68,6 +143,31 @@ export declare const extractGitRepo: (({ execOptions, logger }: Options) => Prom
68
143
  };
69
144
  export declare function extractCIBranchName(): string | undefined;
70
145
  export declare function extractBuildIdFromCI(): Promise<string | undefined>;
146
+ /**
147
+ * Extract the ISO-8601 timestamp at which `branchName` branched off from
148
+ * `parentBranchName`.
149
+ *
150
+ * Algorithm (each step short-circuits on success; returns `undefined` on
151
+ * total failure — never throws):
152
+ * 1. If the repo is a shallow clone, unshallow (or treeless-fetch) so the
153
+ * branch topology is visible to `git merge-base`.
154
+ * 2. `git merge-base <remote>/<branch> <remote>/<parent>` — CI typically
155
+ * operates on remote refs only, so try those first.
156
+ * 3. Fall back to local refs (`git merge-base <branch> <parent>`).
157
+ * 4. If still no merge-base, see if the parent exists on the remote and,
158
+ * if so, fetch it by name (`--filter=tree:0`) and retry. If the parent
159
+ * isn't on the remote at all, give up — we can't compute a branching
160
+ * point for a branch that doesn't exist anywhere.
161
+ * 5. Direct-ancestor refinement: if the merge-base equals the parent
162
+ * branch's tip, the parent hasn't diverged from `branchName` yet
163
+ * (parent is a strict ancestor). The "branching point" is then the
164
+ * parent commit of the first child-only commit — not the merge-base
165
+ * itself, which would be the parent's tip and produce a too-recent
166
+ * timestamp.
167
+ * 6. Resolve the final hash's committer-date via `git show -s --format=%aI`.
168
+ *
169
+ * Cached per (branchName, parentBranchName, cwd).
170
+ */
71
171
  export declare const extractBranchingTimestamp: (({ branchName, parentBranchName, execOptions, logger, }: ExtractGitBranchingTimestampOptions) => Promise<string | undefined>) & {
72
172
  getCachedValues(): Promise<string | undefined>[];
73
173
  setCachedValue(key: any, value: Promise<string | undefined>): void;
@@ -75,16 +175,56 @@ export declare const extractBranchingTimestamp: (({ branchName, parentBranchName
75
175
  TTL?: number | undefined;
76
176
  };
77
177
  export declare function isISODate(str: string): boolean;
178
+ type BranchAncestryOptions = {
179
+ gitBranchName: string;
180
+ defaultBranch: string;
181
+ execOptions?: ExecOptions;
182
+ logger?: Logger;
183
+ };
184
+ /**
185
+ * Enumerate ancestor branches in the window MERGE_BASE..gitBranchName by
186
+ * walking the commits in that window and asking which branches contain each.
187
+ *
188
+ * Mirrors the reference shell algorithm in
189
+ * `.team-lead/scripts-byCommits.sh`. Returns a sorted, deduplicated list
190
+ * of branch names (no `refs/` prefix). Never throws — returns `[]` on git
191
+ * failure. Always includes `defaultBranch` and `gitBranchName`.
192
+ */
193
+ export declare function getBranchAncestryByCommits({ gitBranchName, defaultBranch, execOptions, logger, }: BranchAncestryOptions): Promise<string[]>;
194
+ /**
195
+ * Enumerate ancestor branches by iterating every branch ref and applying
196
+ * Rule 1 (the candidate's merge-base with HEAD must not lie before the
197
+ * primary MERGE_BASE) and Rule 2 (HEAD must not be an ancestor of the
198
+ * candidate).
199
+ *
200
+ * Mirrors the reference shell algorithm in
201
+ * `.team-lead/scripts-byLocalBranches.sh`, with one deliberate extension:
202
+ * the shell script reads `refs/heads/` only, but in CI we typically have
203
+ * exactly one local branch checked out and dozens of remote refs. To make
204
+ * this method useful in CI we ALSO walk `refs/remotes/<remote>/` and strip
205
+ * the remote prefix. The function name is preserved for fidelity to the
206
+ * reference algorithm.
207
+ *
208
+ * Returns a sorted, deduplicated list of branch names. Never throws —
209
+ * returns `[]` on git failure. Always includes `defaultBranch` and
210
+ * `gitBranchName`.
211
+ */
212
+ export declare function getBranchAncestryByLocalBranches({ gitBranchName, defaultBranch, execOptions, logger, }: BranchAncestryOptions): Promise<string[]>;
78
213
  /**
79
214
  * Extracts a list of ancestor branches for the given branch, ordered by most recent commit timestamp.
80
215
  *
81
216
  * Algorithm:
82
- * 1. Check if shallow clone and should skip (via APPLITOOLS_SKIP_BRANCH_LOOKUP_IN_SHALLOW_CLONE)
83
- * 2. Ensure remote branches are available (fetch if needed for single-branch/shallow clones)
84
- * 3. Use git topology to discover ancestor branches efficiently (O(log N) via --first-parent --simplify-by-decoration)
85
- * 4. For each discovered branch, extract the branching timestamp (latest viable commit where branch existed)
86
- * 5. Sort results by timestamp descending (most recent first)
87
- * 6. Return cached results (5-minute TTL) to avoid redundant git operations
217
+ * 1. Check if shallow clone and should skip (via APPLITOOLS_SKIP_BRANCH_LOOKUP_IN_SHALLOW_CLONE).
218
+ * 2. Ensure remote branches are available (fetch if needed for single-branch/shallow clones).
219
+ * 3. Detect the repo's actual default branch via `extractDefaultBranch()` (handles non-standard
220
+ * defaults like JFrog's `JFROG/.../...-rc`).
221
+ * 4. Discover ancestor branches using the strategy selected by
222
+ * `APPLITOOLS_BRANCH_ANCESTRY_STRATEGY` (`commits` (default) or `local`):
223
+ * - `getBranchAncestryByCommits` walks the MERGE_BASE..HEAD commit window;
224
+ * - `getBranchAncestryByLocalBranches` iterates `refs/heads/` + `refs/remotes/<remote>/`.
225
+ * 5. For each discovered branch, extract the branching timestamp.
226
+ * 6. Sort results by timestamp descending (most recent first), tie-break by branch name.
227
+ * 7. Root-branch safety net: if nothing survived, fall back to the detected default branch.
88
228
  *
89
229
  * @param gitBranchName - The branch to analyze
90
230
  * @param execOptions - Git execution options (e.g., cwd)