teamshare-bridge 0.26.25 → 0.27.1
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/dist/cli/commands/build.js +48 -22
- package/dist/cli/commands/build.js.map +1 -1
- package/dist/cli/commands/plan.js +40 -2
- package/dist/cli/commands/plan.js.map +1 -1
- package/dist/cli/commands/planner.js +3 -1
- package/dist/cli/commands/planner.js.map +1 -1
- package/dist/cli/commands/research.js +68 -4
- package/dist/cli/commands/research.js.map +1 -1
- package/dist/cli/commands/run.js +54 -3
- package/dist/cli/commands/run.js.map +1 -1
- package/dist/cli/commands/worker.js +52 -59
- package/dist/cli/commands/worker.js.map +1 -1
- package/dist/cli/commands/workflow.js +36 -2
- package/dist/cli/commands/workflow.js.map +1 -1
- package/dist/lib/api-content.d.ts +38 -0
- package/dist/lib/api-content.js +14 -0
- package/dist/lib/api-content.js.map +1 -1
- package/dist/lib/api.d.ts +4 -0
- package/dist/lib/api.js.map +1 -1
- package/dist/lib/brief.d.ts +12 -0
- package/dist/lib/brief.js +10 -7
- package/dist/lib/brief.js.map +1 -1
- package/dist/lib/browser/batch.d.ts +5 -0
- package/dist/lib/browser/batch.js +29 -0
- package/dist/lib/browser/batch.js.map +1 -1
- package/dist/lib/browser/challenge.d.ts +85 -0
- package/dist/lib/browser/challenge.js +164 -0
- package/dist/lib/browser/challenge.js.map +1 -0
- package/dist/lib/browser/launch.d.ts +9 -0
- package/dist/lib/browser/launch.js +11 -9
- package/dist/lib/browser/launch.js.map +1 -1
- package/dist/lib/browser/session.d.ts +50 -1
- package/dist/lib/browser/session.js +162 -2
- package/dist/lib/browser/session.js.map +1 -1
- package/dist/lib/browser/stealth.d.ts +20 -0
- package/dist/lib/browser/stealth.js +86 -0
- package/dist/lib/browser/stealth.js.map +1 -0
- package/dist/lib/git/git-finalize.d.ts +2 -0
- package/dist/lib/git/git-finalize.js +32 -5
- package/dist/lib/git/git-finalize.js.map +1 -1
- package/dist/lib/git/git-pipeline.d.ts +3 -2
- package/dist/lib/git/git-pipeline.js.map +1 -1
- package/dist/lib/git/git-presence.js +1 -1
- package/dist/lib/git/git-presence.js.map +1 -1
- package/dist/lib/git/index.d.ts +2 -2
- package/dist/lib/git/index.js +4 -1
- package/dist/lib/git/index.js.map +1 -1
- package/dist/lib/git/pr-token.d.ts +74 -16
- package/dist/lib/git/pr-token.js +160 -16
- package/dist/lib/git/pr-token.js.map +1 -1
- package/dist/lib/orchestrator/handlers/browser.js +92 -3
- package/dist/lib/orchestrator/handlers/browser.js.map +1 -1
- package/dist/lib/run-report.d.ts +38 -11
- package/dist/lib/run-report.js +137 -88
- package/dist/lib/run-report.js.map +1 -1
- package/dist/lib/tools/docx-source.d.ts +6 -4
- package/dist/lib/tools/docx-source.js +27 -4
- package/dist/lib/tools/docx-source.js.map +1 -1
- package/dist/lib/tools/pptx-deck.d.ts +90 -0
- package/dist/lib/tools/pptx-deck.js +1302 -147
- package/dist/lib/tools/pptx-deck.js.map +1 -1
- package/package.json +1 -1
- package/skills/teamshare-cdd/SKILL.md +219 -215
package/dist/lib/git/index.d.ts
CHANGED
|
@@ -7,6 +7,6 @@ export { formatLocalGitState } from './stash-context';
|
|
|
7
7
|
export { detectIndexBlocker, recoverBlockedIndex, preflightRecoverIndexes, postIndexRecoveryComment, blockedRecordFor, markBlockedIndexRepo, isBlockedIndexRepo, clearBlockedIndexRepo, clearAllBlockedIndexRepos, } from './index-recovery';
|
|
8
8
|
export type { IndexBlocker, IndexBlockerKind, IndexRecoveryApi, IndexRecoveryRecord, } from './index-recovery';
|
|
9
9
|
export { createPullRequest, isGitHubUrl } from './pr-create';
|
|
10
|
-
export { resolvePrToken, backendRunToken, ghAuthToken } from './pr-token';
|
|
11
|
-
export type { ResolvedPrToken, PrTokenSource } from './pr-token';
|
|
10
|
+
export { resolvePrToken, backendRunToken, ghAuthToken, credentialFillToken, looksLikeGitHubToken, prRefusalLine, } from './pr-token';
|
|
11
|
+
export type { ResolvedPrToken, PrTokenSource, PrTokenRefusal, BackendRunTokenOpts, ResolvePrTokenOpts, ResolvePrTokenResult, } from './pr-token';
|
|
12
12
|
export { slugifySegment } from './slug';
|
package/dist/lib/git/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.slugifySegment = exports.ghAuthToken = exports.backendRunToken = exports.resolvePrToken = exports.isGitHubUrl = exports.createPullRequest = exports.clearAllBlockedIndexRepos = exports.clearBlockedIndexRepo = exports.isBlockedIndexRepo = exports.markBlockedIndexRepo = exports.blockedRecordFor = exports.postIndexRecoveryComment = exports.preflightRecoverIndexes = exports.recoverBlockedIndex = exports.detectIndexBlocker = exports.formatLocalGitState = exports.restoreStash = exports.listStashes = exports.checkOrphanedStashes = exports.formatStashSummary = exports.resolveGitPolicy = exports.commitRemainingChanges = exports.finalizeRunGit = exports.prepareRunGitAsync = exports.prepareRunGit = exports.snapshotGit = exports.ensureRepo = exports.originUrlFor = exports.urlKey = exports.rememberGitToken = exports.tokenForUrl = exports.authArgsForRepo = exports.authArgsForUrl = void 0;
|
|
3
|
+
exports.slugifySegment = exports.prRefusalLine = exports.looksLikeGitHubToken = exports.credentialFillToken = exports.ghAuthToken = exports.backendRunToken = exports.resolvePrToken = exports.isGitHubUrl = exports.createPullRequest = exports.clearAllBlockedIndexRepos = exports.clearBlockedIndexRepo = exports.isBlockedIndexRepo = exports.markBlockedIndexRepo = exports.blockedRecordFor = exports.postIndexRecoveryComment = exports.preflightRecoverIndexes = exports.recoverBlockedIndex = exports.detectIndexBlocker = exports.formatLocalGitState = exports.restoreStash = exports.listStashes = exports.checkOrphanedStashes = exports.formatStashSummary = exports.resolveGitPolicy = exports.commitRemainingChanges = exports.finalizeRunGit = exports.prepareRunGitAsync = exports.prepareRunGit = exports.snapshotGit = exports.ensureRepo = exports.originUrlFor = exports.urlKey = exports.rememberGitToken = exports.tokenForUrl = exports.authArgsForRepo = exports.authArgsForUrl = void 0;
|
|
4
4
|
var git_auth_1 = require("./git-auth");
|
|
5
5
|
Object.defineProperty(exports, "authArgsForUrl", { enumerable: true, get: function () { return git_auth_1.authArgsForUrl; } });
|
|
6
6
|
Object.defineProperty(exports, "authArgsForRepo", { enumerable: true, get: function () { return git_auth_1.authArgsForRepo; } });
|
|
@@ -41,6 +41,9 @@ var pr_token_1 = require("./pr-token");
|
|
|
41
41
|
Object.defineProperty(exports, "resolvePrToken", { enumerable: true, get: function () { return pr_token_1.resolvePrToken; } });
|
|
42
42
|
Object.defineProperty(exports, "backendRunToken", { enumerable: true, get: function () { return pr_token_1.backendRunToken; } });
|
|
43
43
|
Object.defineProperty(exports, "ghAuthToken", { enumerable: true, get: function () { return pr_token_1.ghAuthToken; } });
|
|
44
|
+
Object.defineProperty(exports, "credentialFillToken", { enumerable: true, get: function () { return pr_token_1.credentialFillToken; } });
|
|
45
|
+
Object.defineProperty(exports, "looksLikeGitHubToken", { enumerable: true, get: function () { return pr_token_1.looksLikeGitHubToken; } });
|
|
46
|
+
Object.defineProperty(exports, "prRefusalLine", { enumerable: true, get: function () { return pr_token_1.prRefusalLine; } });
|
|
44
47
|
var slug_1 = require("./slug");
|
|
45
48
|
Object.defineProperty(exports, "slugifySegment", { enumerable: true, get: function () { return slug_1.slugifySegment; } });
|
|
46
49
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/lib/git/index.ts"],"names":[],"mappings":";;;AAAA,uCAOoB;AANlB,0GAAA,cAAc,OAAA;AACd,2GAAA,eAAe,OAAA;AACf,uGAAA,WAAW,OAAA;AACX,4GAAA,gBAAgB,OAAA;AAChB,kGAAA,MAAM,OAAA;AACN,wGAAA,YAAY,OAAA;AAEd,uCAAqD;AAA5C,sGAAA,UAAU,OAAA;AAAE,uGAAA,WAAW,OAAA;AAChC,+CAMwB;AALtB,6GAAA,aAAa,OAAA;AACb,kHAAA,kBAAkB,OAAA;AAClB,8GAAA,cAAc,OAAA;AACd,sHAAA,sBAAsB,OAAA;AACtB,gHAAA,gBAAgB,OAAA;AAElB,2CAKsB;AAJpB,gHAAA,kBAAkB,OAAA;AAClB,kHAAA,oBAAoB,OAAA;AACpB,yGAAA,WAAW,OAAA;AACX,0GAAA,YAAY,OAAA;AAGd,iDAAsD;AAA7C,oHAAA,mBAAmB,OAAA;AAC5B,mDAU0B;AATxB,oHAAA,kBAAkB,OAAA;AAClB,qHAAA,mBAAmB,OAAA;AACnB,yHAAA,uBAAuB,OAAA;AACvB,0HAAA,wBAAwB,OAAA;AACxB,kHAAA,gBAAgB,OAAA;AAChB,sHAAA,oBAAoB,OAAA;AACpB,oHAAA,kBAAkB,OAAA;AAClB,uHAAA,qBAAqB,OAAA;AACrB,2HAAA,yBAAyB,OAAA;AAQ3B,yCAA6D;AAApD,8GAAA,iBAAiB,OAAA;AAAE,wGAAA,WAAW,OAAA;AACvC,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/lib/git/index.ts"],"names":[],"mappings":";;;AAAA,uCAOoB;AANlB,0GAAA,cAAc,OAAA;AACd,2GAAA,eAAe,OAAA;AACf,uGAAA,WAAW,OAAA;AACX,4GAAA,gBAAgB,OAAA;AAChB,kGAAA,MAAM,OAAA;AACN,wGAAA,YAAY,OAAA;AAEd,uCAAqD;AAA5C,sGAAA,UAAU,OAAA;AAAE,uGAAA,WAAW,OAAA;AAChC,+CAMwB;AALtB,6GAAA,aAAa,OAAA;AACb,kHAAA,kBAAkB,OAAA;AAClB,8GAAA,cAAc,OAAA;AACd,sHAAA,sBAAsB,OAAA;AACtB,gHAAA,gBAAgB,OAAA;AAElB,2CAKsB;AAJpB,gHAAA,kBAAkB,OAAA;AAClB,kHAAA,oBAAoB,OAAA;AACpB,yGAAA,WAAW,OAAA;AACX,0GAAA,YAAY,OAAA;AAGd,iDAAsD;AAA7C,oHAAA,mBAAmB,OAAA;AAC5B,mDAU0B;AATxB,oHAAA,kBAAkB,OAAA;AAClB,qHAAA,mBAAmB,OAAA;AACnB,yHAAA,uBAAuB,OAAA;AACvB,0HAAA,wBAAwB,OAAA;AACxB,kHAAA,gBAAgB,OAAA;AAChB,sHAAA,oBAAoB,OAAA;AACpB,oHAAA,kBAAkB,OAAA;AAClB,uHAAA,qBAAqB,OAAA;AACrB,2HAAA,yBAAyB,OAAA;AAQ3B,yCAA6D;AAApD,8GAAA,iBAAiB,OAAA;AAAE,wGAAA,WAAW,OAAA;AACvC,uCAOoB;AANlB,0GAAA,cAAc,OAAA;AACd,2GAAA,eAAe,OAAA;AACf,uGAAA,WAAW,OAAA;AACX,+GAAA,mBAAmB,OAAA;AACnB,gHAAA,oBAAoB,OAAA;AACpB,yGAAA,aAAa,OAAA;AAUf,+BAAwC;AAA/B,sGAAA,cAAc,OAAA"}
|
|
@@ -1,29 +1,87 @@
|
|
|
1
|
-
export type PrTokenSource = 'project' | 'env' | 'gh-cli' | 'github_app';
|
|
1
|
+
export type PrTokenSource = 'project' | 'env' | 'gh-cli' | 'github_app' | 'credential-helper';
|
|
2
2
|
export interface ResolvedPrToken {
|
|
3
3
|
token: string;
|
|
4
4
|
source: PrTokenSource;
|
|
5
|
+
/**
|
|
6
|
+
* Set only on a credential-helper rescue: the backend refused first with
|
|
7
|
+
* this code (e.g. REPO_NOT_INSTALLED) and the helper supplied a token
|
|
8
|
+
* anyway. Lets the caller log WHY the fallback was used without ever
|
|
9
|
+
* seeing the token.
|
|
10
|
+
*/
|
|
11
|
+
note?: string;
|
|
5
12
|
}
|
|
6
|
-
/**
|
|
7
|
-
export
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
export
|
|
13
|
+
/** A typed backend refusal: the UPPER_SNAKE code names the fix. */
|
|
14
|
+
export interface PrTokenRefusal {
|
|
15
|
+
error: {
|
|
16
|
+
code: string;
|
|
17
|
+
message: string;
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
export interface BackendRunTokenOpts {
|
|
14
21
|
remoteUrl: string;
|
|
15
22
|
projectId?: string | null;
|
|
16
23
|
apiKey?: string | null;
|
|
17
24
|
apiBaseUrl?: string | null;
|
|
18
|
-
|
|
25
|
+
/** Passed in the POST body when present (lets the hub audit per task). */
|
|
26
|
+
taskId?: string | null;
|
|
27
|
+
}
|
|
28
|
+
/** Best-effort ambient GitHub CLI token (null when gh is absent/logged-out). */
|
|
29
|
+
export declare function ghAuthToken(): string | null;
|
|
30
|
+
/**
|
|
31
|
+
* GitHub-shaped token check for the credential-helper rescue.
|
|
32
|
+
*
|
|
33
|
+
* Some helpers answer `git credential fill` with a username or some other
|
|
34
|
+
* non-token secret; pushing with that burns the attempt on a 401 and the
|
|
35
|
+
* report then blames the wrong thing. So on a github.com host ONLY a
|
|
36
|
+
* GitHub token shape is accepted (classic `ghp_*` family + fine-grained
|
|
37
|
+
* `github_pat_*` + the legacy 40-hex PAT). Non-GitHub forges (Gitea accepts
|
|
38
|
+
* any non-empty password) take whatever the helper stored.
|
|
39
|
+
*/
|
|
40
|
+
export declare function looksLikeGitHubToken(value: string): boolean;
|
|
41
|
+
/**
|
|
42
|
+
* Best-effort machine credential (step 5). Runs `git credential fill` for the
|
|
43
|
+
* remote's host and returns the filled password when it is usable. Returns
|
|
44
|
+
* null on every failure — absent git, timeout, non-zero exit, empty password,
|
|
45
|
+
* or a non-token-shaped secret on a github.com host. Never throws, never
|
|
46
|
+
* logs the secret (callers log only the source name).
|
|
47
|
+
*
|
|
48
|
+
* NOTE on where the password can come from: `fill` consults the configured
|
|
49
|
+
* helpers AND, when they miss, the prompt fallback (`GIT_ASKPASS` /
|
|
50
|
+
* `core.askPass`) — on a VS Code-integrated shell that fallback silently
|
|
51
|
+
* returns the editor's stored GitHub session. That is ordinary `fill`
|
|
52
|
+
* semantics and a session token is a fine credential (same trust boundary as
|
|
53
|
+
* manager-core), so it is accepted, not scrubbed. `GIT_TERMINAL_PROMPT=0`
|
|
54
|
+
* keeps a truly-interactive prompt from hanging the run past the timeout.
|
|
55
|
+
*/
|
|
56
|
+
export declare function credentialFillToken(remoteUrl: string): ResolvedPrToken | null;
|
|
57
|
+
/**
|
|
58
|
+
* Ask the hub for a one-shot token for this run (step 4).
|
|
59
|
+
*
|
|
60
|
+
* Returns null ONLY when there is no run identity (no project, no key) — a
|
|
61
|
+
* normal "not connected" state, never an error. Every answered request
|
|
62
|
+
* resolves to either a token or a TYPED refusal carrying the backend's
|
|
63
|
+
* UPPER_SNAKE code and message (truncated to 300 chars); a request that never
|
|
64
|
+
* got an answer (network/timeout) is `RUN_TOKEN_UNREACHABLE`. Callers must
|
|
65
|
+
* NOT treat a typed refusal as "try nothing else" — see `resolvePrToken`.
|
|
66
|
+
*/
|
|
67
|
+
export declare function backendRunToken(opts: BackendRunTokenOpts): Promise<ResolvedPrToken | PrTokenRefusal | null>;
|
|
68
|
+
export type ResolvePrTokenOpts = BackendRunTokenOpts;
|
|
69
|
+
export type ResolvePrTokenResult = ResolvedPrToken | PrTokenRefusal | null;
|
|
19
70
|
/**
|
|
20
71
|
* Full precedence chain. Pure except for the env/process reads and the
|
|
21
72
|
* optional backend call — `gh` and the network are only touched when every
|
|
22
73
|
* earlier step missed, so the common PAT/env path stays side-effect free.
|
|
74
|
+
*
|
|
75
|
+
* The backend leg NEVER short-circuits to a refusal: a typed error is
|
|
76
|
+
* remembered, the credential helper is still tried (it may hold a fine PAT
|
|
77
|
+
* while the App installation is merely missing the repo), and a helper hit
|
|
78
|
+
* carries the backend code in `note` so the caller can log why the fallback
|
|
79
|
+
* was used. Only when the helper also misses is the typed error surfaced.
|
|
23
80
|
*/
|
|
24
|
-
export declare function resolvePrToken(opts:
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
81
|
+
export declare function resolvePrToken(opts: ResolvePrTokenOpts): Promise<ResolvePrTokenResult>;
|
|
82
|
+
/**
|
|
83
|
+
* User-facing PR refusal for a typed run-token error. Every branch ends with
|
|
84
|
+
* "The branch IS pushed" — the push already succeeded, so the refusal is
|
|
85
|
+
* never a data-loss scare, only a next step.
|
|
86
|
+
*/
|
|
87
|
+
export declare function prRefusalLine(code: string, message: string): string;
|
package/dist/lib/git/pr-token.js
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ghAuthToken = ghAuthToken;
|
|
4
|
+
exports.looksLikeGitHubToken = looksLikeGitHubToken;
|
|
5
|
+
exports.credentialFillToken = credentialFillToken;
|
|
4
6
|
exports.backendRunToken = backendRunToken;
|
|
5
7
|
exports.resolvePrToken = resolvePrToken;
|
|
8
|
+
exports.prRefusalLine = prRefusalLine;
|
|
6
9
|
/**
|
|
7
10
|
* PR/push token resolution for the task-run git pipeline (2026-10).
|
|
8
11
|
*
|
|
@@ -18,11 +21,22 @@ exports.resolvePrToken = resolvePrToken;
|
|
|
18
21
|
* 2. `GITHUB_TOKEN` / `GITEA_TOKEN` env — ambient machine credential;
|
|
19
22
|
* 3. `gh auth token` — ambient GitHub CLI credential (best-effort);
|
|
20
23
|
* 4. the backend run-token endpoint — the run caller's own App connection,
|
|
21
|
-
* verified against the exact repo before it is handed out
|
|
24
|
+
* verified against the exact repo before it is handed out;
|
|
25
|
+
* 5. `git credential fill` — the OS / manager-core credential helper
|
|
26
|
+
* (best-effort rescue when the backend refuses but the machine holds
|
|
27
|
+
* a usable credential of its own).
|
|
28
|
+
*
|
|
29
|
+
* A backend REPO_NOT_INSTALLED must NOT block the credential-helper rescue:
|
|
30
|
+
* the helper may hold a fine PAT while the App installation is merely
|
|
31
|
+
* missing the repo. So a typed backend refusal is REMEMBERED, the helper is
|
|
32
|
+
* still tried, and only when the helper also misses is the typed error
|
|
33
|
+
* surfaced (with a message that names the fix). Env/gh-cli/file hits still
|
|
34
|
+
* win immediately as today.
|
|
22
35
|
*
|
|
23
36
|
* An installation token is MEMORY-ONLY: it expires in ~1h, is repo-scoped,
|
|
24
37
|
* and must never be written to `git-tokens.json` (that file is for durable
|
|
25
|
-
* PATs). Callers use the returned token transiently and drop it.
|
|
38
|
+
* PATs). Callers use the returned token transiently and drop it. The helper
|
|
39
|
+
* password is likewise memory-only — only the source name is ever logged.
|
|
26
40
|
*/
|
|
27
41
|
const node_child_process_1 = require("node:child_process");
|
|
28
42
|
const shims_1 = require("../workspace/shims");
|
|
@@ -54,38 +68,137 @@ function ghAuthToken() {
|
|
|
54
68
|
}
|
|
55
69
|
}
|
|
56
70
|
/**
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
71
|
+
* GitHub-shaped token check for the credential-helper rescue.
|
|
72
|
+
*
|
|
73
|
+
* Some helpers answer `git credential fill` with a username or some other
|
|
74
|
+
* non-token secret; pushing with that burns the attempt on a 401 and the
|
|
75
|
+
* report then blames the wrong thing. So on a github.com host ONLY a
|
|
76
|
+
* GitHub token shape is accepted (classic `ghp_*` family + fine-grained
|
|
77
|
+
* `github_pat_*` + the legacy 40-hex PAT). Non-GitHub forges (Gitea accepts
|
|
78
|
+
* any non-empty password) take whatever the helper stored.
|
|
79
|
+
*/
|
|
80
|
+
function looksLikeGitHubToken(value) {
|
|
81
|
+
const s = value.trim();
|
|
82
|
+
if (/^(ghp_|gho_|ghu_|ghs_|github_pat_)/.test(s))
|
|
83
|
+
return true;
|
|
84
|
+
if (/^[0-9a-f]{40}$/i.test(s))
|
|
85
|
+
return true;
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Best-effort machine credential (step 5). Runs `git credential fill` for the
|
|
90
|
+
* remote's host and returns the filled password when it is usable. Returns
|
|
91
|
+
* null on every failure — absent git, timeout, non-zero exit, empty password,
|
|
92
|
+
* or a non-token-shaped secret on a github.com host. Never throws, never
|
|
93
|
+
* logs the secret (callers log only the source name).
|
|
94
|
+
*
|
|
95
|
+
* NOTE on where the password can come from: `fill` consults the configured
|
|
96
|
+
* helpers AND, when they miss, the prompt fallback (`GIT_ASKPASS` /
|
|
97
|
+
* `core.askPass`) — on a VS Code-integrated shell that fallback silently
|
|
98
|
+
* returns the editor's stored GitHub session. That is ordinary `fill`
|
|
99
|
+
* semantics and a session token is a fine credential (same trust boundary as
|
|
100
|
+
* manager-core), so it is accepted, not scrubbed. `GIT_TERMINAL_PROMPT=0`
|
|
101
|
+
* keeps a truly-interactive prompt from hanging the run past the timeout.
|
|
102
|
+
*/
|
|
103
|
+
function credentialFillToken(remoteUrl) {
|
|
104
|
+
let host = '';
|
|
105
|
+
try {
|
|
106
|
+
host = new URL(remoteUrl).host.toLowerCase();
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
if (!host)
|
|
112
|
+
return null;
|
|
113
|
+
const github = host === 'github.com' || host.endsWith('.github.com');
|
|
114
|
+
let res;
|
|
115
|
+
try {
|
|
116
|
+
res = (0, node_child_process_1.spawnSync)('git', ['credential', 'fill'], {
|
|
117
|
+
input: `protocol=https\nhost=${host}\n\n`,
|
|
118
|
+
encoding: 'utf-8',
|
|
119
|
+
timeout: 10_000,
|
|
120
|
+
windowsHide: true,
|
|
121
|
+
env: { ...(0, shims_1.envWithoutShims)(), GIT_TERMINAL_PROMPT: '0' },
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
return null;
|
|
126
|
+
}
|
|
127
|
+
if (res.error || res.status !== 0)
|
|
128
|
+
return null;
|
|
129
|
+
const password = String(res.stdout ?? '')
|
|
130
|
+
.split(/\r?\n/)
|
|
131
|
+
.map((line) => line.trim())
|
|
132
|
+
.find((line) => line.startsWith('password='))
|
|
133
|
+
?.slice('password='.length)
|
|
134
|
+
.trim() ?? '';
|
|
135
|
+
if (!password)
|
|
136
|
+
return null;
|
|
137
|
+
if (github && !looksLikeGitHubToken(password))
|
|
138
|
+
return null;
|
|
139
|
+
return { token: password, source: 'credential-helper' };
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Ask the hub for a one-shot token for this run (step 4).
|
|
143
|
+
*
|
|
144
|
+
* Returns null ONLY when there is no run identity (no project, no key) — a
|
|
145
|
+
* normal "not connected" state, never an error. Every answered request
|
|
146
|
+
* resolves to either a token or a TYPED refusal carrying the backend's
|
|
147
|
+
* UPPER_SNAKE code and message (truncated to 300 chars); a request that never
|
|
148
|
+
* got an answer (network/timeout) is `RUN_TOKEN_UNREACHABLE`. Callers must
|
|
149
|
+
* NOT treat a typed refusal as "try nothing else" — see `resolvePrToken`.
|
|
60
150
|
*/
|
|
61
151
|
async function backendRunToken(opts) {
|
|
62
|
-
const { remoteUrl, projectId, apiKey, apiBaseUrl } = opts;
|
|
152
|
+
const { remoteUrl, projectId, apiKey, apiBaseUrl, taskId } = opts;
|
|
63
153
|
if (!remoteUrl || !projectId || !apiKey)
|
|
64
154
|
return null;
|
|
155
|
+
const body = { projectId, repoUrl: remoteUrl };
|
|
156
|
+
if (taskId)
|
|
157
|
+
body.taskId = taskId;
|
|
158
|
+
let res;
|
|
65
159
|
try {
|
|
66
|
-
|
|
160
|
+
res = await fetch(`${(apiBaseUrl ?? DEFAULT_API_BASE_URL).replace(/\/+$/, '')}/git-connections/run-token`, {
|
|
67
161
|
method: 'POST',
|
|
68
162
|
headers: {
|
|
69
163
|
'Content-Type': 'application/json',
|
|
70
164
|
'X-Api-Key': apiKey,
|
|
71
165
|
},
|
|
72
|
-
body: JSON.stringify(
|
|
166
|
+
body: JSON.stringify(body),
|
|
73
167
|
signal: AbortSignal.timeout(15_000),
|
|
74
168
|
});
|
|
75
|
-
const raw = (await res.json().catch(() => null));
|
|
76
|
-
const token = raw?.data?.token;
|
|
77
|
-
if (!res.ok || raw?.success !== true || !token)
|
|
78
|
-
return null;
|
|
79
|
-
return { token, source: 'github_app' };
|
|
80
169
|
}
|
|
81
|
-
catch {
|
|
82
|
-
|
|
170
|
+
catch (err) {
|
|
171
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
172
|
+
return {
|
|
173
|
+
error: {
|
|
174
|
+
code: 'RUN_TOKEN_UNREACHABLE',
|
|
175
|
+
message: `run-token request failed (${reason})`.slice(0, 300),
|
|
176
|
+
},
|
|
177
|
+
};
|
|
83
178
|
}
|
|
179
|
+
const raw = (await res.json().catch(() => null));
|
|
180
|
+
const token = raw?.data?.token;
|
|
181
|
+
if (res.ok && raw?.success === true && token) {
|
|
182
|
+
return { token, source: 'github_app' };
|
|
183
|
+
}
|
|
184
|
+
const code = typeof raw?.error?.code === 'string' && raw.error.code
|
|
185
|
+
? raw.error.code
|
|
186
|
+
: 'GITHUB_APP_MINT_FAILED';
|
|
187
|
+
const message = (typeof raw?.error?.message === 'string' && raw.error.message
|
|
188
|
+
? raw.error.message
|
|
189
|
+
: `run-token request failed (HTTP ${res.status})`).slice(0, 300);
|
|
190
|
+
return { error: { code, message } };
|
|
84
191
|
}
|
|
85
192
|
/**
|
|
86
193
|
* Full precedence chain. Pure except for the env/process reads and the
|
|
87
194
|
* optional backend call — `gh` and the network are only touched when every
|
|
88
195
|
* earlier step missed, so the common PAT/env path stays side-effect free.
|
|
196
|
+
*
|
|
197
|
+
* The backend leg NEVER short-circuits to a refusal: a typed error is
|
|
198
|
+
* remembered, the credential helper is still tried (it may hold a fine PAT
|
|
199
|
+
* while the App installation is merely missing the repo), and a helper hit
|
|
200
|
+
* carries the backend code in `note` so the caller can log why the fallback
|
|
201
|
+
* was used. Only when the helper also misses is the typed error surfaced.
|
|
89
202
|
*/
|
|
90
203
|
async function resolvePrToken(opts) {
|
|
91
204
|
const local = (0, git_auth_1.tokenForUrl)(opts.remoteUrl);
|
|
@@ -97,6 +210,37 @@ async function resolvePrToken(opts) {
|
|
|
97
210
|
const cli = ghAuthToken();
|
|
98
211
|
if (cli)
|
|
99
212
|
return { token: cli, source: 'gh-cli' };
|
|
100
|
-
|
|
213
|
+
const backend = await backendRunToken(opts);
|
|
214
|
+
if (backend && 'token' in backend)
|
|
215
|
+
return backend;
|
|
216
|
+
const remembered = backend && 'error' in backend ? backend.error : null;
|
|
217
|
+
const helper = credentialFillToken(opts.remoteUrl);
|
|
218
|
+
if (helper) {
|
|
219
|
+
return remembered
|
|
220
|
+
? { ...helper, note: `backend ${remembered.code}` }
|
|
221
|
+
: helper;
|
|
222
|
+
}
|
|
223
|
+
if (remembered)
|
|
224
|
+
return { error: remembered };
|
|
225
|
+
return null;
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* User-facing PR refusal for a typed run-token error. Every branch ends with
|
|
229
|
+
* "The branch IS pushed" — the push already succeeded, so the refusal is
|
|
230
|
+
* never a data-loss scare, only a next step.
|
|
231
|
+
*/
|
|
232
|
+
function prRefusalLine(code, message) {
|
|
233
|
+
switch (code) {
|
|
234
|
+
case 'REPO_NOT_INSTALLED':
|
|
235
|
+
return 'PR: not opened — the GitHub installation does not include owner/repo. Add it under Settings → Connected accounts → Manage repositories (company: ask an admin to share or install), then re-run. The branch IS pushed.';
|
|
236
|
+
case 'GITHUB_APP_NOT_CONNECTED':
|
|
237
|
+
return 'PR: not opened — no GitHub installation is linked for this project (tried company + personal fallbacks). Link GitHub in Settings → Connected accounts, share it with the company, or add a project PAT; then re-run. The branch IS pushed.';
|
|
238
|
+
case 'GITHUB_APP_NOT_CONFIGURED':
|
|
239
|
+
case 'GITHUB_APP_MINT_FAILED':
|
|
240
|
+
case 'RUN_TOKEN_UNREACHABLE':
|
|
241
|
+
return `PR: not opened — ${message} (server-side; not something linking can fix). The branch IS pushed.`;
|
|
242
|
+
default:
|
|
243
|
+
return `PR: not opened — ${code}: ${message}. The branch IS pushed.`;
|
|
244
|
+
}
|
|
101
245
|
}
|
|
102
246
|
//# sourceMappingURL=pr-token.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pr-token.js","sourceRoot":"","sources":["../../../src/lib/git/pr-token.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"pr-token.js","sourceRoot":"","sources":["../../../src/lib/git/pr-token.ts"],"names":[],"mappings":";;AA6EA,kCAcC;AAYD,oDAKC;AAiBD,kDAgCC;AAYD,0CAiDC;AAiBD,wCAoBC;AAOD,sCAaC;AAnRD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,2DAA6D;AAC7D,8CAAqD;AACrD,yCAAyC;AAEzC;;;;;;;GAOG;AACH,MAAM,oBAAoB,GACxB,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,+BAA+B,CAAC;AA+BnE,gFAAgF;AAChF,SAAgB,WAAW;IACzB,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAA,iCAAY,EAAC,IAAI,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE;YAChD,QAAQ,EAAE,OAAO;YACjB,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC;YACnC,WAAW,EAAE,IAAI;YACjB,GAAG,EAAE,IAAA,uBAAe,GAAE;YACtB,OAAO,EAAE,MAAM;SAChB,CAAC,CAAC;QACH,MAAM,KAAK,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;QACzB,OAAO,KAAK,IAAI,IAAI,CAAC;IACvB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;;;;;;;GASG;AACH,SAAgB,oBAAoB,CAAC,KAAa;IAChD,MAAM,CAAC,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IACvB,IAAI,oCAAoC,CAAC,IAAI,CAAC,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IAC9D,IAAI,iBAAiB,CAAC,IAAI,CAAC,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IAC3C,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,SAAgB,mBAAmB,CAAC,SAAiB;IACnD,IAAI,IAAI,GAAG,EAAE,CAAC;IACd,IAAI,CAAC;QACH,IAAI,GAAG,IAAI,GAAG,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;IAC/C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IACvB,MAAM,MAAM,GAAG,IAAI,KAAK,YAAY,IAAI,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC;IACrE,IAAI,GAAiC,CAAC;IACtC,IAAI,CAAC;QACH,GAAG,GAAG,IAAA,8BAAS,EAAC,KAAK,EAAE,CAAC,YAAY,EAAE,MAAM,CAAC,EAAE;YAC7C,KAAK,EAAE,wBAAwB,IAAI,MAAM;YACzC,QAAQ,EAAE,OAAO;YACjB,OAAO,EAAE,MAAM;YACf,WAAW,EAAE,IAAI;YACjB,GAAG,EAAE,EAAE,GAAG,IAAA,uBAAe,GAAE,EAAE,mBAAmB,EAAE,GAAG,EAAE;SACxD,CAAC,CAAC;IACL,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,GAAG,CAAC,KAAK,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAC/C,MAAM,QAAQ,GACZ,MAAM,CAAC,GAAG,CAAC,MAAM,IAAI,EAAE,CAAC;SACrB,KAAK,CAAC,OAAO,CAAC;SACd,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;SAC1B,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;QAC7C,EAAE,KAAK,CAAC,WAAW,CAAC,MAAM,CAAC;SAC1B,IAAI,EAAE,IAAI,EAAE,CAAC;IAClB,IAAI,CAAC,QAAQ;QAAE,OAAO,IAAI,CAAC;IAC3B,IAAI,MAAM,IAAI,CAAC,oBAAoB,CAAC,QAAQ,CAAC;QAAE,OAAO,IAAI,CAAC;IAC3D,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,mBAAmB,EAAE,CAAC;AAC1D,CAAC;AAED;;;;;;;;;GASG;AACI,KAAK,UAAU,eAAe,CACnC,IAAyB;IAEzB,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IAClE,IAAI,CAAC,SAAS,IAAI,CAAC,SAAS,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IACrD,MAAM,IAAI,GAA2B,EAAE,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC;IACvE,IAAI,MAAM;QAAE,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACjC,IAAI,GAAa,CAAC;IAClB,IAAI,CAAC;QACH,GAAG,GAAG,MAAM,KAAK,CACf,GAAG,CAAC,UAAU,IAAI,oBAAoB,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,4BAA4B,EACvF;YACE,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,WAAW,EAAE,MAAM;aACpB;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;YAC1B,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,MAAM,CAAC;SACpC,CACF,CAAC;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,MAAM,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAChE,OAAO;YACL,KAAK,EAAE;gBACL,IAAI,EAAE,uBAAuB;gBAC7B,OAAO,EAAE,6BAA6B,MAAM,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC;aAC9D;SACF,CAAC;IACJ,CAAC;IACD,MAAM,GAAG,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAIvC,CAAC;IACT,MAAM,KAAK,GAAG,GAAG,EAAE,IAAI,EAAE,KAAK,CAAC;IAC/B,IAAI,GAAG,CAAC,EAAE,IAAI,GAAG,EAAE,OAAO,KAAK,IAAI,IAAI,KAAK,EAAE,CAAC;QAC7C,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC;IACzC,CAAC;IACD,MAAM,IAAI,GACR,OAAO,GAAG,EAAE,KAAK,EAAE,IAAI,KAAK,QAAQ,IAAI,GAAG,CAAC,KAAK,CAAC,IAAI;QACpD,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI;QAChB,CAAC,CAAC,wBAAwB,CAAC;IAC/B,MAAM,OAAO,GAAG,CACd,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,KAAK,QAAQ,IAAI,GAAG,CAAC,KAAK,CAAC,OAAO;QAC1D,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO;QACnB,CAAC,CAAC,kCAAkC,GAAG,CAAC,MAAM,GAAG,CACpD,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IAChB,OAAO,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,CAAC;AACtC,CAAC;AAMD;;;;;;;;;;GAUG;AACI,KAAK,UAAU,cAAc,CAClC,IAAwB;IAExB,MAAM,KAAK,GAAG,IAAA,sBAAW,EAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAC1C,IAAI,KAAK;QAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;IACtD,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC;IAChE,IAAI,GAAG;QAAE,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;IAC9C,MAAM,GAAG,GAAG,WAAW,EAAE,CAAC;IAC1B,IAAI,GAAG;QAAE,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;IACjD,MAAM,OAAO,GAAG,MAAM,eAAe,CAAC,IAAI,CAAC,CAAC;IAC5C,IAAI,OAAO,IAAI,OAAO,IAAI,OAAO;QAAE,OAAO,OAAO,CAAC;IAClD,MAAM,UAAU,GAAG,OAAO,IAAI,OAAO,IAAI,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;IACxE,MAAM,MAAM,GAAG,mBAAmB,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACnD,IAAI,MAAM,EAAE,CAAC;QACX,OAAO,UAAU;YACf,CAAC,CAAC,EAAE,GAAG,MAAM,EAAE,IAAI,EAAE,WAAW,UAAU,CAAC,IAAI,EAAE,EAAE;YACnD,CAAC,CAAC,MAAM,CAAC;IACb,CAAC;IACD,IAAI,UAAU;QAAE,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC;IAC7C,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;GAIG;AACH,SAAgB,aAAa,CAAC,IAAY,EAAE,OAAe;IACzD,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,oBAAoB;YACvB,OAAO,wNAAwN,CAAC;QAClO,KAAK,0BAA0B;YAC7B,OAAO,4OAA4O,CAAC;QACtP,KAAK,2BAA2B,CAAC;QACjC,KAAK,wBAAwB,CAAC;QAC9B,KAAK,uBAAuB;YAC1B,OAAO,oBAAoB,OAAO,sEAAsE,CAAC;QAC3G;YACE,OAAO,oBAAoB,IAAI,KAAK,OAAO,yBAAyB,CAAC;IACzE,CAAC;AACH,CAAC"}
|
|
@@ -100,6 +100,24 @@ async function emitWithVision(emit, session, cmdId, payload, opts) {
|
|
|
100
100
|
/* keep the pre-settle screen */
|
|
101
101
|
}
|
|
102
102
|
}
|
|
103
|
+
if (session?.connected && typeof session.detectChallenge === 'function') {
|
|
104
|
+
if (!payload.challenge) {
|
|
105
|
+
try {
|
|
106
|
+
const challenge = await session.detectChallenge();
|
|
107
|
+
if (challenge) {
|
|
108
|
+
payload.challenge = {
|
|
109
|
+
...challenge,
|
|
110
|
+
attempted: false,
|
|
111
|
+
passed: false,
|
|
112
|
+
nextStep: challenge.kind === 'block' ? 'report_blocked' : 'ask_human',
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
catch {
|
|
117
|
+
/* a challenge probe never fails the action */
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
103
121
|
if (session?.connected && session.qaVision === true) {
|
|
104
122
|
try {
|
|
105
123
|
const shot = await session.screenshot('jpeg', 62);
|
|
@@ -269,6 +287,8 @@ async function handleBrowserCommand(data, emit) {
|
|
|
269
287
|
? data.actor.trim().slice(0, 80)
|
|
270
288
|
: null;
|
|
271
289
|
const isolated = data.isolated === true;
|
|
290
|
+
// OPT-IN fingerprint reduction (2026-10): see BrowserSessionOptions.
|
|
291
|
+
const stealth = data.stealth === true;
|
|
272
292
|
// A tagged window never changes hands.
|
|
273
293
|
const tagged = manager.get(sessionId);
|
|
274
294
|
if (tagged?.actor && callActor) {
|
|
@@ -293,12 +313,19 @@ async function handleBrowserCommand(data, emit) {
|
|
|
293
313
|
existing.setAllowCredentials(allowCredentials);
|
|
294
314
|
existing.setQaVision(qaVision);
|
|
295
315
|
existing.setActor(callActor);
|
|
316
|
+
if (stealth)
|
|
317
|
+
await existing.enableStealth();
|
|
296
318
|
// reset:true drops a crashed run's leftovers (open modal, corrupted
|
|
297
319
|
// field values, stale validation errors) before the new run starts.
|
|
298
320
|
// A resumed run omits it and keeps its page.
|
|
299
321
|
let pageState;
|
|
300
322
|
if (data.url) {
|
|
301
|
-
pageState = await existing.navigate(String(data.url)
|
|
323
|
+
pageState = await existing.navigate(String(data.url), {
|
|
324
|
+
autoChallenge: data.autoChallenge !== false,
|
|
325
|
+
challengeTimeoutMs: typeof data.challengeTimeoutMs === 'number'
|
|
326
|
+
? data.challengeTimeoutMs
|
|
327
|
+
: undefined,
|
|
328
|
+
});
|
|
302
329
|
}
|
|
303
330
|
else if (data.reset === true) {
|
|
304
331
|
pageState = await existing.navigate('about:blank');
|
|
@@ -314,6 +341,7 @@ async function handleBrowserCommand(data, emit) {
|
|
|
314
341
|
port: existing.port,
|
|
315
342
|
...(existing.actor ? { actor: existing.actor } : {}),
|
|
316
343
|
qaVision: existing.qaVision,
|
|
344
|
+
stealth: existing.stealth,
|
|
317
345
|
...pageState,
|
|
318
346
|
...(screen ? { screen } : {}),
|
|
319
347
|
});
|
|
@@ -357,6 +385,7 @@ async function handleBrowserCommand(data, emit) {
|
|
|
357
385
|
profileDir: profile.dir,
|
|
358
386
|
allowCredentials,
|
|
359
387
|
qaVision,
|
|
388
|
+
stealth,
|
|
360
389
|
...(callActor ? { actor: callActor } : {}),
|
|
361
390
|
});
|
|
362
391
|
// A reused session keeps its flag from a previous connect; honour the
|
|
@@ -369,7 +398,12 @@ async function handleBrowserCommand(data, emit) {
|
|
|
369
398
|
log.info(`Browser session "${sessionId}" on port ${actualPort} ` +
|
|
370
399
|
`(${profile.shared ? 'shared debug profile' : `isolated profile ${profile.dir}`})`);
|
|
371
400
|
const pageState = data.url
|
|
372
|
-
? await session.navigate(String(data.url)
|
|
401
|
+
? await session.navigate(String(data.url), {
|
|
402
|
+
autoChallenge: data.autoChallenge !== false,
|
|
403
|
+
challengeTimeoutMs: typeof data.challengeTimeoutMs === 'number'
|
|
404
|
+
? data.challengeTimeoutMs
|
|
405
|
+
: undefined,
|
|
406
|
+
})
|
|
373
407
|
: info;
|
|
374
408
|
const screen = await screenOf(session);
|
|
375
409
|
emit('orchestrator:browser-result', data.cmdId, {
|
|
@@ -379,6 +413,7 @@ async function handleBrowserCommand(data, emit) {
|
|
|
379
413
|
profile: profile.shared ? 'shared' : 'isolated',
|
|
380
414
|
...(callActor ? { actor: callActor } : {}),
|
|
381
415
|
qaVision: session.qaVision,
|
|
416
|
+
stealth: session.stealth,
|
|
382
417
|
...pageState,
|
|
383
418
|
...(screen ? { screen } : {}),
|
|
384
419
|
});
|
|
@@ -430,7 +465,12 @@ async function handleBrowserCommand(data, emit) {
|
|
|
430
465
|
.then((info) => info.url ?? null)
|
|
431
466
|
.catch(() => null);
|
|
432
467
|
const navSince = Date.now();
|
|
433
|
-
const info = await session.navigate(url
|
|
468
|
+
const info = await session.navigate(url, {
|
|
469
|
+
autoChallenge: data.autoChallenge !== false,
|
|
470
|
+
challengeTimeoutMs: typeof data.challengeTimeoutMs === 'number'
|
|
471
|
+
? data.challengeTimeoutMs
|
|
472
|
+
: undefined,
|
|
473
|
+
});
|
|
434
474
|
const screen = await screenOf(session);
|
|
435
475
|
await emitWithVision(emit, session, data.cmdId, {
|
|
436
476
|
success: true,
|
|
@@ -1093,9 +1133,22 @@ async function handleBrowserCommand(data, emit) {
|
|
|
1093
1133
|
: {}),
|
|
1094
1134
|
...(data.refs === true ? { refs: true } : {}),
|
|
1095
1135
|
});
|
|
1136
|
+
const challenge = data.includeChallenge === false
|
|
1137
|
+
? null
|
|
1138
|
+
: await session.detectChallenge().catch(() => null);
|
|
1096
1139
|
const payload = {
|
|
1097
1140
|
success: true,
|
|
1098
1141
|
...state,
|
|
1142
|
+
...(challenge
|
|
1143
|
+
? {
|
|
1144
|
+
challenge: {
|
|
1145
|
+
...challenge,
|
|
1146
|
+
attempted: false,
|
|
1147
|
+
passed: false,
|
|
1148
|
+
nextStep: challenge.kind === 'block' ? 'report_blocked' : 'ask_human',
|
|
1149
|
+
},
|
|
1150
|
+
}
|
|
1151
|
+
: {}),
|
|
1099
1152
|
};
|
|
1100
1153
|
const wantsShot = data.screenshot === true ||
|
|
1101
1154
|
(session.qaVision && data.screenshot !== false);
|
|
@@ -1174,6 +1227,42 @@ async function handleBrowserCommand(data, emit) {
|
|
|
1174
1227
|
});
|
|
1175
1228
|
break;
|
|
1176
1229
|
}
|
|
1230
|
+
// 2026-10: bounded Cloudflare/CAPTCHA resolution. `attempt` defaults to
|
|
1231
|
+
// none here - navigate already makes the one allowed click; this action
|
|
1232
|
+
// is for a resume after a human answer, so it only polls.
|
|
1233
|
+
case 'waitForChallenge': {
|
|
1234
|
+
const session = manager.get(sessionId);
|
|
1235
|
+
if (!session?.connected) {
|
|
1236
|
+
emit('orchestrator:browser-result', data.cmdId, {
|
|
1237
|
+
success: false,
|
|
1238
|
+
error: `No active browser session "${sessionId}". ` +
|
|
1239
|
+
`Call browser_open({ sessionId: "${sessionId}" }) first.`,
|
|
1240
|
+
});
|
|
1241
|
+
return;
|
|
1242
|
+
}
|
|
1243
|
+
const result = await session.waitForChallenge({
|
|
1244
|
+
attempt: data.attempt === true,
|
|
1245
|
+
timeoutMs: typeof data.timeoutMs === 'number'
|
|
1246
|
+
? data.timeoutMs
|
|
1247
|
+
: typeof data.challengeTimeoutMs === 'number'
|
|
1248
|
+
? data.challengeTimeoutMs
|
|
1249
|
+
: undefined,
|
|
1250
|
+
});
|
|
1251
|
+
const screen = await screenOf(session);
|
|
1252
|
+
await emitWithVision(emit, session, data.cmdId, {
|
|
1253
|
+
success: true,
|
|
1254
|
+
...result,
|
|
1255
|
+
...(screen ? { screen } : {}),
|
|
1256
|
+
...(result.passed
|
|
1257
|
+
? {}
|
|
1258
|
+
: {
|
|
1259
|
+
nextStep: result.challenge?.kind === 'block'
|
|
1260
|
+
? 'report_blocked'
|
|
1261
|
+
: 'ask_human',
|
|
1262
|
+
}),
|
|
1263
|
+
}, { settle: false });
|
|
1264
|
+
break;
|
|
1265
|
+
}
|
|
1177
1266
|
// 2026-10: recent toast / alert / dialog events. A toast that disappeared
|
|
1178
1267
|
// before the next tool call is still in the page's ring buffer.
|
|
1179
1268
|
case 'events': {
|