@hehanlin/open-agent-bridge 0.6.3
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/README.md +36 -0
- package/dist/adapters/acpAdapter.d.ts +45 -0
- package/dist/adapters/acpAdapter.js +171 -0
- package/dist/adapters/acpAdapter.js.map +1 -0
- package/dist/adapters/adapter.d.ts +50 -0
- package/dist/adapters/adapter.js +2 -0
- package/dist/adapters/adapter.js.map +1 -0
- package/dist/adapters/registry.d.ts +7 -0
- package/dist/adapters/registry.js +34 -0
- package/dist/adapters/registry.js.map +1 -0
- package/dist/agent/agentManager.d.ts +45 -0
- package/dist/agent/agentManager.js +110 -0
- package/dist/agent/agentManager.js.map +1 -0
- package/dist/cli.d.ts +13 -0
- package/dist/cli.js +178 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +15 -0
- package/dist/config.js +39 -0
- package/dist/config.js.map +1 -0
- package/dist/detect/acpProbe.d.ts +5 -0
- package/dist/detect/acpProbe.js +61 -0
- package/dist/detect/acpProbe.js.map +1 -0
- package/dist/detect/frameworkDetector.d.ts +30 -0
- package/dist/detect/frameworkDetector.js +88 -0
- package/dist/detect/frameworkDetector.js.map +1 -0
- package/dist/frontier/frontierClient.d.ts +37 -0
- package/dist/frontier/frontierClient.js +103 -0
- package/dist/frontier/frontierClient.js.map +1 -0
- package/dist/frontier/frontierKey.d.ts +19 -0
- package/dist/frontier/frontierKey.js +45 -0
- package/dist/frontier/frontierKey.js.map +1 -0
- package/dist/frontier/health.d.ts +18 -0
- package/dist/frontier/health.js +29 -0
- package/dist/frontier/health.js.map +1 -0
- package/dist/frontier/watchdog.d.ts +23 -0
- package/dist/frontier/watchdog.js +47 -0
- package/dist/frontier/watchdog.js.map +1 -0
- package/dist/fsx/localFs.d.ts +15 -0
- package/dist/fsx/localFs.js +29 -0
- package/dist/fsx/localFs.js.map +1 -0
- package/dist/fsx/safePath.d.ts +1 -0
- package/dist/fsx/safePath.js +44 -0
- package/dist/fsx/safePath.js.map +1 -0
- package/dist/hub/asyncQueue.d.ts +6 -0
- package/dist/hub/asyncQueue.js +30 -0
- package/dist/hub/asyncQueue.js.map +1 -0
- package/dist/hub/hub.d.ts +55 -0
- package/dist/hub/hub.js +328 -0
- package/dist/hub/hub.js.map +1 -0
- package/dist/install/autostart.d.ts +20 -0
- package/dist/install/autostart.js +76 -0
- package/dist/install/autostart.js.map +1 -0
- package/dist/mock/mockRun.d.ts +9 -0
- package/dist/mock/mockRun.js +94 -0
- package/dist/mock/mockRun.js.map +1 -0
- package/dist/store/seq.d.ts +12 -0
- package/dist/store/seq.js +55 -0
- package/dist/store/seq.js.map +1 -0
- package/dist/store/store.d.ts +26 -0
- package/dist/store/store.js +88 -0
- package/dist/store/store.js.map +1 -0
- package/dist/types.d.ts +36 -0
- package/dist/types.js +9 -0
- package/dist/types.js.map +1 -0
- package/package.json +32 -0
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
export async function exchangeFrontierKey(deps, opts) {
|
|
2
|
+
const response = await deps.fetchImpl(`${trimTrailingSlash(opts.serverBase)}/api/open_agent/device/frontier_key`, {
|
|
3
|
+
method: 'POST',
|
|
4
|
+
headers: {
|
|
5
|
+
Authorization: `Bearer ${opts.deviceToken}`,
|
|
6
|
+
'Content-Type': 'application/json'
|
|
7
|
+
},
|
|
8
|
+
body: JSON.stringify({ hostname: opts.hostname, platform: opts.platform, frameworks: opts.frameworks })
|
|
9
|
+
});
|
|
10
|
+
const body = await response.text();
|
|
11
|
+
if (!response.ok) {
|
|
12
|
+
throw new Error(`frontier_key exchange failed: HTTP ${response.status} ${body}`);
|
|
13
|
+
}
|
|
14
|
+
const parsed = JSON.parse(body);
|
|
15
|
+
const data = parsed.data ?? parsed;
|
|
16
|
+
return {
|
|
17
|
+
deviceId: stringField(data, 'device_id'),
|
|
18
|
+
accessKey: stringField(data, 'access_key'),
|
|
19
|
+
wsUrl: stringField(data, 'ws_url'),
|
|
20
|
+
aid: stringField(data, 'aid'),
|
|
21
|
+
fpid: stringField(data, 'fpid'),
|
|
22
|
+
serviceId: numberField(data, 'service_id')
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
export function wsOrigin(wsUrl) {
|
|
26
|
+
return new URL(wsUrl).origin;
|
|
27
|
+
}
|
|
28
|
+
function trimTrailingSlash(value) {
|
|
29
|
+
return value.replace(/\/+$/, '');
|
|
30
|
+
}
|
|
31
|
+
function stringField(data, key) {
|
|
32
|
+
const value = data[key];
|
|
33
|
+
if (typeof value !== 'string') {
|
|
34
|
+
throw new Error(`frontier_key missing string field: ${key}`);
|
|
35
|
+
}
|
|
36
|
+
return value;
|
|
37
|
+
}
|
|
38
|
+
function numberField(data, key) {
|
|
39
|
+
const value = data[key];
|
|
40
|
+
if (typeof value !== 'number') {
|
|
41
|
+
throw new Error(`frontier_key missing number field: ${key}`);
|
|
42
|
+
}
|
|
43
|
+
return value;
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=frontierKey.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frontierKey.js","sourceRoot":"","sources":["../../src/frontier/frontierKey.ts"],"names":[],"mappings":"AAWA,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,IAAiC,EACjC,IAAsH;IAEtH,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,GAAG,iBAAiB,CAAC,IAAI,CAAC,UAAU,CAAC,qCAAqC,EAAE;QAChH,MAAM,EAAE,MAAM;QACd,OAAO,EAAE;YACP,aAAa,EAAE,UAAU,IAAI,CAAC,WAAW,EAAE;YAC3C,cAAc,EAAE,kBAAkB;SACnC;QACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE,CAAC;KACxG,CAAC,CAAC;IAEH,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;IACnC,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CAAC,sCAAsC,QAAQ,CAAC,MAAM,IAAI,IAAI,EAAE,CAAC,CAAC;IACnF,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAiE,CAAC;IAChG,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,IAAI,MAAM,CAAC;IACnC,OAAO;QACL,QAAQ,EAAE,WAAW,CAAC,IAAI,EAAE,WAAW,CAAC;QACxC,SAAS,EAAE,WAAW,CAAC,IAAI,EAAE,YAAY,CAAC;QAC1C,KAAK,EAAE,WAAW,CAAC,IAAI,EAAE,QAAQ,CAAC;QAClC,GAAG,EAAE,WAAW,CAAC,IAAI,EAAE,KAAK,CAAC;QAC7B,IAAI,EAAE,WAAW,CAAC,IAAI,EAAE,MAAM,CAAC;QAC/B,SAAS,EAAE,WAAW,CAAC,IAAI,EAAE,YAAY,CAAC;KAC3C,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,KAAa;IACpC,OAAO,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC;AAC/B,CAAC;AAED,SAAS,iBAAiB,CAAC,KAAa;IACtC,OAAO,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;AACnC,CAAC;AAED,SAAS,WAAW,CAAC,IAA6B,EAAE,GAAW;IAC7D,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC;IACxB,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,MAAM,IAAI,KAAK,CAAC,sCAAsC,GAAG,EAAE,CAAC,CAAC;IAC/D,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,WAAW,CAAC,IAA6B,EAAE,GAAW;IAC7D,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC;IACxB,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,MAAM,IAAI,KAAK,CAAC,sCAAsC,GAAG,EAAE,CAAC,CAAC;IAC/D,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { JsonRpcRequest } from '../types.js';
|
|
2
|
+
export declare class HealthReporter {
|
|
3
|
+
private readonly deps;
|
|
4
|
+
private readonly opts;
|
|
5
|
+
private timer?;
|
|
6
|
+
constructor(deps: {
|
|
7
|
+
send: (m: JsonRpcRequest) => void;
|
|
8
|
+
agentsProvider: () => {
|
|
9
|
+
agentId: string;
|
|
10
|
+
status: 'online' | 'busy' | 'error';
|
|
11
|
+
}[];
|
|
12
|
+
}, opts: {
|
|
13
|
+
intervalMs: number;
|
|
14
|
+
});
|
|
15
|
+
start(): void;
|
|
16
|
+
stop(): void;
|
|
17
|
+
beat(): void;
|
|
18
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export class HealthReporter {
|
|
2
|
+
deps;
|
|
3
|
+
opts;
|
|
4
|
+
timer;
|
|
5
|
+
constructor(deps, opts) {
|
|
6
|
+
this.deps = deps;
|
|
7
|
+
this.opts = opts;
|
|
8
|
+
}
|
|
9
|
+
start() {
|
|
10
|
+
if (this.timer) {
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
this.timer = setInterval(() => this.beat(), this.opts.intervalMs);
|
|
14
|
+
}
|
|
15
|
+
stop() {
|
|
16
|
+
if (this.timer) {
|
|
17
|
+
clearInterval(this.timer);
|
|
18
|
+
this.timer = undefined;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
beat() {
|
|
22
|
+
this.deps.send({
|
|
23
|
+
jsonrpc: '2.0',
|
|
24
|
+
method: '_agent/health',
|
|
25
|
+
params: { agents: this.deps.agentsProvider() }
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=health.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"health.js","sourceRoot":"","sources":["../../src/frontier/health.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,cAAc;IAIN;IAIA;IAPX,KAAK,CAAkB;IAE/B,YACmB,IAGhB,EACgB,IAA4B;QAJ5B,SAAI,GAAJ,IAAI,CAGpB;QACgB,SAAI,GAAJ,IAAI,CAAwB;IAC5C,CAAC;IAEJ,KAAK;QACH,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACf,OAAO;QACT,CAAC;QACD,IAAI,CAAC,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IACpE,CAAC;IAED,IAAI;QACF,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACf,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC1B,IAAI,CAAC,KAAK,GAAG,SAAS,CAAC;QACzB,CAAC;IACH,CAAC;IAED,IAAI;QACF,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;YACb,OAAO,EAAE,KAAK;YACd,MAAM,EAAE,eAAe;YACvB,MAAM,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,EAAE;SAC/C,CAAC,CAAC;IACL,CAAC;CACF"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export declare class Watchdog {
|
|
2
|
+
private readonly deps;
|
|
3
|
+
private readonly opts;
|
|
4
|
+
private readonly target;
|
|
5
|
+
private timer?;
|
|
6
|
+
private lastTickAt;
|
|
7
|
+
private softBaselineAt;
|
|
8
|
+
constructor(deps: {
|
|
9
|
+
now: () => number;
|
|
10
|
+
exit: (code: number) => void;
|
|
11
|
+
env: NodeJS.ProcessEnv;
|
|
12
|
+
}, opts: {
|
|
13
|
+
softMs: number;
|
|
14
|
+
hardMs: number;
|
|
15
|
+
tickMs: number;
|
|
16
|
+
}, target: {
|
|
17
|
+
lastActivityAt(): number;
|
|
18
|
+
forceReconnect(): void;
|
|
19
|
+
});
|
|
20
|
+
start(): void;
|
|
21
|
+
stop(): void;
|
|
22
|
+
tick(): void;
|
|
23
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
export class Watchdog {
|
|
2
|
+
deps;
|
|
3
|
+
opts;
|
|
4
|
+
target;
|
|
5
|
+
timer;
|
|
6
|
+
lastTickAt;
|
|
7
|
+
softBaselineAt;
|
|
8
|
+
constructor(deps, opts, target) {
|
|
9
|
+
this.deps = deps;
|
|
10
|
+
this.opts = opts;
|
|
11
|
+
this.target = target;
|
|
12
|
+
this.lastTickAt = deps.now();
|
|
13
|
+
this.softBaselineAt = target.lastActivityAt();
|
|
14
|
+
}
|
|
15
|
+
start() {
|
|
16
|
+
if (this.timer) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
this.timer = setInterval(() => this.tick(), this.opts.tickMs);
|
|
20
|
+
}
|
|
21
|
+
stop() {
|
|
22
|
+
if (this.timer) {
|
|
23
|
+
clearInterval(this.timer);
|
|
24
|
+
this.timer = undefined;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
tick() {
|
|
28
|
+
const now = this.deps.now();
|
|
29
|
+
if (now - this.lastTickAt > this.opts.tickMs * 2) {
|
|
30
|
+
this.lastTickAt = now;
|
|
31
|
+
this.softBaselineAt = now;
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
this.lastTickAt = now;
|
|
35
|
+
const lastActivity = this.target.lastActivityAt();
|
|
36
|
+
if (now - lastActivity > this.opts.hardMs && this.deps.env.OPEN_AGENT_BRIDGE_SUPERVISED === '1') {
|
|
37
|
+
this.deps.exit(1);
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
const softAnchor = Math.max(lastActivity, this.softBaselineAt);
|
|
41
|
+
if (now - softAnchor > this.opts.softMs) {
|
|
42
|
+
this.target.forceReconnect();
|
|
43
|
+
this.softBaselineAt = now;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=watchdog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"watchdog.js","sourceRoot":"","sources":["../../src/frontier/watchdog.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,QAAQ;IAMA;IACA;IACA;IAPX,KAAK,CAAkB;IACvB,UAAU,CAAS;IACnB,cAAc,CAAS;IAE/B,YACmB,IAAiF,EACjF,IAAwD,EACxD,MAA4D;QAF5D,SAAI,GAAJ,IAAI,CAA6E;QACjF,SAAI,GAAJ,IAAI,CAAoD;QACxD,WAAM,GAAN,MAAM,CAAsD;QAE7E,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC7B,IAAI,CAAC,cAAc,GAAG,MAAM,CAAC,cAAc,EAAE,CAAC;IAChD,CAAC;IAED,KAAK;QACH,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACf,OAAO;QACT,CAAC;QACD,IAAI,CAAC,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAChE,CAAC;IAED,IAAI;QACF,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACf,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC1B,IAAI,CAAC,KAAK,GAAG,SAAS,CAAC;QACzB,CAAC;IACH,CAAC;IAED,IAAI;QACF,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;QAC5B,IAAI,GAAG,GAAG,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACjD,IAAI,CAAC,UAAU,GAAG,GAAG,CAAC;YACtB,IAAI,CAAC,cAAc,GAAG,GAAG,CAAC;YAC1B,OAAO;QACT,CAAC;QACD,IAAI,CAAC,UAAU,GAAG,GAAG,CAAC;QAEtB,MAAM,YAAY,GAAG,IAAI,CAAC,MAAM,CAAC,cAAc,EAAE,CAAC;QAClD,IAAI,GAAG,GAAG,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,4BAA4B,KAAK,GAAG,EAAE,CAAC;YAChG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,OAAO;QACT,CAAC;QAED,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE,IAAI,CAAC,cAAc,CAAC,CAAC;QAC/D,IAAI,GAAG,GAAG,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;YACxC,IAAI,CAAC,MAAM,CAAC,cAAc,EAAE,CAAC;YAC7B,IAAI,CAAC,cAAc,GAAG,GAAG,CAAC;QAC5B,CAAC;IACH,CAAC;CACF"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export declare class LocalFs {
|
|
2
|
+
private readonly workspaceRoot;
|
|
3
|
+
constructor(workspaceRoot: string);
|
|
4
|
+
readTextFile(p: {
|
|
5
|
+
path: string;
|
|
6
|
+
line?: number;
|
|
7
|
+
limit?: number;
|
|
8
|
+
}): Promise<{
|
|
9
|
+
content: string;
|
|
10
|
+
}>;
|
|
11
|
+
writeTextFile(p: {
|
|
12
|
+
path: string;
|
|
13
|
+
content: string;
|
|
14
|
+
}): Promise<void>;
|
|
15
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { dirname } from 'node:path';
|
|
3
|
+
import { resolveSafe } from './safePath.js';
|
|
4
|
+
export class LocalFs {
|
|
5
|
+
workspaceRoot;
|
|
6
|
+
constructor(workspaceRoot) {
|
|
7
|
+
this.workspaceRoot = workspaceRoot;
|
|
8
|
+
}
|
|
9
|
+
async readTextFile(p) {
|
|
10
|
+
const resolved = await resolveSafe(this.workspaceRoot, p.path);
|
|
11
|
+
const content = await readFile(resolved, 'utf8');
|
|
12
|
+
return { content: sliceLines(content, p.line, p.limit) };
|
|
13
|
+
}
|
|
14
|
+
async writeTextFile(p) {
|
|
15
|
+
const resolved = await resolveSafe(this.workspaceRoot, p.path);
|
|
16
|
+
await mkdir(dirname(resolved), { recursive: true });
|
|
17
|
+
await writeFile(resolved, p.content, 'utf8');
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
function sliceLines(content, line, limit) {
|
|
21
|
+
if (line === undefined && limit === undefined) {
|
|
22
|
+
return content;
|
|
23
|
+
}
|
|
24
|
+
const lines = content.split('\n');
|
|
25
|
+
const start = Math.max((line ?? 1) - 1, 0);
|
|
26
|
+
const end = limit === undefined ? undefined : start + Math.max(limit, 0);
|
|
27
|
+
return lines.slice(start, end).join('\n');
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=localFs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"localFs.js","sourceRoot":"","sources":["../../src/fsx/localFs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE5C,MAAM,OAAO,OAAO;IACW;IAA7B,YAA6B,aAAqB;QAArB,kBAAa,GAAb,aAAa,CAAQ;IAAG,CAAC;IAEtD,KAAK,CAAC,YAAY,CAAC,CAAkD;QACnE,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;QAC/D,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QACjD,OAAO,EAAE,OAAO,EAAE,UAAU,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC;IAC3D,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,CAAoC;QACtD,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;QAC/D,MAAM,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACpD,MAAM,SAAS,CAAC,QAAQ,EAAE,CAAC,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAC/C,CAAC;CACF;AAED,SAAS,UAAU,CAAC,OAAe,EAAE,IAAa,EAAE,KAAc;IAChE,IAAI,IAAI,KAAK,SAAS,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QAC9C,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAClC,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;IAC3C,MAAM,GAAG,GAAG,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;IACzE,OAAO,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC5C,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function resolveSafe(workspaceRoot: string, p: string): Promise<string>;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { constants } from 'node:fs';
|
|
2
|
+
import { access, realpath } from 'node:fs/promises';
|
|
3
|
+
import { basename, dirname, isAbsolute, join, relative, resolve } from 'node:path';
|
|
4
|
+
import { OaError } from '../types.js';
|
|
5
|
+
export async function resolveSafe(workspaceRoot, p) {
|
|
6
|
+
const root = await realpath(workspaceRoot);
|
|
7
|
+
const target = isAbsolute(p) ? resolve(p) : resolve(root, p);
|
|
8
|
+
const { existingAncestor, missingParts } = await closestExistingAncestor(target);
|
|
9
|
+
const ancestorReal = await realpath(existingAncestor);
|
|
10
|
+
const resolvedTarget = missingParts.length === 0 ? ancestorReal : join(ancestorReal, ...missingParts);
|
|
11
|
+
if (!isInside(root, resolvedTarget)) {
|
|
12
|
+
throw new OaError('E_FS_PATH_ESCAPE');
|
|
13
|
+
}
|
|
14
|
+
return resolvedTarget;
|
|
15
|
+
}
|
|
16
|
+
async function closestExistingAncestor(target) {
|
|
17
|
+
const missingParts = [];
|
|
18
|
+
let cursor = target;
|
|
19
|
+
while (true) {
|
|
20
|
+
try {
|
|
21
|
+
await access(cursor, constants.F_OK);
|
|
22
|
+
return { existingAncestor: cursor, missingParts };
|
|
23
|
+
}
|
|
24
|
+
catch (error) {
|
|
25
|
+
if (!isNotFound(error)) {
|
|
26
|
+
throw error;
|
|
27
|
+
}
|
|
28
|
+
const parent = dirname(cursor);
|
|
29
|
+
if (parent === cursor) {
|
|
30
|
+
throw new OaError('E_FS_PATH_ESCAPE');
|
|
31
|
+
}
|
|
32
|
+
missingParts.unshift(basename(cursor));
|
|
33
|
+
cursor = parent;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
function isInside(root, target) {
|
|
38
|
+
const rel = relative(root, target);
|
|
39
|
+
return rel === '' || (!rel.startsWith('..') && !isAbsolute(rel));
|
|
40
|
+
}
|
|
41
|
+
function isNotFound(error) {
|
|
42
|
+
return typeof error === 'object' && error !== null && 'code' in error && error.code === 'ENOENT';
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=safePath.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"safePath.js","sourceRoot":"","sources":["../../src/fsx/safePath.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACnF,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAEtC,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,aAAqB,EAAE,CAAS;IAChE,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,aAAa,CAAC,CAAC;IAC3C,MAAM,MAAM,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IAC7D,MAAM,EAAE,gBAAgB,EAAE,YAAY,EAAE,GAAG,MAAM,uBAAuB,CAAC,MAAM,CAAC,CAAC;IACjF,MAAM,YAAY,GAAG,MAAM,QAAQ,CAAC,gBAAgB,CAAC,CAAC;IACtD,MAAM,cAAc,GAAG,YAAY,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,EAAE,GAAG,YAAY,CAAC,CAAC;IAEtG,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,cAAc,CAAC,EAAE,CAAC;QACpC,MAAM,IAAI,OAAO,CAAC,kBAAkB,CAAC,CAAC;IACxC,CAAC;IACD,OAAO,cAAc,CAAC;AACxB,CAAC;AAED,KAAK,UAAU,uBAAuB,CAAC,MAAc;IACnD,MAAM,YAAY,GAAa,EAAE,CAAC;IAClC,IAAI,MAAM,GAAG,MAAM,CAAC;IAEpB,OAAO,IAAI,EAAE,CAAC;QACZ,IAAI,CAAC;YACH,MAAM,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC;YACrC,OAAO,EAAE,gBAAgB,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC;QACpD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;gBACvB,MAAM,KAAK,CAAC;YACd,CAAC;YACD,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;YAC/B,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;gBACtB,MAAM,IAAI,OAAO,CAAC,kBAAkB,CAAC,CAAC;YACxC,CAAC;YACD,YAAY,CAAC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;YACvC,MAAM,GAAG,MAAM,CAAC;QAClB,CAAC;IACH,CAAC;AACH,CAAC;AAED,SAAS,QAAQ,CAAC,IAAY,EAAE,MAAc;IAC5C,MAAM,GAAG,GAAG,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACnC,OAAO,GAAG,KAAK,EAAE,IAAI,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC;AACnE,CAAC;AAED,SAAS,UAAU,CAAC,KAAc;IAChC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,MAAM,IAAI,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,CAAC;AACnG,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export class AsyncQueue {
|
|
2
|
+
tails = new Map();
|
|
3
|
+
waiting = new Map();
|
|
4
|
+
run(key, task) {
|
|
5
|
+
const previous = this.tails.get(key);
|
|
6
|
+
const hasPrevious = this.tails.has(key);
|
|
7
|
+
if (hasPrevious) {
|
|
8
|
+
this.waiting.set(key, this.size(key) + 1);
|
|
9
|
+
}
|
|
10
|
+
const current = (previous
|
|
11
|
+
? previous.catch(() => undefined).then(async () => {
|
|
12
|
+
this.waiting.set(key, Math.max(this.size(key) - 1, 0));
|
|
13
|
+
return task();
|
|
14
|
+
})
|
|
15
|
+
: Promise.resolve().then(task));
|
|
16
|
+
const tail = current.catch(() => undefined);
|
|
17
|
+
this.tails.set(key, tail);
|
|
18
|
+
tail.finally(() => {
|
|
19
|
+
if (this.tails.get(key) === tail) {
|
|
20
|
+
this.tails.delete(key);
|
|
21
|
+
this.waiting.delete(key);
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
return current;
|
|
25
|
+
}
|
|
26
|
+
size(key) {
|
|
27
|
+
return this.waiting.get(key) ?? 0;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=asyncQueue.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"asyncQueue.js","sourceRoot":"","sources":["../../src/hub/asyncQueue.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,UAAU;IACJ,KAAK,GAAG,IAAI,GAAG,EAA4B,CAAC;IAC5C,OAAO,GAAG,IAAI,GAAG,EAAkB,CAAC;IAErD,GAAG,CAAI,GAAW,EAAE,IAAsB;QACxC,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACrC,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACxC,IAAI,WAAW,EAAE,CAAC;YAChB,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;QAC5C,CAAC;QAED,MAAM,OAAO,GAAG,CACd,QAAQ;YACN,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE;gBAC9C,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;gBACvD,OAAO,IAAI,EAAE,CAAC;YAChB,CAAC,CAAC;YACJ,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CACjC,CAAC;QAEF,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;QAC5C,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QAC1B,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE;YAChB,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,IAAI,EAAE,CAAC;gBACjC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;gBACvB,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAC3B,CAAC;QACH,CAAC,CAAC,CAAC;QACH,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,IAAI,CAAC,GAAW;QACd,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACpC,CAAC;CACF"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { Adapter } from '../adapters/adapter.js';
|
|
2
|
+
import type { AgentManager } from '../agent/agentManager.js';
|
|
3
|
+
import type { Config } from '../config.js';
|
|
4
|
+
import type { FrontierClient } from '../frontier/frontierClient.js';
|
|
5
|
+
import { SeqAllocator } from '../store/seq.js';
|
|
6
|
+
import { Store } from '../store/store.js';
|
|
7
|
+
import type { Framework, JsonRpcRequest, JsonRpcResponse } from '../types.js';
|
|
8
|
+
export interface AdapterFactory {
|
|
9
|
+
(framework: Framework, ctx: {
|
|
10
|
+
agentId: string;
|
|
11
|
+
workspace: string;
|
|
12
|
+
}): Adapter;
|
|
13
|
+
}
|
|
14
|
+
export declare class Hub {
|
|
15
|
+
private readonly deps;
|
|
16
|
+
private readonly queue;
|
|
17
|
+
private readonly runtimes;
|
|
18
|
+
private readonly cloudToAgent;
|
|
19
|
+
private readonly pendingPermissions;
|
|
20
|
+
private readonly busyApprovals;
|
|
21
|
+
private readonly now;
|
|
22
|
+
constructor(deps: {
|
|
23
|
+
client: Pick<FrontierClient, 'send' | 'onFrame'>;
|
|
24
|
+
agents: AgentManager;
|
|
25
|
+
store: Store;
|
|
26
|
+
seq: SeqAllocator;
|
|
27
|
+
adapterFactory: AdapterFactory;
|
|
28
|
+
fetchImpl: typeof fetch;
|
|
29
|
+
config: Config;
|
|
30
|
+
now?: () => number;
|
|
31
|
+
});
|
|
32
|
+
start(): void;
|
|
33
|
+
handleFrame(msg: JsonRpcRequest | JsonRpcResponse): Promise<void>;
|
|
34
|
+
agentStatuses(): {
|
|
35
|
+
agentId: string;
|
|
36
|
+
status: 'online' | 'busy' | 'error';
|
|
37
|
+
}[];
|
|
38
|
+
stopAll(): Promise<void>;
|
|
39
|
+
private handleSessionNew;
|
|
40
|
+
private handleSessionPrompt;
|
|
41
|
+
private handleSessionCancel;
|
|
42
|
+
private runPrompt;
|
|
43
|
+
private ensureRuntime;
|
|
44
|
+
private ensureAcpSession;
|
|
45
|
+
private handleUpdate;
|
|
46
|
+
private handleAgentRequest;
|
|
47
|
+
private handleResponse;
|
|
48
|
+
private sendSessionUpdate;
|
|
49
|
+
private sendTurnEnded;
|
|
50
|
+
private requireAgent;
|
|
51
|
+
private respond;
|
|
52
|
+
private sendResult;
|
|
53
|
+
private sendError;
|
|
54
|
+
private inlineImages;
|
|
55
|
+
}
|