aws-runtime-bridge 1.9.100 → 1.9.101
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/browser/browser-bootstrap.d.ts +11 -0
- package/dist/browser/browser-bootstrap.js +4 -0
- package/dist/browser/browser-connect-token.d.ts +10 -0
- package/dist/browser/browser-connect-token.js +2 -0
- package/dist/browser/browser-pool.d.ts +3 -1
- package/dist/browser/browser-pool.js +1 -1
- package/dist/browser/browser-ws-bridge.d.ts +12 -0
- package/dist/browser/browser-ws-bridge.js +6 -0
- package/dist/index.js +1 -1
- package/dist/routes/browser-sessions.js +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
export declare function isBrowserMissingError(error: unknown): boolean;
|
|
4
|
+
export interface BrowserInstallResult {
|
|
5
|
+
ok: boolean;
|
|
6
|
+
output: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export declare function installPlaywrightChromium(): Promise<BrowserInstallResult>;
|
|
10
|
+
|
|
11
|
+
export declare function formatBrowserLaunchError(error: Error, install: BrowserInstallResult): Error;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import{execFile as n}from"node:child_process";import{createRequire as a}from"node:module";import{dirname as m,join as u}from"node:path";import{promisify as c}from"node:util";import{createLogger as l}from"../utils/logger.js";const s=l("browser-bootstrap"),h=c(n),p=a(import.meta.url),g=/executable doesn't exist/i,w=/missing dependencies|shared librar|libnss3|error while loading/i,d=10*60*1e3;function $(r){return r instanceof Error&&g.test(r.message)}function f(){const r=p.resolve("playwright/package.json");return u(m(r),"cli.js")}async function C(){const r=f();s.info(`\u6B63\u5728\u81EA\u52A8\u5B89\u88C5 Playwright Chromium\uFF08\u9996\u6B21\u4F7F\u7528\u9700\u4E0B\u8F7D\uFF0C\u53EF\u80FD\u8017\u65F6\u51E0\u5206\u949F\uFF09: node ${r} install chromium`);try{const{stdout:t,stderr:i}=await h(process.execPath,[r,"install","chromium"],{timeout:d,maxBuffer:16777216,windowsHide:!0});return s.info("Playwright Chromium \u81EA\u52A8\u5B89\u88C5\u5B8C\u6210"),{ok:!0,output:`${t??""}${i??""}`.trim()}}catch(t){const i=t,o=`${i.stdout??""}${i.stderr??""}`.trim()||i.message||String(t);return s.warn(`Playwright Chromium \u81EA\u52A8\u5B89\u88C5\u5931\u8D25: ${o.slice(0,500)}`),{ok:!1,output:o}}}function _(r,t){const i=`${t.output}
|
|
2
|
+
${r.message}`,o=w.test(i),e=[`\u6D4F\u89C8\u5668\u542F\u52A8\u5931\u8D25: ${r.message}`];return o?e.push("\u68C0\u6D4B\u5230\u7CFB\u7EDF\u7F3A\u5C11 Chromium \u8FD0\u884C\u6240\u9700\u4F9D\u8D56\uFF08\u5E38\u89C1\u4E8E\u7CBE\u7B80 Linux \u670D\u52A1\u5668\uFF09\u3002\u8BF7\u4EE5 root \u6267\u884C\u5B89\u88C5\u7CFB\u7EDF\u4F9D\u8D56\u5E76\u91CD\u8BD5\uFF1A"," sudo npx playwright install --with-deps chromium"):t.ok?e.push("\u6D4F\u89C8\u5668\u5DF2\u81EA\u52A8\u5B89\u88C5\u4F46\u542F\u52A8\u4ECD\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5\u78C1\u76D8\u7A7A\u95F4\u6216\u7CFB\u7EDF\u4F9D\u8D56\uFF0C\u53EF\u624B\u52A8\u6267\u884C\uFF1A"," sudo npx playwright install --with-deps chromium"):e.push("Playwright Chromium \u81EA\u52A8\u5B89\u88C5\u5931\u8D25\uFF0C\u8BF7\u624B\u52A8\u6267\u884C\uFF1A"," npx playwright install chromium","\uFF08\u82E5\u63D0\u793A\u7F3A\u5C11\u7CFB\u7EDF\u5E93\uFF0C\u5219\u6267\u884C\uFF1Asudo npx playwright install --with-deps chromium\uFF09"),new Error(e.join(`
|
|
3
|
+
`))}export{_ as formatBrowserLaunchError,C as installPlaywrightChromium,$ as isBrowserMissingError};
|
|
4
|
+
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
export declare function createBrowserConnectToken(agentId: string, browserId?: string): {
|
|
4
|
+
token: string;
|
|
5
|
+
expiresAt: string;
|
|
6
|
+
} | undefined;
|
|
7
|
+
|
|
8
|
+
export declare function consumeBrowserConnectToken(agentId: string, browserId: string, token: string): boolean;
|
|
9
|
+
|
|
10
|
+
export declare function deleteBrowserConnectTokensForAgent(agentId: string): void;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import i from"node:crypto";import{DEFAULT_BROWSER_ID as c}from"./types.js";const f=60*1e3,n=new Map;function u(o,e){const t=e&&e.trim()?e.trim():c,r=`browserws_${i.randomBytes(32).toString("base64url")}`,s=Date.now()+f;return n.set(r,{agentId:o,browserId:t,expiresAt:s}),{token:r,expiresAt:new Date(s).toISOString()}}function w(o,e,t){const r=n.get(t);return r?r.expiresAt<Date.now()?(n.delete(t),!1):r.agentId!==o||r.browserId!==e?!1:(n.delete(t),!0):!1}function d(o){for(const[e,t]of n.entries())t.agentId===o&&n.delete(e)}export{w as consumeBrowserConnectToken,u as createBrowserConnectToken,d as deleteBrowserConnectTokensForAgent};
|
|
2
|
+
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
|
|
2
2
|
import type { Page } from "playwright";
|
|
3
|
-
import { type BrowserPoolConfig, type SessionBrowser } from "./types.js";
|
|
4
3
|
import type { ListenerTriggerEvent, PageListener } from "./page-listener-types.js";
|
|
4
|
+
import { type BrowserPoolConfig, type SessionBrowser } from "./types.js";
|
|
5
5
|
|
|
6
6
|
export interface SessionSummary {
|
|
7
7
|
agentId: string;
|
|
@@ -38,6 +38,8 @@ export declare class BrowserPool {
|
|
|
38
38
|
|
|
39
39
|
launch(agentId: string, browserId?: string, title?: string, scopeKey?: string): Promise<SessionBrowser>;
|
|
40
40
|
|
|
41
|
+
private launchChromium;
|
|
42
|
+
|
|
41
43
|
get(agentId: string, browserId?: string): SessionBrowser | undefined;
|
|
42
44
|
|
|
43
45
|
getOrLaunch(agentId: string, browserId?: string, title?: string, scopeKey?: string): Promise<SessionBrowser>;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{chromium as M}from"playwright";import{DEFAULT_BROWSER_ID as h,IDLE_CHECK_INTERVAL_MS as _,IDLE_TIMEOUT_MS as C,MAX_PAGES_PER_SESSION as D,MAX_SESSIONS as x,MAX_SESSIONS_PER_AGENT as E,SESSION_TIMEOUT_MS as $,makeBrowserKey as k}from"./types.js";import{ScreencastManager as H}from"./screencast-manager.js";import{StepArchive as b}from"./step-archive.js";import{BrowserProfileStore as O}from"./browser-profile-store.js";import{ListenerStore as L}from"./listener-store.js";import{PageListenerManager as N}from"./page-listener-manager.js";import{buildStealthInitScript as B,STEALTH_LAUNCH_ARGS as R,STEALTH_IGNORE_ARGS as K}from"./stealth.js";const U=1280,z=800;class G{onSessionClose(e){this.sessionCloseHandlers.push(e)}setListenerTriggerHook(e){this.listenerTriggerHook=e}resolveKey(e,t){if(!e||typeof e!="string")throw new Error("scopeKey must be a non-empty string");const i=t&&t.trim()?t.trim():h;if(i.includes("::"))throw new Error(`browserId must not contain "::" (reserved separator): ${i}`);return k(e,i)}constructor(e){this.sessions=new Map,this.idleTimer=null,this.sessionCloseHandlers=[],this.listenerTriggerHook=null,this.config={headless:e?.headless??!0,executablePath:e?.executablePath,viewportWidth:e?.viewportWidth??U,viewportHeight:e?.viewportHeight??z,maxPagesPerSession:e?.maxPagesPerSession??D,maxSessionDurationMs:e?.maxSessionDurationMs??$,idleTimeoutMs:e?.idleTimeoutMs??C,launchArgs:e?.launchArgs,screencastConfig:e?.screencastConfig,archiveConfig:e?.archiveConfig,ssrfConfig:e?.ssrfConfig,userAgent:e?.userAgent,locale:e?.locale,timezone:e?.timezone,profileDir:e?.profileDir,stealth:e?.stealth??!0},this.profileStore=e?.profileDir?new O({profileDir:e.profileDir}):null,this.listenerStore=e?.profileDir?new L({listenerDir:e.profileDir}):null}async launch(e,t,i,s){const r=s??`agent:${e}`,n=this.resolveKey(r,t);if(this.sessions.has(n))throw new Error(`Browser session already exists for ${e}/${t??h}`);if(this.sessions.size>=x)throw new Error(`BrowserPool reached MAX_SESSIONS=${x}; close existing sessions before launching new ones`);let c=0;for(const o of this.sessions.values())o.agentId===e&&(c+=1);if(c>=E)throw new Error(`BrowserPool reached MAX_SESSIONS_PER_AGENT=${E} for agent ${e}; close some browser sessions first`);const l={headless:this.config.headless};this.config.executablePath&&(l.executablePath=this.config.executablePath),this.config.stealth?(l.ignoreDefaultArgs=[...K],l.args=[...R,...this.config.launchArgs??[]]):this.config.launchArgs&&this.config.launchArgs.length>0&&(l.args=this.config.launchArgs);const p=await M.launch(l);let m=this.config.userAgent,y;if(this.config.stealth)try{const o=await p.newBrowserCDPSession(),f=await o.send("Browser.getVersion"),g=f.product?.match(/Chrome\/(\d+)/);g&&(y=g[1]),!m&&f.userAgent&&(m=String(f.userAgent).replace(/HeadlessChrome\/([\d.]+)/g,"Chrome/$1")),await o.detach().catch(()=>{})}catch{}const w={viewport:{width:this.config.viewportWidth,height:this.config.viewportHeight}};if(m&&(w.userAgent=m),this.config.locale&&(w.locale=this.config.locale),this.config.timezone&&(w.timezoneId=this.config.timezone),this.profileStore)try{let o=await this.profileStore.load(r);!o&&r!==e&&(o=await this.profileStore.load(e),o&&await this.profileStore.save(r,o)),o&&(w.storageState=o)}catch{}const v=await p.newContext(w).catch(async o=>{throw await p.close().catch(()=>{}),o});this.config.stealth&&await v.addInitScript(B(y??"126")).catch(()=>{});const S=await v.newPage().catch(async o=>{throw await p.close().catch(()=>{}),o}),P=new H(this.config.screencastConfig),I=new b(this.config.archiveConfig),A=new N(e,t?.trim()||h,{onTrigger:(o,f)=>{const g=this.listenerTriggerHook;if(g)try{g(e,t?.trim()||h,o,f)}catch{}},store:this.listenerStore,scopeKey:r});try{await P.start(S)}catch{}try{const o=S;o.screencast?.showActions&&await o.screencast.showActions({cursor:"pointer"})}catch{}const T=Date.now(),a={agentId:e,scopeKey:r,browserId:t?.trim()||h,title:i?.trim()||"\u6D4F\u89C8\u5668\u4F1A\u8BDD",browser:p,context:v,pages:[S],activePageIndex:0,screencast:P,archive:I,listenerManager:A,launchedAt:T,lastActivityAt:T,humanTakeover:!1,qualityPreset:"original"};v.on("page",o=>{if(a.pages.length>=this.config.maxPagesPerSession){o.close().catch(()=>{});return}a.pages.push(o);const f=a.pages.length-1;this.setActivePage(e,f,a.browserId).catch(()=>{}),o.on("close",()=>{const g=a.pages.indexOf(o);if(g!==-1){if(a.pages.splice(g,1),a.pages.length===0){this.close(e,a.browserId).catch(()=>{});return}a.activePageIndex>=a.pages.length?a.activePageIndex=a.pages.length-1:g<a.activePageIndex&&(a.activePageIndex-=1)}})});try{await A.attach(S)}catch{}return this.sessions.set(n,a),this.ensureIdleTimer(),this.profileStore&&(a.autoSaveTimer=setInterval(async()=>{try{const o=await a.context.storageState();await this.profileStore.save(a.scopeKey,o)}catch{}},3e4),a.autoSaveTimer.unref&&a.autoSaveTimer.unref()),a}get(e,t){const i=t&&t.trim()?t.trim():h;for(const s of this.sessions.values())if(s.agentId===e&&s.browserId===i)return s}async getOrLaunch(e,t,i,s){const r=s??`agent:${e}`,n=this.resolveKey(r,t),c=this.sessions.get(n);return c||this.launch(e,t,i,s)}async close(e,t){const i=t&&t.trim()?t.trim():h;let s,r;for(const[c,l]of this.sessions)if(l.agentId===e&&l.browserId===i){s=c,r=l;break}if(!s||!r)return;const n=r;n.autoSaveTimer&&(clearInterval(n.autoSaveTimer),n.autoSaveTimer=void 0);try{await n.screencast.dispose()}catch{}try{await n.listenerManager.dispose()}catch{}if(n.archive.clear(),this.profileStore)try{const c=await n.context.storageState();await this.profileStore.save(n.scopeKey,c)}catch{}try{await n.browser.close()}catch{}this.sessions.delete(s);for(const c of this.sessionCloseHandlers)try{c(e,i)}catch{}this.sessions.size===0&&this.stopIdleTimer()}async closeByAgent(e){if(!e)return;const t=[];for(const[i,s]of this.sessions)s.agentId===e&&t.push(i);await Promise.all(t.map(i=>{const r=this.sessions.get(i)?.browserId;return this.close(e,r)}))}async collectListenerEvents(e){if(!e)return[];const t=[];for(const i of this.sessions.values()){if(i.agentId!==e)continue;await i.listenerManager.scanExistsAtPoll();const s=i.listenerManager.collectEvents();s.length>0&&t.push(...s)}return t.sort((i,s)=>i.triggeredAt-s.triggeredAt),t}getActivePage(e,t){const i=this.requireSession(e,t),s=i.pages[i.activePageIndex];if(!s||s.isClosed())throw new Error(`No active page for agent ${e}/${i.browserId} (index ${i.activePageIndex})`);return s}async setActivePage(e,t,i){const s=this.requireSession(e,i);if(!Number.isInteger(t)||t<0||t>=s.pages.length)throw new Error(`Page index ${t} out of range (0..${s.pages.length-1}) for agent ${e}/${s.browserId}`);if(s.activePageIndex===t)return s.pages[t];const r=s.pages[s.activePageIndex];if(r&&!r.isClosed())try{await s.screencast.stop(r)}catch{}s.activePageIndex=t;const n=s.pages[t];try{await s.screencast.start(n)}catch{}try{await s.listenerManager.reattach(n)}catch{}return this.touchActivity(e,i),n}async newPage(e,t){const i=this.requireSession(e,t);if(i.pages.length>=this.config.maxPagesPerSession)throw new Error(`Agent ${e}/${i.browserId} reached maxPagesPerSession=${this.config.maxPagesPerSession}; close a tab first`);const s=await i.context.newPage();i.pages.push(s);const r=i.pages.length-1;return this.touchActivity(e,t),this.setActivePage(e,r,t)}async closePage(e,t,i){const s=this.requireSession(e,i);if(!Number.isInteger(t)||t<0||t>=s.pages.length)throw new Error(`Page index ${t} out of range (0..${s.pages.length-1}) for agent ${e}/${s.browserId}`);const r=s.pages[t];if(t===s.activePageIndex)try{await s.screencast.stop(r)}catch{}try{await r.close()}catch{}if(s.pages.splice(t,1),s.pages.length===0){await this.close(e,i);return}s.activePageIndex>=s.pages.length?s.activePageIndex=s.pages.length-1:t<s.activePageIndex&&(s.activePageIndex-=1);const n=s.pages[s.activePageIndex];if(!n.isClosed()){try{await s.screencast.start(n)}catch{}try{await s.listenerManager.reattach(n)}catch{}}this.touchActivity(e,i)}listSessions(e){const t=[];for(const i of this.sessions.values()){if(e&&i.agentId!==e)continue;const s=i.pages[i.activePageIndex];let r="",n="";if(s&&!s.isClosed())try{r=s.url()}catch{}t.push({agentId:i.agentId,browserId:i.browserId,title:i.title,pageCount:i.pages.length,activePageIndex:i.activePageIndex,launchedAt:i.launchedAt,lastActivityAt:i.lastActivityAt,currentUrl:r,currentTitle:n})}return t}touchActivity(e,t){const i=t&&t.trim()?t.trim():h;for(const s of this.sessions.values())if(s.agentId===e&&s.browserId===i){s.lastActivityAt=Date.now();return}}async dispose(){this.stopIdleTimer();const e=Array.from(this.sessions.keys());await Promise.all(e.map(t=>{const i=this.sessions.get(t);return i?this.close(i.agentId,i.browserId):Promise.resolve()}))}requireSession(e,t){const i=t&&t.trim()?t.trim():h;for(const s of this.sessions.values())if(s.agentId===e&&s.browserId===i)return s;throw new Error(`Browser session not launched for ${e}/${t??h}`)}ensureIdleTimer(){this.idleTimer||this.config.idleTimeoutMs<=0&&this.config.maxSessionDurationMs<=0||(this.idleTimer=setInterval(()=>{this.checkIdleSessions()},_),this.idleTimer.unref&&this.idleTimer.unref())}stopIdleTimer(){this.idleTimer&&(clearInterval(this.idleTimer),this.idleTimer=null)}async checkIdleSessions(){const e=Date.now(),t=[];for(const i of this.sessions.values()){if(i.humanTakeover)continue;const s=e-i.lastActivityAt,r=e-i.launchedAt;if(this.config.idleTimeoutMs>0&&s>this.config.idleTimeoutMs){t.push(i);continue}this.config.maxSessionDurationMs>0&&r>this.config.maxSessionDurationMs&&t.push(i)}await Promise.all(t.map(i=>this.close(i.agentId,i.browserId)))}}let u=null;function Y(d){return u||(u=new G(d)),u}async function Z(){u&&(await u.dispose(),u=null)}export{G as BrowserPool,Z as disposeBrowserPool,Y as getBrowserPool};
|
|
1
|
+
import{chromium as E}from"playwright";import{formatBrowserLaunchError as C,installPlaywrightChromium as _,isBrowserMissingError as D}from"./browser-bootstrap.js";import{BrowserProfileStore as $}from"./browser-profile-store.js";import{ListenerStore as b}from"./listener-store.js";import{PageListenerManager as k}from"./page-listener-manager.js";import{ScreencastManager as H}from"./screencast-manager.js";import{buildStealthInitScript as B,STEALTH_LAUNCH_ARGS as L,STEALTH_IGNORE_ARGS as O}from"./stealth.js";import{StepArchive as N}from"./step-archive.js";import{DEFAULT_BROWSER_ID as h,IDLE_CHECK_INTERVAL_MS as R,IDLE_TIMEOUT_MS as K,MAX_PAGES_PER_SESSION as U,MAX_SESSIONS as x,MAX_SESSIONS_PER_AGENT as I,SESSION_TIMEOUT_MS as z,makeBrowserKey as G}from"./types.js";const W=1280,q=800;class V{onSessionClose(e){this.sessionCloseHandlers.push(e)}setListenerTriggerHook(e){this.listenerTriggerHook=e}resolveKey(e,s){if(!e||typeof e!="string")throw new Error("scopeKey must be a non-empty string");const i=s&&s.trim()?s.trim():h;if(i.includes("::"))throw new Error(`browserId must not contain "::" (reserved separator): ${i}`);return G(e,i)}constructor(e){this.sessions=new Map,this.idleTimer=null,this.sessionCloseHandlers=[],this.listenerTriggerHook=null,this.config={headless:e?.headless??!0,executablePath:e?.executablePath,viewportWidth:e?.viewportWidth??W,viewportHeight:e?.viewportHeight??q,maxPagesPerSession:e?.maxPagesPerSession??U,maxSessionDurationMs:e?.maxSessionDurationMs??z,idleTimeoutMs:e?.idleTimeoutMs??K,launchArgs:e?.launchArgs,screencastConfig:e?.screencastConfig,archiveConfig:e?.archiveConfig,ssrfConfig:e?.ssrfConfig,userAgent:e?.userAgent,locale:e?.locale,timezone:e?.timezone,profileDir:e?.profileDir,stealth:e?.stealth??!0},this.profileStore=e?.profileDir?new $({profileDir:e.profileDir}):null,this.listenerStore=e?.profileDir?new b({listenerDir:e.profileDir}):null}async launch(e,s,i,t){const r=t??`agent:${e}`,n=this.resolveKey(r,s);if(this.sessions.has(n))throw new Error(`Browser session already exists for ${e}/${s??h}`);if(this.sessions.size>=x)throw new Error(`BrowserPool reached MAX_SESSIONS=${x}; close existing sessions before launching new ones`);let c=0;for(const o of this.sessions.values())o.agentId===e&&(c+=1);if(c>=I)throw new Error(`BrowserPool reached MAX_SESSIONS_PER_AGENT=${I} for agent ${e}; close some browser sessions first`);const l={headless:this.config.headless};this.config.executablePath&&(l.executablePath=this.config.executablePath),this.config.stealth?(l.ignoreDefaultArgs=[...O],l.args=[...L,...this.config.launchArgs??[]]):this.config.launchArgs&&this.config.launchArgs.length>0&&(l.args=this.config.launchArgs);const p=await this.launchChromium(l);let m=this.config.userAgent,y;if(this.config.stealth)try{const o=await p.newBrowserCDPSession(),f=await o.send("Browser.getVersion"),g=f.product?.match(/Chrome\/(\d+)/);g&&(y=g[1]),!m&&f.userAgent&&(m=String(f.userAgent).replace(/HeadlessChrome\/([\d.]+)/g,"Chrome/$1")),await o.detach().catch(()=>{})}catch{}const w={viewport:{width:this.config.viewportWidth,height:this.config.viewportHeight}};if(m&&(w.userAgent=m),this.config.locale&&(w.locale=this.config.locale),this.config.timezone&&(w.timezoneId=this.config.timezone),this.profileStore)try{let o=await this.profileStore.load(r);!o&&r!==e&&(o=await this.profileStore.load(e),o&&await this.profileStore.save(r,o)),o&&(w.storageState=o)}catch{}const S=await p.newContext(w).catch(async o=>{throw await p.close().catch(()=>{}),o});this.config.stealth&&await S.addInitScript(B(y??"126")).catch(()=>{});const v=await S.newPage().catch(async o=>{throw await p.close().catch(()=>{}),o}),P=new H(this.config.screencastConfig),M=new N(this.config.archiveConfig),A=new k(e,s?.trim()||h,{onTrigger:(o,f)=>{const g=this.listenerTriggerHook;if(g)try{g(e,s?.trim()||h,o,f)}catch{}},store:this.listenerStore,scopeKey:r});try{await P.start(v)}catch{}try{const o=v;o.screencast?.showActions&&await o.screencast.showActions({cursor:"pointer"})}catch{}const T=Date.now(),a={agentId:e,scopeKey:r,browserId:s?.trim()||h,title:i?.trim()||"\u6D4F\u89C8\u5668\u4F1A\u8BDD",browser:p,context:S,pages:[v],activePageIndex:0,screencast:P,archive:M,listenerManager:A,launchedAt:T,lastActivityAt:T,humanTakeover:!1,qualityPreset:"original"};S.on("page",o=>{if(a.pages.length>=this.config.maxPagesPerSession){o.close().catch(()=>{});return}a.pages.push(o);const f=a.pages.length-1;this.setActivePage(e,f,a.browserId).catch(()=>{}),o.on("close",()=>{const g=a.pages.indexOf(o);if(g!==-1){if(a.pages.splice(g,1),a.pages.length===0){this.close(e,a.browserId).catch(()=>{});return}a.activePageIndex>=a.pages.length?a.activePageIndex=a.pages.length-1:g<a.activePageIndex&&(a.activePageIndex-=1)}})});try{await A.attach(v)}catch{}return this.sessions.set(n,a),this.ensureIdleTimer(),this.profileStore&&(a.autoSaveTimer=setInterval(async()=>{try{const o=await a.context.storageState();await this.profileStore.save(a.scopeKey,o)}catch{}},3e4),a.autoSaveTimer.unref&&a.autoSaveTimer.unref()),a}async launchChromium(e){try{return await E.launch(e)}catch(s){if(this.config.executablePath||!D(s))throw s;const i=await _();try{return await E.launch(e)}catch(t){throw C(t instanceof Error?t:new Error(String(t)),i)}}}get(e,s){const i=s&&s.trim()?s.trim():h;for(const t of this.sessions.values())if(t.agentId===e&&t.browserId===i)return t}async getOrLaunch(e,s,i,t){const r=t??`agent:${e}`,n=this.resolveKey(r,s),c=this.sessions.get(n);return c||this.launch(e,s,i,t)}async close(e,s){const i=s&&s.trim()?s.trim():h;let t,r;for(const[c,l]of this.sessions)if(l.agentId===e&&l.browserId===i){t=c,r=l;break}if(!t||!r)return;const n=r;n.autoSaveTimer&&(clearInterval(n.autoSaveTimer),n.autoSaveTimer=void 0);try{await n.screencast.dispose()}catch{}try{await n.listenerManager.dispose()}catch{}if(n.archive.clear(),this.profileStore)try{const c=await n.context.storageState();await this.profileStore.save(n.scopeKey,c)}catch{}try{await n.browser.close()}catch{}this.sessions.delete(t);for(const c of this.sessionCloseHandlers)try{c(e,i)}catch{}this.sessions.size===0&&this.stopIdleTimer()}async closeByAgent(e){if(!e)return;const s=[];for(const[i,t]of this.sessions)t.agentId===e&&s.push(i);await Promise.all(s.map(i=>{const r=this.sessions.get(i)?.browserId;return this.close(e,r)}))}async collectListenerEvents(e){if(!e)return[];const s=[];for(const i of this.sessions.values()){if(i.agentId!==e)continue;await i.listenerManager.scanExistsAtPoll();const t=i.listenerManager.collectEvents();t.length>0&&s.push(...t)}return s.sort((i,t)=>i.triggeredAt-t.triggeredAt),s}getActivePage(e,s){const i=this.requireSession(e,s),t=i.pages[i.activePageIndex];if(!t||t.isClosed())throw new Error(`No active page for agent ${e}/${i.browserId} (index ${i.activePageIndex})`);return t}async setActivePage(e,s,i){const t=this.requireSession(e,i);if(!Number.isInteger(s)||s<0||s>=t.pages.length)throw new Error(`Page index ${s} out of range (0..${t.pages.length-1}) for agent ${e}/${t.browserId}`);if(t.activePageIndex===s)return t.pages[s];const r=t.pages[t.activePageIndex];if(r&&!r.isClosed())try{await t.screencast.stop(r)}catch{}t.activePageIndex=s;const n=t.pages[s];try{await t.screencast.start(n)}catch{}try{await t.listenerManager.reattach(n)}catch{}return this.touchActivity(e,i),n}async newPage(e,s){const i=this.requireSession(e,s);if(i.pages.length>=this.config.maxPagesPerSession)throw new Error(`Agent ${e}/${i.browserId} reached maxPagesPerSession=${this.config.maxPagesPerSession}; close a tab first`);const t=await i.context.newPage();i.pages.push(t);const r=i.pages.length-1;return this.touchActivity(e,s),this.setActivePage(e,r,s)}async closePage(e,s,i){const t=this.requireSession(e,i);if(!Number.isInteger(s)||s<0||s>=t.pages.length)throw new Error(`Page index ${s} out of range (0..${t.pages.length-1}) for agent ${e}/${t.browserId}`);const r=t.pages[s];if(s===t.activePageIndex)try{await t.screencast.stop(r)}catch{}try{await r.close()}catch{}if(t.pages.splice(s,1),t.pages.length===0){await this.close(e,i);return}t.activePageIndex>=t.pages.length?t.activePageIndex=t.pages.length-1:s<t.activePageIndex&&(t.activePageIndex-=1);const n=t.pages[t.activePageIndex];if(!n.isClosed()){try{await t.screencast.start(n)}catch{}try{await t.listenerManager.reattach(n)}catch{}}this.touchActivity(e,i)}listSessions(e){const s=[];for(const i of this.sessions.values()){if(e&&i.agentId!==e)continue;const t=i.pages[i.activePageIndex];let r="",n="";if(t&&!t.isClosed())try{r=t.url()}catch{}s.push({agentId:i.agentId,browserId:i.browserId,title:i.title,pageCount:i.pages.length,activePageIndex:i.activePageIndex,launchedAt:i.launchedAt,lastActivityAt:i.lastActivityAt,currentUrl:r,currentTitle:n})}return s}touchActivity(e,s){const i=s&&s.trim()?s.trim():h;for(const t of this.sessions.values())if(t.agentId===e&&t.browserId===i){t.lastActivityAt=Date.now();return}}async dispose(){this.stopIdleTimer();const e=Array.from(this.sessions.keys());await Promise.all(e.map(s=>{const i=this.sessions.get(s);return i?this.close(i.agentId,i.browserId):Promise.resolve()}))}requireSession(e,s){const i=s&&s.trim()?s.trim():h;for(const t of this.sessions.values())if(t.agentId===e&&t.browserId===i)return t;throw new Error(`Browser session not launched for ${e}/${s??h}`)}ensureIdleTimer(){this.idleTimer||this.config.idleTimeoutMs<=0&&this.config.maxSessionDurationMs<=0||(this.idleTimer=setInterval(()=>{this.checkIdleSessions()},R),this.idleTimer.unref&&this.idleTimer.unref())}stopIdleTimer(){this.idleTimer&&(clearInterval(this.idleTimer),this.idleTimer=null)}async checkIdleSessions(){const e=Date.now(),s=[];for(const i of this.sessions.values()){if(i.humanTakeover)continue;const t=e-i.lastActivityAt,r=e-i.launchedAt;if(this.config.idleTimeoutMs>0&&t>this.config.idleTimeoutMs){s.push(i);continue}this.config.maxSessionDurationMs>0&&r>this.config.maxSessionDurationMs&&s.push(i)}await Promise.all(s.map(i=>this.close(i.agentId,i.browserId)))}}let u=null;function se(d){return u||(u=new V(d)),u}async function ie(){u&&(await u.dispose(),u=null)}export{V as BrowserPool,ie as disposeBrowserPool,se as getBrowserPool};
|
|
2
2
|
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
|
|
2
|
+
import type { IncomingMessage } from "node:http";
|
|
3
|
+
import type { Socket } from "node:net";
|
|
4
|
+
|
|
5
|
+
export declare function parseBrowserBridgePath(pathname: string): {
|
|
6
|
+
agentId: string;
|
|
7
|
+
browserId: string;
|
|
8
|
+
} | null;
|
|
9
|
+
|
|
10
|
+
export declare function attachBrowserWebSocketServer(server: {
|
|
11
|
+
on: (event: "upgrade", listener: (request: IncomingMessage, socket: Socket, head: Buffer) => void) => unknown;
|
|
12
|
+
}): void;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import i,{WebSocketServer as R}from"ws";import{isRuntimeTokenValid as U}from"../middleware/auth.js";import{getBrowserWsPort as T}from"../services/browser-session-manager.js";import{createLogger as k}from"../utils/logger.js";import{consumeBrowserConnectToken as E}from"./browser-connect-token.js";import{DEFAULT_BROWSER_ID as S}from"./types.js";const u=k("browser-ws-bridge"),O=/^\/browser\/agent\/([^/]+)(?:\/([^/]+))?$/;function W(c){const o=O.exec(c);return o?{agentId:decodeURIComponent(o[1]||""),browserId:o[2]?decodeURIComponent(o[2]):S}:null}function B(c,o){const a=o.searchParams.get("token")||"";if(a.trim())return a.trim();const t=c.headers["x-runtime-token"];return Array.isArray(t)?t[0]?.trim()||"":typeof t=="string"?t.trim():String(c.headers.authorization||"").match(/^Bearer\s+(.+)$/i)?.[1]?.trim()||""}function L(c){const o=new R({noServer:!0});c.on("upgrade",(a,t,b)=>{const h=a.headers.host||"localhost",$=new URL(a.url||"/",`http://${h}`),p=W($.pathname);if(!p)return;const d=B(a,$),s=p.agentId,g=p.browserId,y=d?d.length>12?`${d.substring(0,12)}...`:d:"empty";if(u.info(`[browser-ws] upgrade \u8BF7\u6C42: agentId=${s}, browserId=${g}, token=${y}`),!U(d)&&!E(s,g,d)){u.warn(`[browser-ws] token \u6821\u9A8C\u5931\u8D25: agentId=${s}, browserId=${g}`),t.write(`HTTP/1.1 401 Unauthorized\r
|
|
2
|
+
\r
|
|
3
|
+
`),t.destroy();return}const I=T();if(!I){u.warn(`[browser-ws] browser \u5DE5\u5177\u6808\u672A\u542F\u52A8: agentId=${s}`),t.write(`HTTP/1.1 503 Service Unavailable\r
|
|
4
|
+
\r
|
|
5
|
+
`),t.destroy();return}const P=g===S?`/agent/${encodeURIComponent(s)}`:`/agent/${encodeURIComponent(s)}/${encodeURIComponent(g)}`,f=`ws://127.0.0.1:${I}${P}`;let e=null;const w=[];o.handleUpgrade(a,t,b,n=>{try{e=new i(f)}catch(r){u.warn(`[browser-ws] \u672C\u5730 WS \u8FDE\u63A5\u5931\u8D25: ${f}, err=${r.message}`),n.close(1011,"local ws connect failed");return}const l=()=>{e&&e.readyState!==i.CLOSED&&e.close()};e.on("open",()=>{u.info(`[browser-ws] \u5DF2\u8F6C\u53D1: agentId=${s}, browserId=${g}, upstream=${f}`);for(const r of w)e&&e.readyState===i.OPEN&&e.send(r.data,{binary:r.binary});w.length=0}),e.on("message",(r,m)=>{n.readyState===i.OPEN&&n.send(r,{binary:m})}),e.on("close",(r,m)=>{n.readyState===i.OPEN&&n.close(r,m.toString())}),e.on("error",r=>{u.warn(`[browser-ws] \u672C\u5730 WS \u9519\u8BEF: agentId=${s}, err=${r.message}`),l(),n.readyState===i.OPEN&&n.close(1011,r.message)}),n.on("message",(r,m)=>{e&&e.readyState===i.OPEN?e.send(r,{binary:m}):w.length<200&&w.push({data:r,binary:m})}),n.on("close",()=>{l()}),n.on("error",()=>{l()})})})}export{L as attachBrowserWebSocketServer,W as parseBrowserBridgePath};
|
|
6
|
+
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import I from"express";import D from"cors";import{existsSync as E,readFileSync as B}from"node:fs";import x from"node:path";import M from"node:os";import{allowedCorsOrigins as y,port as h,validateProductionToken as O}from"./config.js";import{propertiesRouter as G}from"./routes/properties.js";import{ymlRouter as _}from"./routes/yml.js";import{instanceRouter as F,setGracefulShutdownFn as K}from"./routes/instance.js";import{skillsRouter as L}from"./routes/skills.js";import{mcpRouter as N}from"./routes/mcp.js";import{terminalRouter as j,sdkSessions as S}from"./routes/terminal.js";import{sessionsRouter as U}from"./routes/sessions.js";import{gitRouter as W}from"./routes/git.js";import{fileSnapshotRouter as z}from"./routes/file-snapshot.js";import{acodeTodosRouter as J}from"./routes/acode-todos.js";import{backgroundTasksRouter as Y}from"./routes/background-tasks.js";import{subAgentsRouter as q}from"./routes/sub-agents.js";import{browserSessionsRouter as H}from"./routes/browser-sessions.js";import{browserListenersRouter as Z}from"./routes/browser-listeners.js";import{fileBrowserRouter as Q}from"./routes/file-browser.js";import{aiSourcesRouter as V}from"./routes/ai-sources.js";import{processesRouter as X}from"./routes/processes.js";import{systemMetricsRouter as ee}from"./routes/system-metrics.js";import{taskContextRouter as re}from"./routes/task-context.js";import{fileDiffRollbackRouter as te}from"./routes/file-diff-rollback.js";import{attachPtyWebSocketServer as ie,closeAllPtySessions as ne,ptyRouter as oe,ptySessions as se}from"./routes/pty.js";import{runtimeBindingRouter as ae,logRuntimeBindingStartupState as me}from"./routes/runtime-binding.js";import{dashboardRouter as ue}from"./routes/dashboard.js";import{eventsRouter as ce}from"./routes/events.js";import{attachRemoteDesktopWebSocketServer as de}from"./remote-desktop/index.js";import{loadPersistedSessions as P,savePersistedSessions as $}from"./services/terminal-persistence.js";import{detectOrphanProcesses as ge}from"./services/process-detector.js";import{startOrphanMonitor as pe,stopOrphanMonitor as fe}from"./services/orphan-monitor.js";import{getAgentProcessManager as k}from"./services/agent-process-manager.js";import{adapterRegistry as le}from"./adapter/index.js";import{logger as e}from"./utils/logger.js";import{autoRegister as be,unregister as we,bridgeRestartCleanup as he,cancelBackgroundRegisterRetries as Se}from"./services/auto-register.js";import{stopTunnelClient as Re}from"./services/tunnel-client.js";import{ensureAwsClientAgentMcpReleased as Ie}from"./services/aws-client-agent-mcp.js";import{ensureAcodePackageReleased as ye}from"./services/acode-package.js";import{ensureStartupConfig as Pe}from"./services/startup-config-wizard.js";import{handleCliCommand as $e}from"./services/cli-commands.js";import{migrateOldPathsOnStartup as ke}from"./services/legacy-path-migration.js";import{subAgentStore as Ce}from"./services/sub-agent-manager-instance.js";import{disposeBrowserSessionManager as Te}from"./services/browser-session-manager.js";import{buildGracefulShutdownPlan as ve,shouldCleanupPersistedSessionsOnStartup as Ae}from"./services/runtime-lifecycle-policy.js";import{deliverPendingBridgeLifecycleNotifications as De}from"./services/lifecycle-state.js";const C=await $e();C.handled&&process.exit(C.exitCode),await Pe(),O(),Ie(),ye(),ke(),me();async function Ee(){try{if(await be())e.info("[runtime-bridge] \u81EA\u52A8\u6CE8\u518C\u6210\u529F");else{const{loadConfig:i}=await import("./services/auto-register.js"),s=i();!!s.userKey&&s.enabled?e.warn("[runtime-bridge] \u81EA\u52A8\u6CE8\u518C\u6682\u65F6\u5931\u8D25\uFF0C\u5C06\u5728\u540E\u53F0\u6301\u7EED\u91CD\u8BD5\u76F4\u5230\u4E0E\u8C03\u5EA6\u4E2D\u5FC3\u5EFA\u7ACB\u8FDE\u63A5"):(e.info("[runtime-bridge] \u81EA\u52A8\u6CE8\u518C\u672A\u914D\u7F6E\uFF0C\u7EE7\u7EED\u542F\u52A8\u670D\u52A1"),e.info("[runtime-bridge] \u8981\u542F\u7528\u81EA\u52A8\u6CE8\u518C\uFF0C\u8BF7\u521B\u5EFA\u914D\u7F6E\u6587\u4EF6 ~/.aws-bridge/config.json"))}}catch(r){const i=r;e.warn("[runtime-bridge] \u81EA\u52A8\u6CE8\u518C\u51FA\u9519:",i.message)}}Ee().then(()=>Be()).then(()=>De()).then(()=>{e.info("[runtime-bridge] Bridge \u751F\u547D\u5468\u671F\u901A\u77E5\u540C\u6B65\u5B8C\u6210")}).catch(r=>{e.warn("[runtime-bridge] \u81EA\u52A8\u6CE8\u518C\u6216\u6E05\u7406\u51FA\u9519:",r)});async function Be(){try{if(process.env.AWS_BRIDGE_RESTART_CLEANUP!=="true"){e.info("[runtime-bridge] \u8DF3\u8FC7 Bridge \u91CD\u542F\u6E05\u7406\uFF0C\u4FDD\u7559 Agent \u72B6\u6001\u4F9B\u8C03\u5EA6\u4E2D\u5FC3\u6062\u590D");return}const{getRegistrationState:r}=await import("./services/auto-register.js"),i=r();if(!i.registered||!i.instanceId){e.info("[runtime-bridge] \u5B9E\u4F8B\u672A\u6CE8\u518C\uFF0C\u8DF3\u8FC7 Bridge \u91CD\u542F\u6E05\u7406");return}e.info("[runtime-bridge] \u2605 Bridge \u91CD\u542F\u6E05\u7406\u5DF2\u663E\u5F0F\u542F\u7528\uFF0C\u6B63\u5728\u901A\u77E5\u8C03\u5EA6\u4E2D\u5FC3\u6E05\u7406 Agent \u72B6\u6001...");const s=await he();s.success?e.info(`[runtime-bridge] \u2605 Bridge \u91CD\u542F\u6E05\u7406\u6210\u529F\uFF0C\u6E05\u7406\u4E86 ${s.agentCount||0} \u4E2A Agent`):e.warn(`[runtime-bridge] \u2605 Bridge \u91CD\u542F\u6E05\u7406\u5931\u8D25: ${s.error}`)}catch(r){const i=r;e.warn("[runtime-bridge] Bridge \u91CD\u542F\u6E05\u7406\u51FA\u9519:",i.message)}}async function xe(){try{const r=await P();if(r.length===0){e.info("[runtime-bridge] \u65E0\u6301\u4E45\u5316\u4F1A\u8BDD\uFF0C\u8DF3\u8FC7\u8FDB\u7A0B\u6CE8\u518C\u8868\u91CD\u5EFA");return}await k().rebuildRegistry(r.map(s=>({agentId:s.agentId,sessionId:s.sessionId,pid:s.pid,workspacePath:s.workspacePath,command:s.command,mode:"sdk"}))),e.info(`[runtime-bridge] \u8FDB\u7A0B\u6CE8\u518C\u8868\u91CD\u5EFA\u5B8C\u6210: ${r.length} \u6761\u8BB0\u5F55`)}catch(r){const i=r;e.warn("[runtime-bridge] \u8FDB\u7A0B\u6CE8\u518C\u8868\u91CD\u5EFA\u5931\u8D25:",i.message)}}xe().catch(r=>{e.warn("[runtime-bridge] \u8FDB\u7A0B\u6CE8\u518C\u8868\u91CD\u5EFA\u51FA\u9519:",r)});async function Me(){try{const r=await import("node:fs/promises"),i=await import("node:path"),s=await import("node:os"),f=i.join(s.tmpdir(),"agentswork-runtime-bridge",".preserve-sessions");let u=!1;try{const t=await r.readFile(f,"utf-8");u=JSON.parse(t).preserveSessions===!0,await r.unlink(f),e.info(`[runtime-bridge] \u2605 \u68C0\u6D4B\u5230\u4FDD\u7559\u4F1A\u8BDD\u6807\u8BB0\uFF0CpreserveSessions=${u}`)}catch{}const a=await P();if(a.length===0){e.info("[runtime-bridge] \u542F\u52A8\u65F6\u65E0\u6301\u4E45\u5316\u4F1A\u8BDD\uFF0C\u65E0\u9700\u68C0\u6D4B\u5B64\u513F\u8FDB\u7A0B");return}if(!Ae(u)){e.info(`[runtime-bridge] \u2605 \u4FDD\u7559 ${a.length} \u4E2A\u6301\u4E45\u5316\u4F1A\u8BDD\u5E76\u91CD\u5EFA\u8FDB\u7A0B\u6CE8\u518C\u8868`),await k().rebuildRegistry(a.map(o=>({agentId:o.agentId,sessionId:o.sessionId,pid:o.pid,workspacePath:o.workspacePath,command:o.command,mode:"sdk"})));return}e.info(`[runtime-bridge] \u2605 \u5DF2\u663E\u5F0F\u542F\u7528\u542F\u52A8\u6E05\u7406\uFF0C\u68C0\u6D4B ${a.length} \u4E2A\u6301\u4E45\u5316\u4F1A\u8BDD\u7684\u5B64\u513F\u8FDB\u7A0B...`);const d=await ge(a.map(t=>({agentId:t.agentId,pid:t.pid,workspacePath:t.workspacePath,command:t.command})));if(d.length>0){e.warn(`[runtime-bridge] \u2605 \u68C0\u6D4B\u5230 ${d.length} \u4E2A\u5B64\u513F\u8FDB\u7A0B\u4ECD\u5728\u8FD0\u884C\uFF1A`);for(const t of d)e.warn(` - agentId=${t.agentId}, pid=${t.process.pid}, command=${t.process.command?.slice(0,50)}`);e.info("[runtime-bridge] \u6B63\u5728\u81EA\u52A8\u6E05\u7406\u6240\u6709\u5B64\u513F\u8FDB\u7A0B...");for(const t of d)try{if(t.process.pid)if(process.platform==="win32"){const{execSync:o}=await import("node:child_process");o(`taskkill /PID ${t.process.pid} /T /F`,{encoding:"utf8",timeout:3e3}),e.info(`[runtime-bridge] \u5DF2\u81EA\u52A8\u7EC8\u6B62\u5B64\u513F\u8FDB\u7A0B: agentId=${t.agentId}, PID=${t.process.pid}`)}else process.kill(t.process.pid,"SIGKILL"),e.info(`[runtime-bridge] \u5DF2\u81EA\u52A8\u7EC8\u6B62\u5B64\u513F\u8FDB\u7A0B: agentId=${t.agentId}, PID=${t.process.pid}`)}catch(o){const c=o;e.warn(`[runtime-bridge] \u81EA\u52A8\u7EC8\u6B62\u5B64\u513F\u8FDB\u7A0B\u5931\u8D25: agentId=${t.agentId}, PID=${t.process.pid}, error=${c.message}`)}await new Promise(t=>setTimeout(t,1e3))}await $([]),e.info(`[runtime-bridge] \u2605 \u542F\u52A8\u6E05\u7406\u5B8C\u6210\uFF0C\u5DF2\u6E05\u7A7A\u6240\u6709\u6301\u4E45\u5316\u4F1A\u8BDD\uFF08\u6E05\u7406\u4E86 ${d.length} \u4E2A\u5B64\u513F\u8FDB\u7A0B\uFF09`)}catch(r){const i=r;e.warn("[runtime-bridge] \u542F\u52A8\u65F6\u5B64\u513F\u8FDB\u7A0B\u68C0\u6D4B\u5931\u8D25:",i.message)}}Me().catch(r=>{e.warn("[runtime-bridge] \u5B64\u513F\u8FDB\u7A0B\u68C0\u6D4B\u51FA\u9519:",r)}),pe().catch(r=>{e.warn("[runtime-bridge] \u542F\u52A8\u5B64\u513F\u8FDB\u7A0B\u76D1\u63A7\u5931\u8D25:",r)});const n=I();n.use(D({origin(r,i){if(!r){i(null,!0);return}if(y.includes("*")){i(null,!0);return}if(y.includes(r)){i(null,!0);return}try{if(new URL(r).port===String(h)){i(null,!0);return}}catch{}i(new Error(`[runtime-bridge] CORS origin is not allowed: ${r}`))}})),n.use(I.json({limit:"1mb"})),n.use("/runtime",ae),n.use("/runtime",G),n.use("/runtime",_),n.use("/runtime",F),n.use("/runtime",L),n.use("/runtime",N),n.use("/runtime",j),n.use("/runtime",U),n.use("/runtime",X),n.use("/runtime",ee),n.use("/runtime",ce),n.use("/runtime",W),n.use("/runtime",z),n.use("/runtime",J),n.use("/runtime",Y),n.use("/runtime",q),n.use("/runtime",H),n.use("/runtime",Z),n.use("/runtime",V),n.use("/runtime",re),n.use("/runtime",te),n.use("/pty",oe),n.use("/",ue),n.use("/api/file-browser",Q);function Oe(){const r=n.listen(h,()=>{e.info(`[runtime-bridge] listening on ${h}`)});return ie(r),de(r),r.on("error",i=>{if(i.code==="EADDRINUSE"){e.error(`[runtime-bridge] port ${h} is already in use. Stop the existing runtime-bridge process or set AWS_RUNTIME_BRIDGE_PORT to another port before starting.`),process.exitCode=1;return}e.error("[runtime-bridge] failed to start server:",i),process.exitCode=1}),r}let T=!1;async function b(r,i,s=!1){if(T){e.info(`[runtime-bridge] \u5DF2\u5728\u5173\u95ED\u4E2D\uFF0C\u5FFD\u7565 ${r}`);return}T=!0,s||R()&&(s=!0,e.info("[runtime-bridge] \u2605 \u68C0\u6D4B\u5230 .preserve-sessions \u6807\u8BB0\u6587\u4EF6\uFF0C\u81EA\u52A8\u5347\u7EA7\u4E3A\u4FDD\u7559\u4F1A\u8BDD\u6A21\u5F0F")),e.info(`[runtime-bridge] \u6536\u5230 ${r} \u4FE1\u53F7\uFF0C\u5F00\u59CB\u4F18\u96C5\u5173\u95ED... (preserveSessions=${s})`);const f=Date.now(),u=ve(s);try{const a=S.size;if(u.terminateSdkSessions){e.info(`[runtime-bridge] \u6B63\u5728\u505C\u6B62 ${a} \u4E2A SDK \u4F1A\u8BDD...`);for(const[t,o]of S.entries())try{const c=o.providerId||"claude-code",g=le.get(c);let p="";try{const m=g.getSessionPid?.(t);m&&(p=` (PID: ${m})`)}catch{}await g.terminateSession(t),e.info(`[runtime-bridge] SDK \u4F1A\u8BDD ${t} \u5DF2\u7EC8\u6B62${p}`),S.delete(t)}catch(c){const g=c;e.error(`[runtime-bridge] SDK \u4F1A\u8BDD ${t} \u7EC8\u6B62\u5931\u8D25:`,g.message),S.delete(t)}}else e.info(`[runtime-bridge] \u2605 \u4FDD\u7559 ${a} \u4E2A SDK \u4F1A\u8BDD\uFF0C\u4E0D\u5728\u91CD\u542F\u6062\u590D\u573A\u666F\u4E2D\u7EC8\u6B62 Agent \u8FDB\u7A0B`);const l=se.size;u.closePtySessions?(e.info(`[runtime-bridge] \u6B63\u5728\u505C\u6B62 ${l} \u4E2A PTY \u4F1A\u8BDD...`),ne("shutdown")):e.info(`[runtime-bridge] \u2605 \u4FDD\u7559 ${l} \u4E2A PTY \u4F1A\u8BDD\uFF0C\u4E0D\u5728\u91CD\u542F\u6062\u590D\u573A\u666F\u4E2D\u5173\u95ED\u7EC8\u7AEF\u8FDB\u7A0B`),e.info("[runtime-bridge] \u6B63\u5728\u505C\u6B62\u5B64\u513F\u8FDB\u7A0B\u76D1\u63A7...");try{const c=(await import("file://"+require("path").join(__dirname,"..","package","acode","dist","background-command-manager.js")).catch(()=>({backgroundCommandManager:null}))).backgroundCommandManager;c&&(e.info("[runtime-bridge] \u6B63\u5728\u6E05\u7406\u540E\u53F0\u547D\u4EE4..."),await c.disposeAll())}catch(t){e.warn("[runtime-bridge] \u540E\u53F0\u547D\u4EE4\u6E05\u7406\u5931\u8D25: %s",t?.message)}if(fe(),u.terminateResidualProcesses&&(e.info("[runtime-bridge] \u7B49\u5F85\u8FDB\u7A0B\u5B8C\u5168\u7EC8\u6B62..."),await new Promise(t=>setTimeout(t,1e3))),u.terminateResidualProcesses)try{const{detectOrphanProcesses:t,terminateProcessTree:o}=await import("./services/process-detector.js"),{loadPersistedSessions:c}=await import("./services/terminal-persistence.js"),g=await c();if(g.length>0){const p=await t(g.map(m=>({agentId:m.agentId,pid:m.pid,workspacePath:m.workspacePath,command:m.command})));if(p.length>0){e.warn(`[runtime-bridge] \u68C0\u6D4B\u5230 ${p.length} \u4E2A\u6B8B\u7559\u8FDB\u7A0B\uFF0C\u6B63\u5728\u5F3A\u5236\u7EC8\u6B62...`);for(const m of p)if(m.process.pid){const A=await o(m.process.pid);e.info(`[runtime-bridge] \u5DF2\u5F3A\u5236\u7EC8\u6B62\u6B8B\u7559\u8FDB\u7A0B\u6811\uFF1AagentId=${m.agentId}, PID=${m.process.pid}, \u7EC8\u6B62\u4E86 ${A.terminated} \u4E2A\u8FDB\u7A0B`)}}}}catch(t){const o=t;e.warn("[runtime-bridge] \u6B8B\u7559\u8FDB\u7A0B\u68C0\u67E5\u5931\u8D25:",o.message)}else e.info("[runtime-bridge] \u2605 \u4FDD\u7559\u6A21\u5F0F\u8DF3\u8FC7\u6B8B\u7559\u8FDB\u7A0B\u5F3A\u5236\u7EC8\u6B62\uFF0C\u7B49\u5F85\u8C03\u5EA6\u4E2D\u5FC3\u6062\u590D\u4F1A\u8BDD");if(u.unregisterInstance){e.info("[runtime-bridge] \u6B63\u5728\u6CE8\u9500\u5B9E\u4F8B...");try{await we()}catch(t){const o=t;e.error("[runtime-bridge] \u6CE8\u9500\u5B9E\u4F8B\u5931\u8D25:",o.message)}}else e.info("[runtime-bridge] \u2605 \u4FDD\u7559\u6A21\u5F0F\u8DF3\u8FC7\u5B9E\u4F8B\u6CE8\u9500\uFF0C\u907F\u514D\u8C03\u5EA6\u4E2D\u5FC3\u5C06 Agent \u6807\u8BB0\u4E3A stopped");if(Se(),u.stopTunnelClient&&(e.info("[runtime-bridge] \u6B63\u5728\u5173\u95ED\u96A7\u9053\u5BA2\u6237\u7AEF..."),Re()),u.clearPersistedSessions){e.info("[runtime-bridge] \u6B63\u5728\u6E05\u7A7A\u6301\u4E45\u5316\u4F1A\u8BDD\u72B6\u6001...");try{await $([])}catch(t){const o=t;e.error("[runtime-bridge] \u6E05\u7A7A\u6301\u4E45\u5316\u72B6\u6001\u5931\u8D25:",o.message)}}else e.info("[runtime-bridge] \u2605 \u4FDD\u7559\u6301\u4E45\u5316\u4F1A\u8BDD\u72B6\u6001\uFF08aws-mcp-server \u91CD\u542F\u6062\u590D\u573A\u666F\uFF09");try{await Te(),e.info("[runtime-bridge] browser \u5DE5\u5177\u6808\u5DF2\u6E05\u7406")}catch(t){e.warn("[runtime-bridge] browser \u5DE5\u5177\u6808\u6E05\u7406\u5931\u8D25:",t.message)}const d=Date.now()-f;e.info(`[runtime-bridge] \u4F18\u96C5\u5173\u95ED\u5B8C\u6210 (\u8017\u65F6 ${d}ms)\uFF0C\u505C\u6B62 ${a} SDK \u4F1A\u8BDD`),i.close(()=>{e.info("[runtime-bridge] HTTP \u670D\u52A1\u5668\u5DF2\u5173\u95ED"),process.exit(process.exitCode||0)}),setTimeout(()=>{e.warn("[runtime-bridge] \u4F18\u96C5\u5173\u95ED\u8D85\u65F6\uFF0C\u5F3A\u5236\u9000\u51FA"),process.exit(1)},15e3)}catch(a){const l=a;e.error("[runtime-bridge] \u4F18\u96C5\u5173\u95ED\u8FC7\u7A0B\u4E2D\u53D1\u751F\u9519\u8BEF:",l),process.exit(1)}}Ce.reconcileZombies().then(r=>{r>0&&e.info(`[runtime-bridge] \u5DF2\u6E05\u7406 ${r} \u4E2A\u50F5\u5C38 sub-agent \u8BB0\u5F55`)}).catch(r=>{e.warn("[runtime-bridge] \u6E05\u7406\u50F5\u5C38 sub-agent \u8BB0\u5F55\u5931\u8D25:",r.message)});const w=Oe(),v=x.join(M.tmpdir(),"agentswork-runtime-bridge",".preserve-sessions");function R(){try{if(E(v)){const r=B(v,"utf-8");return JSON.parse(r).preserveSessions===!0}}catch{}return!1}K(async(r,i)=>{await b(r,w,i)}),process.on("SIGTERM",()=>{const r=R();b("SIGTERM",w,r)}),process.on("SIGINT",()=>{const r=R();b("SIGINT",w,r)}),process.platform==="win32"&&process.on("SIGBREAK",()=>{const r=R();b("SIGBREAK",w,r)}),process.on("uncaughtException",r=>{e.error("[runtime-bridge] \u672A\u6355\u83B7\u5F02\u5E38:",r),b("uncaughtException",w)}),process.on("unhandledRejection",r=>{e.error("[runtime-bridge] \u672A\u5904\u7406\u7684 Promise \u62D2\u7EDD:",r)});
|
|
2
|
+
import I from"express";import B from"cors";import{existsSync as D,readFileSync as E}from"node:fs";import x from"node:path";import M from"node:os";import{allowedCorsOrigins as y,port as h,validateProductionToken as O}from"./config.js";import{propertiesRouter as G}from"./routes/properties.js";import{ymlRouter as _}from"./routes/yml.js";import{instanceRouter as F,setGracefulShutdownFn as K}from"./routes/instance.js";import{skillsRouter as L}from"./routes/skills.js";import{mcpRouter as N}from"./routes/mcp.js";import{terminalRouter as j,sdkSessions as S}from"./routes/terminal.js";import{sessionsRouter as W}from"./routes/sessions.js";import{gitRouter as U}from"./routes/git.js";import{fileSnapshotRouter as z}from"./routes/file-snapshot.js";import{acodeTodosRouter as J}from"./routes/acode-todos.js";import{backgroundTasksRouter as Y}from"./routes/background-tasks.js";import{subAgentsRouter as q}from"./routes/sub-agents.js";import{browserSessionsRouter as H}from"./routes/browser-sessions.js";import{browserListenersRouter as Z}from"./routes/browser-listeners.js";import{fileBrowserRouter as Q}from"./routes/file-browser.js";import{aiSourcesRouter as V}from"./routes/ai-sources.js";import{processesRouter as X}from"./routes/processes.js";import{systemMetricsRouter as ee}from"./routes/system-metrics.js";import{taskContextRouter as re}from"./routes/task-context.js";import{fileDiffRollbackRouter as te}from"./routes/file-diff-rollback.js";import{attachPtyWebSocketServer as ie,closeAllPtySessions as ne,ptyRouter as oe,ptySessions as se}from"./routes/pty.js";import{runtimeBindingRouter as ae,logRuntimeBindingStartupState as me}from"./routes/runtime-binding.js";import{dashboardRouter as ue}from"./routes/dashboard.js";import{eventsRouter as ce}from"./routes/events.js";import{attachRemoteDesktopWebSocketServer as de}from"./remote-desktop/index.js";import{attachBrowserWebSocketServer as ge}from"./browser/browser-ws-bridge.js";import{loadPersistedSessions as P,savePersistedSessions as $}from"./services/terminal-persistence.js";import{detectOrphanProcesses as pe}from"./services/process-detector.js";import{startOrphanMonitor as fe,stopOrphanMonitor as le}from"./services/orphan-monitor.js";import{getAgentProcessManager as k}from"./services/agent-process-manager.js";import{adapterRegistry as be}from"./adapter/index.js";import{logger as e}from"./utils/logger.js";import{autoRegister as we,unregister as he,bridgeRestartCleanup as Se,cancelBackgroundRegisterRetries as Re}from"./services/auto-register.js";import{stopTunnelClient as Ie}from"./services/tunnel-client.js";import{ensureAwsClientAgentMcpReleased as ye}from"./services/aws-client-agent-mcp.js";import{ensureAcodePackageReleased as Pe}from"./services/acode-package.js";import{ensureStartupConfig as $e}from"./services/startup-config-wizard.js";import{handleCliCommand as ke}from"./services/cli-commands.js";import{migrateOldPathsOnStartup as Ce}from"./services/legacy-path-migration.js";import{subAgentStore as Te}from"./services/sub-agent-manager-instance.js";import{disposeBrowserSessionManager as ve}from"./services/browser-session-manager.js";import{buildGracefulShutdownPlan as Ae,shouldCleanupPersistedSessionsOnStartup as Be}from"./services/runtime-lifecycle-policy.js";import{deliverPendingBridgeLifecycleNotifications as De}from"./services/lifecycle-state.js";const C=await ke();C.handled&&process.exit(C.exitCode),await $e(),O(),ye(),Pe(),Ce(),me();async function Ee(){try{if(await we())e.info("[runtime-bridge] \u81EA\u52A8\u6CE8\u518C\u6210\u529F");else{const{loadConfig:i}=await import("./services/auto-register.js"),s=i();!!s.userKey&&s.enabled?e.warn("[runtime-bridge] \u81EA\u52A8\u6CE8\u518C\u6682\u65F6\u5931\u8D25\uFF0C\u5C06\u5728\u540E\u53F0\u6301\u7EED\u91CD\u8BD5\u76F4\u5230\u4E0E\u8C03\u5EA6\u4E2D\u5FC3\u5EFA\u7ACB\u8FDE\u63A5"):(e.info("[runtime-bridge] \u81EA\u52A8\u6CE8\u518C\u672A\u914D\u7F6E\uFF0C\u7EE7\u7EED\u542F\u52A8\u670D\u52A1"),e.info("[runtime-bridge] \u8981\u542F\u7528\u81EA\u52A8\u6CE8\u518C\uFF0C\u8BF7\u521B\u5EFA\u914D\u7F6E\u6587\u4EF6 ~/.aws-bridge/config.json"))}}catch(r){const i=r;e.warn("[runtime-bridge] \u81EA\u52A8\u6CE8\u518C\u51FA\u9519:",i.message)}}Ee().then(()=>xe()).then(()=>De()).then(()=>{e.info("[runtime-bridge] Bridge \u751F\u547D\u5468\u671F\u901A\u77E5\u540C\u6B65\u5B8C\u6210")}).catch(r=>{e.warn("[runtime-bridge] \u81EA\u52A8\u6CE8\u518C\u6216\u6E05\u7406\u51FA\u9519:",r)});async function xe(){try{if(process.env.AWS_BRIDGE_RESTART_CLEANUP!=="true"){e.info("[runtime-bridge] \u8DF3\u8FC7 Bridge \u91CD\u542F\u6E05\u7406\uFF0C\u4FDD\u7559 Agent \u72B6\u6001\u4F9B\u8C03\u5EA6\u4E2D\u5FC3\u6062\u590D");return}const{getRegistrationState:r}=await import("./services/auto-register.js"),i=r();if(!i.registered||!i.instanceId){e.info("[runtime-bridge] \u5B9E\u4F8B\u672A\u6CE8\u518C\uFF0C\u8DF3\u8FC7 Bridge \u91CD\u542F\u6E05\u7406");return}e.info("[runtime-bridge] \u2605 Bridge \u91CD\u542F\u6E05\u7406\u5DF2\u663E\u5F0F\u542F\u7528\uFF0C\u6B63\u5728\u901A\u77E5\u8C03\u5EA6\u4E2D\u5FC3\u6E05\u7406 Agent \u72B6\u6001...");const s=await Se();s.success?e.info(`[runtime-bridge] \u2605 Bridge \u91CD\u542F\u6E05\u7406\u6210\u529F\uFF0C\u6E05\u7406\u4E86 ${s.agentCount||0} \u4E2A Agent`):e.warn(`[runtime-bridge] \u2605 Bridge \u91CD\u542F\u6E05\u7406\u5931\u8D25: ${s.error}`)}catch(r){const i=r;e.warn("[runtime-bridge] Bridge \u91CD\u542F\u6E05\u7406\u51FA\u9519:",i.message)}}async function Me(){try{const r=await P();if(r.length===0){e.info("[runtime-bridge] \u65E0\u6301\u4E45\u5316\u4F1A\u8BDD\uFF0C\u8DF3\u8FC7\u8FDB\u7A0B\u6CE8\u518C\u8868\u91CD\u5EFA");return}await k().rebuildRegistry(r.map(s=>({agentId:s.agentId,sessionId:s.sessionId,pid:s.pid,workspacePath:s.workspacePath,command:s.command,mode:"sdk"}))),e.info(`[runtime-bridge] \u8FDB\u7A0B\u6CE8\u518C\u8868\u91CD\u5EFA\u5B8C\u6210: ${r.length} \u6761\u8BB0\u5F55`)}catch(r){const i=r;e.warn("[runtime-bridge] \u8FDB\u7A0B\u6CE8\u518C\u8868\u91CD\u5EFA\u5931\u8D25:",i.message)}}Me().catch(r=>{e.warn("[runtime-bridge] \u8FDB\u7A0B\u6CE8\u518C\u8868\u91CD\u5EFA\u51FA\u9519:",r)});async function Oe(){try{const r=await import("node:fs/promises"),i=await import("node:path"),s=await import("node:os"),f=i.join(s.tmpdir(),"agentswork-runtime-bridge",".preserve-sessions");let u=!1;try{const t=await r.readFile(f,"utf-8");u=JSON.parse(t).preserveSessions===!0,await r.unlink(f),e.info(`[runtime-bridge] \u2605 \u68C0\u6D4B\u5230\u4FDD\u7559\u4F1A\u8BDD\u6807\u8BB0\uFF0CpreserveSessions=${u}`)}catch{}const a=await P();if(a.length===0){e.info("[runtime-bridge] \u542F\u52A8\u65F6\u65E0\u6301\u4E45\u5316\u4F1A\u8BDD\uFF0C\u65E0\u9700\u68C0\u6D4B\u5B64\u513F\u8FDB\u7A0B");return}if(!Be(u)){e.info(`[runtime-bridge] \u2605 \u4FDD\u7559 ${a.length} \u4E2A\u6301\u4E45\u5316\u4F1A\u8BDD\u5E76\u91CD\u5EFA\u8FDB\u7A0B\u6CE8\u518C\u8868`),await k().rebuildRegistry(a.map(o=>({agentId:o.agentId,sessionId:o.sessionId,pid:o.pid,workspacePath:o.workspacePath,command:o.command,mode:"sdk"})));return}e.info(`[runtime-bridge] \u2605 \u5DF2\u663E\u5F0F\u542F\u7528\u542F\u52A8\u6E05\u7406\uFF0C\u68C0\u6D4B ${a.length} \u4E2A\u6301\u4E45\u5316\u4F1A\u8BDD\u7684\u5B64\u513F\u8FDB\u7A0B...`);const d=await pe(a.map(t=>({agentId:t.agentId,pid:t.pid,workspacePath:t.workspacePath,command:t.command})));if(d.length>0){e.warn(`[runtime-bridge] \u2605 \u68C0\u6D4B\u5230 ${d.length} \u4E2A\u5B64\u513F\u8FDB\u7A0B\u4ECD\u5728\u8FD0\u884C\uFF1A`);for(const t of d)e.warn(` - agentId=${t.agentId}, pid=${t.process.pid}, command=${t.process.command?.slice(0,50)}`);e.info("[runtime-bridge] \u6B63\u5728\u81EA\u52A8\u6E05\u7406\u6240\u6709\u5B64\u513F\u8FDB\u7A0B...");for(const t of d)try{if(t.process.pid)if(process.platform==="win32"){const{execSync:o}=await import("node:child_process");o(`taskkill /PID ${t.process.pid} /T /F`,{encoding:"utf8",timeout:3e3}),e.info(`[runtime-bridge] \u5DF2\u81EA\u52A8\u7EC8\u6B62\u5B64\u513F\u8FDB\u7A0B: agentId=${t.agentId}, PID=${t.process.pid}`)}else process.kill(t.process.pid,"SIGKILL"),e.info(`[runtime-bridge] \u5DF2\u81EA\u52A8\u7EC8\u6B62\u5B64\u513F\u8FDB\u7A0B: agentId=${t.agentId}, PID=${t.process.pid}`)}catch(o){const c=o;e.warn(`[runtime-bridge] \u81EA\u52A8\u7EC8\u6B62\u5B64\u513F\u8FDB\u7A0B\u5931\u8D25: agentId=${t.agentId}, PID=${t.process.pid}, error=${c.message}`)}await new Promise(t=>setTimeout(t,1e3))}await $([]),e.info(`[runtime-bridge] \u2605 \u542F\u52A8\u6E05\u7406\u5B8C\u6210\uFF0C\u5DF2\u6E05\u7A7A\u6240\u6709\u6301\u4E45\u5316\u4F1A\u8BDD\uFF08\u6E05\u7406\u4E86 ${d.length} \u4E2A\u5B64\u513F\u8FDB\u7A0B\uFF09`)}catch(r){const i=r;e.warn("[runtime-bridge] \u542F\u52A8\u65F6\u5B64\u513F\u8FDB\u7A0B\u68C0\u6D4B\u5931\u8D25:",i.message)}}Oe().catch(r=>{e.warn("[runtime-bridge] \u5B64\u513F\u8FDB\u7A0B\u68C0\u6D4B\u51FA\u9519:",r)}),fe().catch(r=>{e.warn("[runtime-bridge] \u542F\u52A8\u5B64\u513F\u8FDB\u7A0B\u76D1\u63A7\u5931\u8D25:",r)});const n=I();n.use(B({origin(r,i){if(!r){i(null,!0);return}if(y.includes("*")){i(null,!0);return}if(y.includes(r)){i(null,!0);return}try{if(new URL(r).port===String(h)){i(null,!0);return}}catch{}i(new Error(`[runtime-bridge] CORS origin is not allowed: ${r}`))}})),n.use(I.json({limit:"1mb"})),n.use("/runtime",ae),n.use("/runtime",G),n.use("/runtime",_),n.use("/runtime",F),n.use("/runtime",L),n.use("/runtime",N),n.use("/runtime",j),n.use("/runtime",W),n.use("/runtime",X),n.use("/runtime",ee),n.use("/runtime",ce),n.use("/runtime",U),n.use("/runtime",z),n.use("/runtime",J),n.use("/runtime",Y),n.use("/runtime",q),n.use("/runtime",H),n.use("/runtime",Z),n.use("/runtime",V),n.use("/runtime",re),n.use("/runtime",te),n.use("/pty",oe),n.use("/",ue),n.use("/api/file-browser",Q);function Ge(){const r=n.listen(h,()=>{e.info(`[runtime-bridge] listening on ${h}`)});return ie(r),de(r),ge(r),r.on("error",i=>{if(i.code==="EADDRINUSE"){e.error(`[runtime-bridge] port ${h} is already in use. Stop the existing runtime-bridge process or set AWS_RUNTIME_BRIDGE_PORT to another port before starting.`),process.exitCode=1;return}e.error("[runtime-bridge] failed to start server:",i),process.exitCode=1}),r}let T=!1;async function b(r,i,s=!1){if(T){e.info(`[runtime-bridge] \u5DF2\u5728\u5173\u95ED\u4E2D\uFF0C\u5FFD\u7565 ${r}`);return}T=!0,s||R()&&(s=!0,e.info("[runtime-bridge] \u2605 \u68C0\u6D4B\u5230 .preserve-sessions \u6807\u8BB0\u6587\u4EF6\uFF0C\u81EA\u52A8\u5347\u7EA7\u4E3A\u4FDD\u7559\u4F1A\u8BDD\u6A21\u5F0F")),e.info(`[runtime-bridge] \u6536\u5230 ${r} \u4FE1\u53F7\uFF0C\u5F00\u59CB\u4F18\u96C5\u5173\u95ED... (preserveSessions=${s})`);const f=Date.now(),u=Ae(s);try{const a=S.size;if(u.terminateSdkSessions){e.info(`[runtime-bridge] \u6B63\u5728\u505C\u6B62 ${a} \u4E2A SDK \u4F1A\u8BDD...`);for(const[t,o]of S.entries())try{const c=o.providerId||"claude-code",g=be.get(c);let p="";try{const m=g.getSessionPid?.(t);m&&(p=` (PID: ${m})`)}catch{}await g.terminateSession(t),e.info(`[runtime-bridge] SDK \u4F1A\u8BDD ${t} \u5DF2\u7EC8\u6B62${p}`),S.delete(t)}catch(c){const g=c;e.error(`[runtime-bridge] SDK \u4F1A\u8BDD ${t} \u7EC8\u6B62\u5931\u8D25:`,g.message),S.delete(t)}}else e.info(`[runtime-bridge] \u2605 \u4FDD\u7559 ${a} \u4E2A SDK \u4F1A\u8BDD\uFF0C\u4E0D\u5728\u91CD\u542F\u6062\u590D\u573A\u666F\u4E2D\u7EC8\u6B62 Agent \u8FDB\u7A0B`);const l=se.size;u.closePtySessions?(e.info(`[runtime-bridge] \u6B63\u5728\u505C\u6B62 ${l} \u4E2A PTY \u4F1A\u8BDD...`),ne("shutdown")):e.info(`[runtime-bridge] \u2605 \u4FDD\u7559 ${l} \u4E2A PTY \u4F1A\u8BDD\uFF0C\u4E0D\u5728\u91CD\u542F\u6062\u590D\u573A\u666F\u4E2D\u5173\u95ED\u7EC8\u7AEF\u8FDB\u7A0B`),e.info("[runtime-bridge] \u6B63\u5728\u505C\u6B62\u5B64\u513F\u8FDB\u7A0B\u76D1\u63A7...");try{const c=(await import("file://"+require("path").join(__dirname,"..","package","acode","dist","background-command-manager.js")).catch(()=>({backgroundCommandManager:null}))).backgroundCommandManager;c&&(e.info("[runtime-bridge] \u6B63\u5728\u6E05\u7406\u540E\u53F0\u547D\u4EE4..."),await c.disposeAll())}catch(t){e.warn("[runtime-bridge] \u540E\u53F0\u547D\u4EE4\u6E05\u7406\u5931\u8D25: %s",t?.message)}if(le(),u.terminateResidualProcesses&&(e.info("[runtime-bridge] \u7B49\u5F85\u8FDB\u7A0B\u5B8C\u5168\u7EC8\u6B62..."),await new Promise(t=>setTimeout(t,1e3))),u.terminateResidualProcesses)try{const{detectOrphanProcesses:t,terminateProcessTree:o}=await import("./services/process-detector.js"),{loadPersistedSessions:c}=await import("./services/terminal-persistence.js"),g=await c();if(g.length>0){const p=await t(g.map(m=>({agentId:m.agentId,pid:m.pid,workspacePath:m.workspacePath,command:m.command})));if(p.length>0){e.warn(`[runtime-bridge] \u68C0\u6D4B\u5230 ${p.length} \u4E2A\u6B8B\u7559\u8FDB\u7A0B\uFF0C\u6B63\u5728\u5F3A\u5236\u7EC8\u6B62...`);for(const m of p)if(m.process.pid){const A=await o(m.process.pid);e.info(`[runtime-bridge] \u5DF2\u5F3A\u5236\u7EC8\u6B62\u6B8B\u7559\u8FDB\u7A0B\u6811\uFF1AagentId=${m.agentId}, PID=${m.process.pid}, \u7EC8\u6B62\u4E86 ${A.terminated} \u4E2A\u8FDB\u7A0B`)}}}}catch(t){const o=t;e.warn("[runtime-bridge] \u6B8B\u7559\u8FDB\u7A0B\u68C0\u67E5\u5931\u8D25:",o.message)}else e.info("[runtime-bridge] \u2605 \u4FDD\u7559\u6A21\u5F0F\u8DF3\u8FC7\u6B8B\u7559\u8FDB\u7A0B\u5F3A\u5236\u7EC8\u6B62\uFF0C\u7B49\u5F85\u8C03\u5EA6\u4E2D\u5FC3\u6062\u590D\u4F1A\u8BDD");if(u.unregisterInstance){e.info("[runtime-bridge] \u6B63\u5728\u6CE8\u9500\u5B9E\u4F8B...");try{await he()}catch(t){const o=t;e.error("[runtime-bridge] \u6CE8\u9500\u5B9E\u4F8B\u5931\u8D25:",o.message)}}else e.info("[runtime-bridge] \u2605 \u4FDD\u7559\u6A21\u5F0F\u8DF3\u8FC7\u5B9E\u4F8B\u6CE8\u9500\uFF0C\u907F\u514D\u8C03\u5EA6\u4E2D\u5FC3\u5C06 Agent \u6807\u8BB0\u4E3A stopped");if(Re(),u.stopTunnelClient&&(e.info("[runtime-bridge] \u6B63\u5728\u5173\u95ED\u96A7\u9053\u5BA2\u6237\u7AEF..."),Ie()),u.clearPersistedSessions){e.info("[runtime-bridge] \u6B63\u5728\u6E05\u7A7A\u6301\u4E45\u5316\u4F1A\u8BDD\u72B6\u6001...");try{await $([])}catch(t){const o=t;e.error("[runtime-bridge] \u6E05\u7A7A\u6301\u4E45\u5316\u72B6\u6001\u5931\u8D25:",o.message)}}else e.info("[runtime-bridge] \u2605 \u4FDD\u7559\u6301\u4E45\u5316\u4F1A\u8BDD\u72B6\u6001\uFF08aws-mcp-server \u91CD\u542F\u6062\u590D\u573A\u666F\uFF09");try{await ve(),e.info("[runtime-bridge] browser \u5DE5\u5177\u6808\u5DF2\u6E05\u7406")}catch(t){e.warn("[runtime-bridge] browser \u5DE5\u5177\u6808\u6E05\u7406\u5931\u8D25:",t.message)}const d=Date.now()-f;e.info(`[runtime-bridge] \u4F18\u96C5\u5173\u95ED\u5B8C\u6210 (\u8017\u65F6 ${d}ms)\uFF0C\u505C\u6B62 ${a} SDK \u4F1A\u8BDD`),i.close(()=>{e.info("[runtime-bridge] HTTP \u670D\u52A1\u5668\u5DF2\u5173\u95ED"),process.exit(process.exitCode||0)}),setTimeout(()=>{e.warn("[runtime-bridge] \u4F18\u96C5\u5173\u95ED\u8D85\u65F6\uFF0C\u5F3A\u5236\u9000\u51FA"),process.exit(1)},15e3)}catch(a){const l=a;e.error("[runtime-bridge] \u4F18\u96C5\u5173\u95ED\u8FC7\u7A0B\u4E2D\u53D1\u751F\u9519\u8BEF:",l),process.exit(1)}}Te.reconcileZombies().then(r=>{r>0&&e.info(`[runtime-bridge] \u5DF2\u6E05\u7406 ${r} \u4E2A\u50F5\u5C38 sub-agent \u8BB0\u5F55`)}).catch(r=>{e.warn("[runtime-bridge] \u6E05\u7406\u50F5\u5C38 sub-agent \u8BB0\u5F55\u5931\u8D25:",r.message)});const w=Ge(),v=x.join(M.tmpdir(),"agentswork-runtime-bridge",".preserve-sessions");function R(){try{if(D(v)){const r=E(v,"utf-8");return JSON.parse(r).preserveSessions===!0}}catch{}return!1}K(async(r,i)=>{await b(r,w,i)}),process.on("SIGTERM",()=>{const r=R();b("SIGTERM",w,r)}),process.on("SIGINT",()=>{const r=R();b("SIGINT",w,r)}),process.platform==="win32"&&process.on("SIGBREAK",()=>{const r=R();b("SIGBREAK",w,r)}),process.on("uncaughtException",r=>{e.error("[runtime-bridge] \u672A\u6355\u83B7\u5F02\u5E38:",r),b("uncaughtException",w)}),process.on("unhandledRejection",r=>{e.error("[runtime-bridge] \u672A\u5904\u7406\u7684 Promise \u62D2\u7EDD:",r)});
|
|
3
3
|
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{Router as
|
|
1
|
+
import{Router as f}from"express";import{createBrowserConnectToken as w}from"../browser/browser-connect-token.js";import{DEFAULT_BROWSER_ID as I}from"../browser/types.js";import{validateToken as i}from"../middleware/auth.js";import{closeBrowserSessionById as b,isBrowserSessionManagerStarted as d,listBrowserWsUrls as g}from"../services/browser-session-manager.js";import{createLogger as k}from"../utils/logger.js";const c=k("browser-sessions"),m=f();m.post("/browser-sessions/:agentId/connect-token",i,(o,s)=>{const r=String(o.params.agentId??"").trim();if(!r){s.status(400).json({ok:!1,error:"agentId is required"});return}const e=o.body??{},t=typeof e.browserId=="string"&&e.browserId.trim()?e.browserId.trim():I;try{if(d()&&!g(r).some(u=>u.browserId===t)){s.status(404).json({ok:!1,error:"browser session not found"});return}const n=w(r,t);if(!n){s.status(500).json({ok:!1,error:"failed to create token"});return}s.json({ok:!0,...n})}catch(n){const a=n;c.error("[browser-sessions] \u7B7E\u53D1\u8FDE\u63A5\u4EE4\u724C\u5931\u8D25: %s",a.message),s.status(500).json({ok:!1,error:a.message})}}),m.get("/browser-sessions/:agentId",i,async(o,s)=>{const r=String(o.params.agentId??"");if(!r.trim()){s.status(400).json({ok:!1,error:"agentId is required"});return}try{if(!d()){s.json({ok:!0,agentId:r,sessions:[]});return}const e=g(r);s.json({ok:!0,agentId:r,sessions:e})}catch(e){const t=e;c.error("[browser-sessions] \u5217\u8868\u5931\u8D25: %s",t.message),s.status(500).json({ok:!1,error:t.message})}}),m.delete("/browser-sessions/:agentId/:browserId",i,async(o,s)=>{const r=String(o.params.agentId??""),e=String(o.params.browserId??"");if(!r.trim()||!e.trim()){s.status(400).json({ok:!1,error:"agentId and browserId are required"});return}try{if(!d()){s.json({ok:!0,agentId:r,browserId:e});return}await b(r,e),s.json({ok:!0,agentId:r,browserId:e})}catch(t){const n=t;c.error("[browser-sessions] \u5173\u95ED\u5931\u8D25: %s",n.message),s.status(500).json({ok:!1,error:n.message})}});export{m as browserSessionsRouter};
|
|
2
2
|
|