abtars 0.2.0 → 0.2.1-alpha.10
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 +15 -18
- package/bundle/{_registry.generated-6GO2PAMD.js → _registry.generated-4P6KTBTH.js} +8 -8
- package/bundle/_registry.generated-G2FSGHNY.js +36 -0
- package/bundle/_registry.generated-G2FSGHNY.js.map +7 -0
- package/bundle/_registry.generated-N74SMTUJ.js +36 -0
- package/bundle/_registry.generated-N74SMTUJ.js.map +7 -0
- package/bundle/_registry.generated-Y4VT5MBX.js +36 -0
- package/bundle/_registry.generated-Y4VT5MBX.js.map +7 -0
- package/bundle/abtars-browser.js +0 -1
- package/bundle/abtars-browser.js.map +2 -2
- package/bundle/abtars-cli.js +589 -547
- package/bundle/abtars-cli.js.map +4 -4
- package/bundle/abtars-restart.js +1 -1
- package/bundle/abtars-rss.js +0 -1
- package/bundle/abtars-rss.js.map +2 -2
- package/bundle/abtars-task.js +1 -2
- package/bundle/abtars-task.js.map +2 -2
- package/bundle/abtars.js +58 -33
- package/bundle/abtars.js.map +2 -2
- package/bundle/{agent-registry-SYUFNSVB.js → agent-registry-TM7EISOV.js} +2 -2
- package/bundle/{browse-delivery-64GQIUHG.js → browse-delivery-VTLEAVYA.js} +4 -4
- package/bundle/{browser-5H2Q7GEC.js → browser-JQGYFZAG.js} +5 -5
- package/bundle/browser-M4KDLN75.js +19 -0
- package/bundle/browser-REIXOJ6S.js +19 -0
- package/bundle/browser-VG2GTEND.js +19 -0
- package/bundle/{chunk-KFENC7BM.js → chunk-4YOTNYAE.js} +2 -2
- package/bundle/{chunk-KWBGYWDO.js → chunk-7I5C2U3C.js} +1 -1
- package/bundle/chunk-7I5C2U3C.js.map +7 -0
- package/bundle/{chunk-7STAQF5O.js → chunk-CNWXVXGH.js} +4 -4
- package/bundle/{chunk-7STAQF5O.js.map → chunk-CNWXVXGH.js.map} +2 -2
- package/bundle/{chunk-JX3ZZU3O.js → chunk-CU3O53U3.js} +28 -14
- package/bundle/chunk-CU3O53U3.js.map +7 -0
- package/bundle/chunk-EZZBO2QK.js +85 -0
- package/bundle/chunk-EZZBO2QK.js.map +7 -0
- package/bundle/{chunk-XLLSPBBT.js → chunk-GPL57SRN.js} +2 -2
- package/bundle/chunk-GPL57SRN.js.map +7 -0
- package/bundle/{chunk-PQ62LZNA.js → chunk-HEHD3GG5.js} +2 -2
- package/bundle/{chunk-A5OJYQNU.js → chunk-HTGVYNPE.js} +4 -4
- package/bundle/{chunk-WUTCGJDZ.js → chunk-HZRUBJ4Q.js} +148 -9
- package/bundle/chunk-HZRUBJ4Q.js.map +7 -0
- package/bundle/{chunk-ZVDVNSXK.js → chunk-J7CFCY4U.js} +2 -2
- package/bundle/{chunk-HXJRZWKA.js → chunk-JRK3UFBS.js} +106 -58
- package/bundle/chunk-JRK3UFBS.js.map +7 -0
- package/bundle/{chunk-GZUQQWBZ.js → chunk-KJOCXWJ5.js} +3 -3
- package/bundle/chunk-KJOCXWJ5.js.map +7 -0
- package/bundle/{chunk-K7P74UNQ.js → chunk-LDKSCXGL.js} +3 -3
- package/bundle/{chunk-K7P74UNQ.js.map → chunk-LDKSCXGL.js.map} +2 -2
- package/bundle/chunk-MNKLPRGY.js +138 -0
- package/bundle/chunk-MNKLPRGY.js.map +7 -0
- package/bundle/chunk-O73EZGKR.js +135 -0
- package/bundle/chunk-O73EZGKR.js.map +7 -0
- package/bundle/{chunk-OZ4IZFV4.js → chunk-Q7F5R2LL.js} +1 -1
- package/bundle/{chunk-OZ4IZFV4.js.map → chunk-Q7F5R2LL.js.map} +2 -2
- package/bundle/{chunk-XOCP5BMO.js → chunk-URAQLQ2U.js} +2 -2
- package/bundle/chunk-URAQLQ2U.js.map +7 -0
- package/bundle/{chunk-PPSB2ZIN.js → chunk-VREI2GUO.js} +18 -7
- package/bundle/chunk-VREI2GUO.js.map +7 -0
- package/bundle/chunk-VYR25H37.js +135 -0
- package/bundle/chunk-VYR25H37.js.map +7 -0
- package/bundle/{commands-E3Y4QUNF.js → commands-J6JAZ7D2.js} +5 -5
- package/bundle/{deploy-lib-import-ODLDL2DB.js → deploy-lib-import-PJXUADPS.js} +18 -16
- package/bundle/{direct-api-transport-TRV45NO6.js → direct-api-transport-ZSJHKYBX.js} +1 -1
- package/bundle/direct-api-transport-ZSJHKYBX.js.map +7 -0
- package/bundle/{discord-adapter-5DS7UTBE.js → discord-adapter-OCWSJTJU.js} +8 -8
- package/bundle/{doctor-R54GZPKL.js → doctor-XOGVHA4W.js} +13 -2
- package/bundle/{doctor-R54GZPKL.js.map → doctor-XOGVHA4W.js.map} +2 -2
- package/bundle/{install-RSLOS3Q5.js → install-6H3APAIJ.js} +3 -3
- package/bundle/{irc-adapter-RKRUSZXB.js → irc-adapter-AIEP6OX6.js} +6 -2
- package/bundle/irc-adapter-AIEP6OX6.js.map +7 -0
- package/bundle/{message-pipeline-CFVO73CK.js → message-pipeline-TCPHRBAK.js} +5 -5
- package/bundle/meta.json +4005 -3868
- package/bundle/{phase-transport-FEZ4SIJJ.js → phase-transport-ME2XDRR2.js} +3 -3
- package/bundle/restore-UH2UE2K5.js +151 -0
- package/bundle/restore-UH2UE2K5.js.map +7 -0
- package/bundle/rollback-D7AYTC7Z.js +11 -0
- package/bundle/{sleep-BPWX3FCN.js → sleep-IOWYTSMK.js} +2 -2
- package/bundle/{soul-bundle-BRIUDEQ2.js → soul-bundle-AH5S3MVI.js} +2 -2
- package/bundle/{soul-loader-GBXJ7EBH.js → soul-loader-N5FA4I6C.js} +3 -3
- package/bundle/soul-loader-N5FA4I6C.js.map +7 -0
- package/bundle/{start-4IWBKLWO.js → start-CBVKNEAT.js} +1 -1
- package/bundle/{subagent-runtime-MDBO6LHS.js → subagent-runtime-OOJXCKJF.js} +2 -2
- package/bundle/subagent-runtime-OOJXCKJF.js.map +7 -0
- package/bundle/{system-status-WAY63BYC.js → system-status-4JP36OKC.js} +12 -5
- package/bundle/{system-status-WAY63BYC.js.map → system-status-4JP36OKC.js.map} +2 -2
- package/bundle/{task-store-KIBFZL5A.js → task-store-LC7ZMS72.js} +2 -2
- package/bundle/task-store-LC7ZMS72.js.map +7 -0
- package/bundle/{telegram-adapter-MVA33IO2.js → telegram-adapter-QXHJQLLX.js} +5 -5
- package/bundle/{update-check-O5MS6B3L.js → update-check-XVY2IK2L.js} +2 -2
- package/bundle/update-check-XVY2IK2L.js.map +7 -0
- package/core/skills/tools/rss/SKILL.md +51 -0
- package/install-manifest.json +4 -3
- package/package.json +3 -4
- package/scripts/abtars-daemon.service +1 -1
- package/scripts/abtars-watchdog.service +1 -1
- package/scripts/abtars.sh +3 -5
- package/scripts/abtars@.service +1 -1
- package/scripts/build-and-deploy.sh +6 -0
- package/scripts/com.abtars.daemon.plist +1 -1
- package/scripts/com.abtars.watchdog.plist +1 -1
- package/scripts/daily-backup.sh +1 -61
- package/scripts/doctor.sh +48 -33
- package/scripts/watchdog.sh +53 -8
- package/bundle/chunk-GZUQQWBZ.js.map +0 -7
- package/bundle/chunk-HXJRZWKA.js.map +0 -7
- package/bundle/chunk-JX3ZZU3O.js.map +0 -7
- package/bundle/chunk-KWBGYWDO.js.map +0 -7
- package/bundle/chunk-PPSB2ZIN.js.map +0 -7
- package/bundle/chunk-WUTCGJDZ.js.map +0 -7
- package/bundle/chunk-XLLSPBBT.js.map +0 -7
- package/bundle/chunk-XOCP5BMO.js.map +0 -7
- package/bundle/direct-api-transport-TRV45NO6.js.map +0 -7
- package/bundle/irc-adapter-RKRUSZXB.js.map +0 -7
- package/bundle/passwd-QSHZJ2CG.js +0 -134
- package/bundle/passwd-QSHZJ2CG.js.map +0 -7
- package/bundle/restore-ROJF22R2.js +0 -47
- package/bundle/restore-ROJF22R2.js.map +0 -7
- package/core/core_templates/SOUL.md +0 -24
- package/core/core_templates/agent_notes.md +0 -7
- package/core/core_templates/core_facts.md +0 -10
- package/core/core_templates/user_profile.md +0 -7
- package/core/skills/tools/fxtwitter/SKILL.md +0 -52
- package/core/skills/tools/twitterX/SKILL.md +0 -52
- package/core/skills/tools/twitterX/scripts/abtars-tweet.js +0 -532
- package/core/skills/tools/twitterX/scripts/package.json +0 -1
- /package/bundle/{_registry.generated-6GO2PAMD.js.map → _registry.generated-4P6KTBTH.js.map} +0 -0
- /package/bundle/{agent-registry-SYUFNSVB.js.map → agent-registry-TM7EISOV.js.map} +0 -0
- /package/bundle/{browse-delivery-64GQIUHG.js.map → browse-delivery-VTLEAVYA.js.map} +0 -0
- /package/bundle/{browser-5H2Q7GEC.js.map → browser-JQGYFZAG.js.map} +0 -0
- /package/bundle/{commands-E3Y4QUNF.js.map → browser-M4KDLN75.js.map} +0 -0
- /package/bundle/{deploy-lib-import-ODLDL2DB.js.map → browser-REIXOJ6S.js.map} +0 -0
- /package/bundle/{install-RSLOS3Q5.js.map → browser-VG2GTEND.js.map} +0 -0
- /package/bundle/{chunk-KFENC7BM.js.map → chunk-4YOTNYAE.js.map} +0 -0
- /package/bundle/{chunk-PQ62LZNA.js.map → chunk-HEHD3GG5.js.map} +0 -0
- /package/bundle/{chunk-A5OJYQNU.js.map → chunk-HTGVYNPE.js.map} +0 -0
- /package/bundle/{chunk-ZVDVNSXK.js.map → chunk-J7CFCY4U.js.map} +0 -0
- /package/bundle/{message-pipeline-CFVO73CK.js.map → commands-J6JAZ7D2.js.map} +0 -0
- /package/bundle/{phase-transport-FEZ4SIJJ.js.map → deploy-lib-import-PJXUADPS.js.map} +0 -0
- /package/bundle/{discord-adapter-5DS7UTBE.js.map → discord-adapter-OCWSJTJU.js.map} +0 -0
- /package/bundle/{sleep-BPWX3FCN.js.map → install-6H3APAIJ.js.map} +0 -0
- /package/bundle/{soul-bundle-BRIUDEQ2.js.map → message-pipeline-TCPHRBAK.js.map} +0 -0
- /package/bundle/{soul-loader-GBXJ7EBH.js.map → phase-transport-ME2XDRR2.js.map} +0 -0
- /package/bundle/{subagent-runtime-MDBO6LHS.js.map → rollback-D7AYTC7Z.js.map} +0 -0
- /package/bundle/{task-store-KIBFZL5A.js.map → sleep-IOWYTSMK.js.map} +0 -0
- /package/bundle/{update-check-O5MS6B3L.js.map → soul-bundle-AH5S3MVI.js.map} +0 -0
- /package/bundle/{start-4IWBKLWO.js.map → start-CBVKNEAT.js.map} +0 -0
- /package/bundle/{telegram-adapter-MVA33IO2.js.map → telegram-adapter-QXHJQLLX.js.map} +0 -0
|
@@ -70,7 +70,7 @@ async function createSubagentTransport(role, registry, currentModel) {
|
|
|
70
70
|
return { model: fb.model, provider: fb.provider, providerName: fb.providerName, contextWindow: fb.contextWindow, maxOutput: fb.maxOutput, fallbacks: [] };
|
|
71
71
|
})();
|
|
72
72
|
if (agent.provider.transport === "api") {
|
|
73
|
-
const { DirectApiTransport } = await import("./direct-api-transport-
|
|
73
|
+
const { DirectApiTransport } = await import("./direct-api-transport-ZSJHKYBX.js");
|
|
74
74
|
const { FallbackPolicy } = await import("./fallback-policy-SR6ED5I3.js");
|
|
75
75
|
const apiKey = getEnv().getApiKey(agent.provider.apiKeyEnv ?? "API_KEY");
|
|
76
76
|
const startModel = currentModel ?? agent.model;
|
|
@@ -186,4 +186,4 @@ export {
|
|
|
186
186
|
createAgentTransport,
|
|
187
187
|
createSubagentTransport
|
|
188
188
|
};
|
|
189
|
-
//# sourceMappingURL=chunk-
|
|
189
|
+
//# sourceMappingURL=chunk-J7CFCY4U.js.map
|
|
@@ -21,12 +21,18 @@ function packagePaths(pkg) {
|
|
|
21
21
|
return {
|
|
22
22
|
home,
|
|
23
23
|
config: join(home, "config"),
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
24
|
+
app: join(home, "app"),
|
|
25
|
+
appPrev: join(home, "app.prev"),
|
|
26
|
+
appPrev1: join(home, "app.prev.1"),
|
|
27
|
+
appPrev2: join(home, "app.prev.2"),
|
|
28
|
+
appPrev3: join(home, "app.prev.3"),
|
|
29
|
+
appStaging: join(home, "app.staging"),
|
|
27
30
|
bin: join(home, "bin"),
|
|
28
31
|
manifest: join(home, "manifest.json"),
|
|
29
|
-
lock: join(home, ".update.lock")
|
|
32
|
+
lock: join(home, ".update.lock"),
|
|
33
|
+
// Legacy
|
|
34
|
+
releases: join(home, "releases"),
|
|
35
|
+
current: join(home, "current")
|
|
30
36
|
};
|
|
31
37
|
}
|
|
32
38
|
|
|
@@ -55,8 +61,8 @@ function emptyManifest(pkg, host) {
|
|
|
55
61
|
host,
|
|
56
62
|
source: "local",
|
|
57
63
|
migrationsApplied: [],
|
|
58
|
-
|
|
59
|
-
|
|
64
|
+
previousVersion: null,
|
|
65
|
+
previousCommit: null
|
|
60
66
|
};
|
|
61
67
|
}
|
|
62
68
|
|
|
@@ -141,52 +147,96 @@ async function inspectLock(path) {
|
|
|
141
147
|
|
|
142
148
|
// src/cli/deploy-lib/releases.ts
|
|
143
149
|
import { createHash } from "node:crypto";
|
|
144
|
-
import {
|
|
145
|
-
import {
|
|
146
|
-
|
|
147
|
-
|
|
150
|
+
import { existsSync, mkdirSync, rmSync, renameSync, readdirSync, cpSync, readFileSync, writeFileSync } from "node:fs";
|
|
151
|
+
import { readFile as readFile3 } from "node:fs/promises";
|
|
152
|
+
import { join as join2 } from "node:path";
|
|
153
|
+
function atomicSwap(appDir, _appPrevLegacy, appStagingDir) {
|
|
154
|
+
const prev1 = appDir.replace(/\/app$/, "/app.prev.1");
|
|
155
|
+
const prev2 = appDir.replace(/\/app$/, "/app.prev.2");
|
|
156
|
+
const prev3 = appDir.replace(/\/app$/, "/app.prev.3");
|
|
157
|
+
const legacyPrev = _appPrevLegacy;
|
|
158
|
+
if (existsSync(legacyPrev) && !existsSync(prev1)) {
|
|
159
|
+
renameSync(legacyPrev, prev1);
|
|
160
|
+
} else if (existsSync(legacyPrev)) {
|
|
161
|
+
rmSync(legacyPrev, { recursive: true, force: true });
|
|
162
|
+
}
|
|
148
163
|
try {
|
|
149
|
-
const
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
164
|
+
const curPkg = join2(appDir, "package.json");
|
|
165
|
+
const stagePkg = join2(appStagingDir, "package.json");
|
|
166
|
+
if (existsSync(curPkg) && existsSync(stagePkg)) {
|
|
167
|
+
const curVer = JSON.parse(readFileSync(curPkg, "utf-8")).version;
|
|
168
|
+
const stageVer = JSON.parse(readFileSync(stagePkg, "utf-8")).version;
|
|
169
|
+
if (curVer && curVer === stageVer) {
|
|
170
|
+
rmSync(appDir, { recursive: true, force: true });
|
|
171
|
+
renameSync(appStagingDir, appDir);
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
} catch {
|
|
154
176
|
}
|
|
177
|
+
if (existsSync(prev3)) rmSync(prev3, { recursive: true, force: true });
|
|
178
|
+
if (existsSync(prev2)) renameSync(prev2, prev3);
|
|
179
|
+
if (existsSync(prev1)) renameSync(prev1, prev2);
|
|
180
|
+
if (existsSync(appDir)) renameSync(appDir, prev1);
|
|
181
|
+
renameSync(appStagingDir, appDir);
|
|
155
182
|
}
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
183
|
+
function configSnapshot(configDir) {
|
|
184
|
+
const slot0 = join2(configDir, ".pre-update");
|
|
185
|
+
const slot1 = join2(configDir, ".pre-update.1");
|
|
186
|
+
const slot2 = join2(configDir, ".pre-update.2");
|
|
187
|
+
if (existsSync(slot2)) rmSync(slot2, { recursive: true, force: true });
|
|
188
|
+
if (existsSync(slot1)) renameSync(slot1, slot2);
|
|
189
|
+
if (existsSync(slot0)) renameSync(slot0, slot1);
|
|
190
|
+
mkdirSync(slot0, { recursive: true });
|
|
191
|
+
if (!existsSync(configDir)) return;
|
|
192
|
+
for (const entry of readdirSync(configDir, { withFileTypes: true })) {
|
|
193
|
+
if (entry.name.startsWith(".pre-update")) continue;
|
|
194
|
+
const src = join2(configDir, entry.name);
|
|
195
|
+
const dst = join2(slot0, entry.name);
|
|
196
|
+
if (entry.isDirectory()) {
|
|
197
|
+
cpSync(src, dst, { recursive: true });
|
|
198
|
+
} else {
|
|
199
|
+
cpSync(src, dst);
|
|
200
|
+
}
|
|
166
201
|
}
|
|
167
202
|
}
|
|
168
|
-
async function
|
|
169
|
-
const
|
|
170
|
-
const
|
|
203
|
+
async function healthProbe(home, afterTimestamp, timeoutMs = 6e4) {
|
|
204
|
+
const lockPath = join2(home, "bridge.lock");
|
|
205
|
+
const deadline = Date.now() + timeoutMs;
|
|
206
|
+
while (Date.now() < deadline) {
|
|
207
|
+
try {
|
|
208
|
+
const content = JSON.parse(await readFile3(lockPath, "utf-8"));
|
|
209
|
+
if (content.lastHeartbeat && content.lastHeartbeat > afterTimestamp) {
|
|
210
|
+
return { healthy: true, pid: content.pid, heartbeat: content.lastHeartbeat };
|
|
211
|
+
}
|
|
212
|
+
} catch {
|
|
213
|
+
}
|
|
214
|
+
await new Promise((r) => setTimeout(r, 3e3));
|
|
215
|
+
}
|
|
216
|
+
return { healthy: false };
|
|
217
|
+
}
|
|
218
|
+
function writeSentinel(home, sentinel) {
|
|
219
|
+
const dir = join2(home, "state");
|
|
220
|
+
mkdirSync(dir, { recursive: true });
|
|
221
|
+
writeFileSync(join2(dir, "update.sentinel"), JSON.stringify(sentinel, null, 2) + "\n");
|
|
222
|
+
}
|
|
223
|
+
function readSentinel(home) {
|
|
171
224
|
try {
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
225
|
+
const content = readFileSync(join2(home, "state", "update.sentinel"), "utf-8");
|
|
226
|
+
return JSON.parse(content);
|
|
227
|
+
} catch {
|
|
228
|
+
return null;
|
|
175
229
|
}
|
|
176
|
-
await symlink(target, tmp);
|
|
177
|
-
await rename(tmp, currentLink);
|
|
178
230
|
}
|
|
179
|
-
|
|
180
|
-
const
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
pruned.push(version);
|
|
231
|
+
function clearSentinel(home, _version) {
|
|
232
|
+
const path = join2(home, "state", "update.sentinel");
|
|
233
|
+
if (!existsSync(path)) return;
|
|
234
|
+
try {
|
|
235
|
+
const sentinel = JSON.parse(readFileSync(path, "utf-8"));
|
|
236
|
+
sentinel.status = "success";
|
|
237
|
+
writeFileSync(path, JSON.stringify(sentinel, null, 2) + "\n");
|
|
238
|
+
} catch {
|
|
188
239
|
}
|
|
189
|
-
return pruned;
|
|
190
240
|
}
|
|
191
241
|
async function hashFile(path) {
|
|
192
242
|
try {
|
|
@@ -197,17 +247,14 @@ async function hashFile(path) {
|
|
|
197
247
|
throw err;
|
|
198
248
|
}
|
|
199
249
|
}
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
return s.isDirectory();
|
|
204
|
-
} catch {
|
|
205
|
-
return false;
|
|
250
|
+
function cleanStaleStaging(stagingDir) {
|
|
251
|
+
if (existsSync(stagingDir)) {
|
|
252
|
+
rmSync(stagingDir, { recursive: true, force: true });
|
|
206
253
|
}
|
|
207
254
|
}
|
|
208
255
|
|
|
209
256
|
// src/cli/deploy-lib/cleanup.ts
|
|
210
|
-
import { rm
|
|
257
|
+
import { rm } from "node:fs/promises";
|
|
211
258
|
import { homedir as homedir2 } from "node:os";
|
|
212
259
|
import { resolve } from "node:path";
|
|
213
260
|
function isUnsafeRemovalTarget(path) {
|
|
@@ -234,7 +281,7 @@ async function removePath(path, opts = {}) {
|
|
|
234
281
|
}
|
|
235
282
|
if (opts.dryRun) return true;
|
|
236
283
|
try {
|
|
237
|
-
await
|
|
284
|
+
await rm(path, { recursive: true });
|
|
238
285
|
return true;
|
|
239
286
|
} catch (err) {
|
|
240
287
|
if (err.code === "ENOENT") return false;
|
|
@@ -275,16 +322,17 @@ export {
|
|
|
275
322
|
LockHeldError,
|
|
276
323
|
acquireLock,
|
|
277
324
|
inspectLock,
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
325
|
+
atomicSwap,
|
|
326
|
+
configSnapshot,
|
|
327
|
+
healthProbe,
|
|
328
|
+
writeSentinel,
|
|
329
|
+
readSentinel,
|
|
330
|
+
clearSentinel,
|
|
283
331
|
hashFile,
|
|
284
|
-
|
|
332
|
+
cleanStaleStaging,
|
|
285
333
|
isUnsafeRemovalTarget,
|
|
286
334
|
planRemoval,
|
|
287
335
|
removePath,
|
|
288
336
|
safeCopyTree
|
|
289
337
|
};
|
|
290
|
-
//# sourceMappingURL=chunk-
|
|
338
|
+
//# sourceMappingURL=chunk-JRK3UFBS.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/cli/deploy-lib/paths.ts", "../src/cli/deploy-lib/manifest.ts", "../src/cli/deploy-lib/lock.ts", "../src/cli/deploy-lib/releases.ts", "../src/cli/deploy-lib/cleanup.ts", "../src/cli/deploy-lib/safe-copy.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Runtime directory resolution for deploy-lib consumers.\n *\n * Rules:\n * - abtars runtime root: $ABTARS_HOME ?? ~/.abtars\n * - abmind runtime root: $ABMIND_HOME ?? ~/.abmind\n * - user bin dir: ~/.local/bin (always, XDG convention)\n *\n * All callers use these resolvers \u2014 never hardcode paths. Required by\n * plan #158 v7 (Ag2 round-2 nit): cross-repo manifest reads must respect\n * env-var overrides, not assume default locations.\n */\n\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\n\nexport type PackageName = 'abtars' | 'abmind';\n\nexport function resolveAbtarsHome(): string {\n return process.env['ABTARS_HOME'] ?? join(homedir(), '.abtars');\n}\n\nexport function resolveAbmindHome(): string {\n return process.env['ABMIND_HOME'] ?? join(homedir(), '.abmind');\n}\n\nexport function resolvePackageHome(pkg: PackageName): string {\n return pkg === 'abtars' ? resolveAbtarsHome() : resolveAbmindHome();\n}\n\nexport function resolveUserBinDir(): string {\n return join(homedir(), '.local', 'bin');\n}\n\nexport interface PackagePaths {\n readonly home: string;\n readonly config: string;\n readonly app: string;\n readonly appPrev: string;\n readonly appPrev1: string;\n readonly appPrev2: string;\n readonly appPrev3: string;\n readonly appStaging: string;\n readonly bin: string;\n readonly manifest: string;\n readonly lock: string;\n // Legacy \u2014 kept for migration detection only. Remove after all hosts migrated.\n readonly releases: string;\n readonly current: string;\n}\n\nexport function packagePaths(pkg: PackageName): PackagePaths {\n const home = resolvePackageHome(pkg);\n return {\n home,\n config: join(home, 'config'),\n app: join(home, 'app'),\n appPrev: join(home, 'app.prev'),\n appPrev1: join(home, 'app.prev.1'),\n appPrev2: join(home, 'app.prev.2'),\n appPrev3: join(home, 'app.prev.3'),\n appStaging: join(home, 'app.staging'),\n bin: join(home, 'bin'),\n manifest: join(home, 'manifest.json'),\n lock: join(home, '.update.lock'),\n // Legacy\n releases: join(home, 'releases'),\n current: join(home, 'current'),\n };\n}\n", "/**\n * Runtime manifest: the single source of truth for \"what's installed\".\n *\n * Location: $HOME/manifest.json (per packagePaths().manifest).\n * Read by: `status`, cross-package compatibility checks, doctor.\n * Written by: `install`, `update`, `rollback`, migrations.\n */\n\nimport { readFile, writeFile } from 'node:fs/promises';\n\nexport interface Manifest {\n readonly package: 'abtars' | 'abmind';\n /** Currently active release version. */\n readonly version: string;\n /** Git SHA of the source that produced the active release, if known. */\n readonly commit: string | null;\n /** Git branch, if known. */\n readonly branch: string | null;\n /** Hash of package-lock.json at time of last install. */\n readonly packageLockHash: string | null;\n /** ISO timestamp of when the active release became active. */\n readonly activatedAt: string;\n /** Hostname where install lives (informational). */\n readonly host: string;\n /** Source adapter that produced the current release (local | npm | github). */\n readonly source: 'local' | 'npm' | 'github';\n /** Applied migrations (ordered). */\n readonly migrationsApplied: readonly string[];\n /** Previous version (for rollback). Null on first install. */\n readonly previousVersion: string | null;\n /** Previous commit (for rollback reference). */\n readonly previousCommit: string | null;\n /** Install mode: simple (manual), supervised (launchd/systemd user-scope), or supervised-daemon (system-scope). */\n readonly installMode?: 'simple' | 'supervised' | 'supervised-daemon';\n}\n\nexport async function readManifest(path: string): Promise<Manifest | null> {\n try {\n const raw = await readFile(path, 'utf-8');\n return JSON.parse(raw) as Manifest;\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') return null;\n throw err;\n }\n}\n\nexport async function writeManifest(path: string, manifest: Manifest): Promise<void> {\n await writeFile(path, JSON.stringify(manifest, null, 2) + '\\n', 'utf-8');\n}\n\nexport function emptyManifest(pkg: 'abtars' | 'abmind', host: string): Manifest {\n return {\n package: pkg,\n version: '',\n commit: null,\n branch: null,\n packageLockHash: null,\n activatedAt: new Date().toISOString(),\n host,\n source: 'local',\n migrationsApplied: [],\n previousVersion: null,\n previousCommit: null,\n };\n}\n", "/**\n * Update lock: prevents concurrent `install` / `update` / `rollback` runs\n * in the same runtime from colliding.\n *\n * Mechanism: write a JSON pidfile at packagePaths().lock. If file exists and\n * the PID is alive and the mtime is recent (<1h), refuse to proceed. Otherwise\n * take the lock.\n *\n * Stale timeout matches plan: 1 hour (our updates take minutes). Compared to\n * claude-code's 7-day timeout which accommodates laptop sleep during a long\n * install \u2014 not applicable for our short-lived updates.\n */\n\nimport { readFile, unlink, writeFile } from 'node:fs/promises';\nimport { unlinkSync } from 'node:fs';\nimport { hostname } from 'node:os';\n\nconst STALE_MS = 60 * 60 * 1000; // 1 hour\n\nexport interface LockContent {\n readonly pid: number;\n readonly host: string;\n readonly startedAt: string;\n readonly cmd: string;\n}\n\nexport class LockHeldError extends Error {\n constructor(\n public readonly content: LockContent,\n public readonly isStale: boolean,\n ) {\n const staleMsg = isStale ? ' (appears stale \u2014 process may have crashed)' : '';\n super(\n `Lock held by pid ${content.pid} since ${content.startedAt} ` +\n `(cmd: ${content.cmd})${staleMsg}`,\n );\n this.name = 'LockHeldError';\n }\n}\n\nfunction isPidAlive(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch (err) {\n return (err as NodeJS.ErrnoException).code === 'EPERM';\n }\n}\n\nasync function readLock(path: string): Promise<LockContent | null> {\n try {\n return JSON.parse(await readFile(path, 'utf-8')) as LockContent;\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') return null;\n throw err;\n }\n}\n\n/**\n * Acquire the lock or throw LockHeldError. Returns a release function.\n * Caller must call release() on both success and failure; the returned\n * function is idempotent.\n */\nexport async function acquireLock(path: string, cmd: string): Promise<() => Promise<void>> {\n const existing = await readLock(path);\n if (existing) {\n const alive = isPidAlive(existing.pid);\n const started = Date.parse(existing.startedAt);\n const age = Date.now() - (Number.isFinite(started) ? started : 0);\n const stale = !alive || age > STALE_MS;\n if (!stale) {\n throw new LockHeldError(existing, false);\n }\n // Stale: fall through and take it, but tell the caller so doctor can surface.\n }\n\n const content: LockContent = {\n pid: process.pid,\n host: hostname(),\n startedAt: new Date().toISOString(),\n cmd,\n };\n await writeFile(path, JSON.stringify(content, null, 2) + '\\n', 'utf-8');\n\n let released = false;\n const release = async (): Promise<void> => {\n if (released) return;\n released = true;\n try {\n await unlink(path);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== 'ENOENT') throw err;\n }\n };\n\n // Best-effort cleanup on unexpected exit.\n const exitHandler = (): void => {\n try {\n unlinkSync(path);\n } catch {\n /* ignore \u2014 stale detection handles orphans next run */\n }\n };\n process.once('exit', exitHandler);\n\n return release;\n}\n\nexport async function inspectLock(path: string): Promise<\n | { held: false }\n | { held: true; content: LockContent; stale: boolean }\n> {\n const content = await readLock(path);\n if (!content) return { held: false };\n const alive = isPidAlive(content.pid);\n const started = Date.parse(content.startedAt);\n const age = Date.now() - (Number.isFinite(started) ? started : 0);\n const stale = !alive || age > STALE_MS;\n return { held: true, content, stale };\n}\n", "/**\n * Deploy primitives: atomic swap, config snapshot, health probe, hash.\n *\n * #785: replaces the old releases/current symlink model with\n * app/ + app.prev/ atomic rename swap.\n */\n\nimport { createHash } from 'node:crypto';\nimport { existsSync, mkdirSync, rmSync, renameSync, readdirSync, cpSync, readFileSync, writeFileSync } from 'node:fs';\nimport { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\n\n/**\n * Atomic swap with 3-prior rotation.\n * app.prev.3/ \u2192 delete, app.prev.2/ \u2192 .3, app.prev.1/ \u2192 .2, app/ \u2192 .prev.1, staging/ \u2192 app/\n * Backward compat: migrates old app.prev/ \u2192 app.prev.1/ if found.\n */\nexport function atomicSwap(appDir: string, _appPrevLegacy: string, appStagingDir: string): void {\n const prev1 = appDir.replace(/\\/app$/, '/app.prev.1');\n const prev2 = appDir.replace(/\\/app$/, '/app.prev.2');\n const prev3 = appDir.replace(/\\/app$/, '/app.prev.3');\n const legacyPrev = _appPrevLegacy; // app.prev/ (old format)\n\n // Migrate old app.prev/ \u2192 app.prev.1/ if exists\n if (existsSync(legacyPrev) && !existsSync(prev1)) {\n renameSync(legacyPrev, prev1);\n } else if (existsSync(legacyPrev)) {\n rmSync(legacyPrev, { recursive: true, force: true });\n }\n\n // Skip rotation if current app/ has same version as staging (no-op redeploy)\n try {\n const curPkg = join(appDir, \"package.json\");\n const stagePkg = join(appStagingDir, \"package.json\");\n if (existsSync(curPkg) && existsSync(stagePkg)) {\n const curVer = JSON.parse(readFileSync(curPkg, \"utf-8\")).version;\n const stageVer = JSON.parse(readFileSync(stagePkg, \"utf-8\")).version;\n if (curVer && curVer === stageVer) {\n // Same version \u2014 just replace app/ without rotating priors\n rmSync(appDir, { recursive: true, force: true });\n renameSync(appStagingDir, appDir);\n return;\n }\n }\n } catch { /* proceed with normal rotation if read fails */ }\n\n // Rotate: 3 \u2192 delete, 2 \u2192 3, 1 \u2192 2\n if (existsSync(prev3)) rmSync(prev3, { recursive: true, force: true });\n if (existsSync(prev2)) renameSync(prev2, prev3);\n if (existsSync(prev1)) renameSync(prev1, prev2);\n\n // app/ \u2192 app.prev.1/\n if (existsSync(appDir)) renameSync(appDir, prev1);\n\n // app.staging/ \u2192 app/\n renameSync(appStagingDir, appDir);\n}\n\n/**\n * Rotate config snapshots (3 slots) and create a fresh snapshot.\n * Excludes .pre-update* dirs from the copy to avoid recursion.\n */\nexport function configSnapshot(configDir: string): void {\n const slot0 = join(configDir, '.pre-update');\n const slot1 = join(configDir, '.pre-update.1');\n const slot2 = join(configDir, '.pre-update.2');\n\n // Rotate\n if (existsSync(slot2)) rmSync(slot2, { recursive: true, force: true });\n if (existsSync(slot1)) renameSync(slot1, slot2);\n if (existsSync(slot0)) renameSync(slot0, slot1);\n\n // Fresh snapshot \u2014 copy config/ contents excluding .pre-update* dirs\n mkdirSync(slot0, { recursive: true });\n if (!existsSync(configDir)) return;\n for (const entry of readdirSync(configDir, { withFileTypes: true })) {\n if (entry.name.startsWith('.pre-update')) continue;\n const src = join(configDir, entry.name);\n const dst = join(slot0, entry.name);\n if (entry.isDirectory()) {\n cpSync(src, dst, { recursive: true });\n } else {\n cpSync(src, dst);\n }\n }\n}\n\n/**\n * Poll bridge.lock for a fresh lastHeartbeat after restart.\n * Returns true if healthy within timeoutMs, false otherwise.\n */\nexport async function healthProbe(\n home: string,\n afterTimestamp: number,\n timeoutMs: number = 60_000,\n): Promise<{ healthy: boolean; pid?: number; heartbeat?: number }> {\n const lockPath = join(home, 'bridge.lock');\n const deadline = Date.now() + timeoutMs;\n while (Date.now() < deadline) {\n try {\n const content = JSON.parse(await readFile(lockPath, 'utf-8'));\n if (content.lastHeartbeat && content.lastHeartbeat > afterTimestamp) {\n return { healthy: true, pid: content.pid, heartbeat: content.lastHeartbeat };\n }\n } catch {\n // File doesn't exist yet or invalid JSON \u2014 keep polling\n }\n await new Promise(r => setTimeout(r, 3000));\n }\n return { healthy: false };\n}\n\n/**\n * Write/read/clear the update sentinel.\n */\nexport interface UpdateSentinel {\n version: string;\n previousVersion: string | null;\n startedAt: string;\n status: 'pending' | 'success';\n}\n\nexport function writeSentinel(home: string, sentinel: UpdateSentinel): void {\n const dir = join(home, 'state');\n mkdirSync(dir, { recursive: true });\n writeFileSync(join(dir, 'update.sentinel'), JSON.stringify(sentinel, null, 2) + '\\n');\n}\n\nexport function readSentinel(home: string): UpdateSentinel | null {\n try {\n const content = readFileSync(join(home, 'state', 'update.sentinel'), 'utf-8');\n return JSON.parse(content);\n } catch {\n return null;\n }\n}\n\nexport function clearSentinel(home: string, _version: string): void {\n const path = join(home, 'state', 'update.sentinel');\n if (!existsSync(path)) return;\n try {\n const sentinel: UpdateSentinel = JSON.parse(readFileSync(path, 'utf-8'));\n sentinel.status = 'success';\n writeFileSync(path, JSON.stringify(sentinel, null, 2) + '\\n');\n } catch {\n // Best effort\n }\n}\n\nexport async function hashFile(path: string): Promise<string | null> {\n try {\n const buf = await readFile(path);\n return createHash('sha256').update(buf).digest('hex');\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') return null;\n throw err;\n }\n}\n\n/**\n * Clean up stale app.staging/ from a previously interrupted update.\n */\nexport function cleanStaleStaging(stagingDir: string): void {\n if (existsSync(stagingDir)) {\n rmSync(stagingDir, { recursive: true, force: true });\n }\n}\n", "/**\n * Safety-guarded destructive ops for `reset` / `uninstall`.\n *\n * Cleanup utilities for deploy operations.\n * Key primitive: isUnsafeRemovalTarget() rejects catastrophic paths ('/',\n * '~', empty, etc.) BEFORE any caller invokes rm. Caller must always check.\n */\n\nimport { rm } from 'node:fs/promises';\nimport { homedir } from 'node:os';\nimport { resolve } from 'node:path';\n\n/**\n * True if the path is something we refuse to remove, regardless of flags.\n *\n * Rejects:\n * - empty / whitespace-only strings\n * - '/', '\\\\', or any path that resolves to root\n * - '~' (home), home dir itself, or parents of home\n * - Anything not under the user's home dir (defense-in-depth against\n * config pointing at /etc/... by mistake)\n *\n * Callers SHOULD still confirm with the user before removing even \"safe\"\n * paths; this function is a hard floor, not a substitute for confirmation.\n */\nexport function isUnsafeRemovalTarget(path: string): boolean {\n const trimmed = path.trim();\n if (trimmed === '') return true;\n if (trimmed === '~' || trimmed === '/' || trimmed === '\\\\') return true;\n const abs = resolve(trimmed);\n if (abs === '/' || abs === '') return true;\n const home = homedir();\n if (abs === home) return true;\n // Must be under home (defense in depth).\n const homeWithSep = home.endsWith('/') ? home : home + '/';\n if (!abs.startsWith(homeWithSep)) return true;\n return false;\n}\n\nexport interface RemovePlan {\n readonly path: string;\n readonly willRemove: boolean;\n readonly reason: string;\n}\n\n/**\n * Plan a remove without executing. Used by --dry-run flows in reset/uninstall.\n */\nexport function planRemoval(path: string): RemovePlan {\n if (isUnsafeRemovalTarget(path)) {\n return { path, willRemove: false, reason: 'refused: unsafe target' };\n }\n return { path, willRemove: true, reason: 'would remove recursively' };\n}\n\n/**\n * Remove a path after validating safety. Throws if the target is unsafe.\n * Returns true if the path was removed, false if it didn't exist.\n */\nexport async function removePath(path: string, opts: { dryRun?: boolean } = {}): Promise<boolean> {\n if (isUnsafeRemovalTarget(path)) {\n throw new Error(`Refused to remove unsafe target: ${path}`);\n }\n if (opts.dryRun) return true;\n try {\n await rm(path, { recursive: true });\n return true;\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') return false;\n throw err;\n }\n}\n", "/**\n * Safe recursive copy that skips non-regular-file entries Node's cp()\n * refuses to handle (EINVAL on sockets). Real runtime roots can contain\n * UNIX sockets (browser.sock, memory.sock, etc.) which are ephemeral IPC\n * endpoints \u2014 not data we want or can back up.\n *\n * Skipped: sockets, FIFOs, block devices, character devices.\n * Copied: regular files, directories, symlinks.\n */\n\nimport { cp, lstat } from 'node:fs/promises';\n\nexport interface SafeCopyOptions {\n readonly preserveTimestamps?: boolean;\n /** Overwrite existing entries at the destination. Default: false. */\n readonly force?: boolean;\n}\n\nasync function shouldCopy(src: string): Promise<boolean> {\n try {\n const s = await lstat(src);\n if (s.isSocket() || s.isFIFO() || s.isBlockDevice() || s.isCharacterDevice()) {\n return false;\n }\n return true;\n } catch {\n // Let the subsequent cp call surface the real error if any.\n return true;\n }\n}\n\nexport async function safeCopyTree(src: string, dst: string, opts: SafeCopyOptions = {}): Promise<void> {\n await cp(src, dst, {\n recursive: true,\n preserveTimestamps: opts.preserveTimestamps === true,\n force: opts.force === true,\n filter: shouldCopy,\n });\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["readFile", "writeFile", "readFile", "join", "homedir"]
|
|
7
|
+
}
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
deliverBrowseResult,
|
|
6
6
|
readPendingBrowse,
|
|
7
7
|
writePendingBrowse
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-LDKSCXGL.js";
|
|
9
9
|
import {
|
|
10
10
|
BrowserIpcServer,
|
|
11
11
|
BrowserManager,
|
|
@@ -56,7 +56,7 @@ function register(api) {
|
|
|
56
56
|
await browserIpc.start();
|
|
57
57
|
logInfo("browser", `\u{1F50C} Browser IPC listening on ${browserIpc.socketPath}`);
|
|
58
58
|
};
|
|
59
|
-
const spawnSocketPath = join(abtarsHome(), "browse-spawn.sock");
|
|
59
|
+
const spawnSocketPath = join(abtarsHome(), "browser-socket", "browse-spawn.sock");
|
|
60
60
|
try {
|
|
61
61
|
unlinkSync(spawnSocketPath);
|
|
62
62
|
} catch (err) {
|
|
@@ -128,4 +128,4 @@ export {
|
|
|
128
128
|
register,
|
|
129
129
|
browser_exports
|
|
130
130
|
};
|
|
131
|
-
//# sourceMappingURL=chunk-
|
|
131
|
+
//# sourceMappingURL=chunk-KJOCXWJ5.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/capabilities/browser/index.ts"],
|
|
4
|
+
"sourcesContent": ["import { logAndSwallow } from \"../../components/log-and-swallow.js\";\nimport { getEnv } from \"../../components/env-schema.js\";\n/**\n * Browser capability \u2014 browse-spawn IPC + browse-checker heartbeat.\n * Level 1 (lightpanda fetch) is handled by the agent via skill \u2014 no bridge code needed.\n * Level 2 (Browsie) uses runtime.spawn() via IPC socket.\n */\n\nimport { BrowserManager } from \"./browser-manager.js\";\nimport { BrowserTool } from \"./browser-tool.js\";\nimport { BrowserIpcServer } from \"./browser-ipc-server.js\";\nimport { DomainAllowlist } from \"./domain-allowlist.js\";\nimport { checkBrowseTasks, deliverBrowseResult } from \"./browse-delivery.js\";\nimport { readPendingBrowse, writePendingBrowse } from \"./abtars-browse.js\";\nimport type { PendingBrowseEntry } from \"./abtars-browse.js\";\nimport { logInfo, logWarn } from \"../../components/logger.js\";\nimport { abtarsHome } from \"../../paths.js\";\nimport type { CapabilityApi } from \"../capability.js\";\nimport * as net from \"node:net\";\nimport { join } from \"node:path\";\nimport { unlinkSync } from \"node:fs\";\n\nexport function register(api: CapabilityApi): void {\n const browserManager = new BrowserManager();\n const allowlist = DomainAllowlist.fromEnv();\n const browserTool = new BrowserTool(browserManager, allowlist);\n let browserIpc: BrowserIpcServer | null = null;\n\n const ensureBrowserIpc = async (): Promise<void> => {\n if (browserIpc || getEnv().browserDocker) return;\n browserIpc = new BrowserIpcServer(browserTool);\n await browserIpc.start();\n logInfo(\"browser\", `\uD83D\uDD0C Browser IPC listening on ${browserIpc.socketPath}`);\n };\n\n // Browse-spawn IPC \u2014 CLI sends task, bridge spawns via runtime\n const spawnSocketPath = join(abtarsHome(), \"browser-socket\", \"browse-spawn.sock\");\n try { unlinkSync(spawnSocketPath); } catch (err) { logAndSwallow(\"index\", \"op\", err); }\n\n const spawnServer = net.createServer((conn) => {\n let buf = \"\";\n conn.on(\"data\", (chunk) => {\n buf += chunk.toString();\n const nl = buf.indexOf(\"\\n\");\n if (nl === -1) return;\n const line = buf.slice(0, nl);\n buf = buf.slice(nl + 1);\n\n try {\n const { taskId, task, prompt, chatId, threadId, timeoutMs } = JSON.parse(line);\n\n const entry: PendingBrowseEntry = {\n taskId, task, chatId, threadId,\n pid: process.pid, // bridge pid \u2014 runtime manages the actual transport\n startedAt: Date.now(), timeoutMs,\n logFile: \"\", // no log file \u2014 result comes from callback\n };\n const entries = readPendingBrowse();\n entries.push(entry);\n writePendingBrowse(entries);\n\n // Fire-and-forget via runtime\n api.runtime.spawn(\"browsie\", prompt, {\n timeoutMs,\n onComplete: (_id: string, result: string) => {\n deliverBrowseResult(entry, result);\n const remaining = readPendingBrowse().filter(e => e.taskId !== taskId);\n writePendingBrowse(remaining);\n },\n onError: (_id: string, err: Error) => {\n logWarn(\"browser\", `Browsie spawn failed for ${taskId}: ${err.message}`);\n deliverBrowseResult(entry, `Browse task failed: ${err.message}`);\n const remaining = readPendingBrowse().filter(e => e.taskId !== taskId);\n writePendingBrowse(remaining);\n },\n }).then(({ taskId: spawnId }) => {\n conn.write(JSON.stringify({ ok: true, taskId, spawnId, status: \"spawned\" }) + \"\\n\");\n }).catch((err) => {\n conn.write(JSON.stringify({ ok: false, error: err instanceof Error ? err.message : String(err) }) + \"\\n\");\n });\n } catch (err) {\n conn.write(JSON.stringify({ ok: false, error: err instanceof Error ? err.message : String(err) }) + \"\\n\");\n }\n });\n conn.on(\"error\", () => {});\n });\n\n spawnServer.listen(spawnSocketPath, () => {\n logInfo(\"browser\", `\uD83D\uDD0C Browse spawn IPC listening on ${spawnSocketPath}`);\n });\n\n api.registerHeartbeatTask({\n name: \"browse-checker\",\n execute: async () => { await ensureBrowserIpc(); checkBrowseTasks(); },\n });\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
appendReminder,
|
|
5
5
|
localDate,
|
|
6
6
|
require_main
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-HEHD3GG5.js";
|
|
8
8
|
import {
|
|
9
9
|
init_log_and_swallow,
|
|
10
10
|
logAndSwallow
|
|
@@ -136,7 +136,7 @@ Usage:
|
|
|
136
136
|
}
|
|
137
137
|
mkdirSync(join(abtarsHome(), "subagents"), { recursive: true });
|
|
138
138
|
const prompt = loadBrowsePrompt(task, chatId, taskId);
|
|
139
|
-
const spawnSocket = join(abtarsHome(), "browse-spawn.sock");
|
|
139
|
+
const spawnSocket = join(abtarsHome(), "browser-socket", "browse-spawn.sock");
|
|
140
140
|
const net = await import("node:net");
|
|
141
141
|
const result = await new Promise((resolve, reject) => {
|
|
142
142
|
const conn = net.createConnection(spawnSocket);
|
|
@@ -204,4 +204,4 @@ export {
|
|
|
204
204
|
deliverBrowseResult,
|
|
205
205
|
checkBrowseTasks
|
|
206
206
|
};
|
|
207
|
-
//# sourceMappingURL=chunk-
|
|
207
|
+
//# sourceMappingURL=chunk-LDKSCXGL.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/capabilities/browser/browse-delivery.ts", "../src/capabilities/browser/abtars-browse.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Browse task delivery \u2014 write report + notify user via reminder.\n * Called from runtime.spawn() onComplete/onError callbacks.\n */\n\nimport { writeFileSync, mkdirSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { abtarsHome } from \"../../paths.js\";\nimport { logInfo, logWarn } from \"../../components/logger.js\";\nimport { localDate } from \"../../utils/date.js\";\nimport { appendReminder } from \"../../components/tasks/task-checker.js\";\nimport { readPendingBrowse, writePendingBrowse } from \"./abtars-browse.js\";\nimport type { PendingBrowseEntry } from \"./abtars-browse.js\";\n\nconst TAG = \"browse-delivery\";\n\nconst subagentsDir = (): string => join(abtarsHome(), \"subagents\");\n\n/** Deliver result for a browse task. Called by runtime.spawn() callback. */\nexport function deliverBrowseResult(entry: PendingBrowseEntry, result: string): void {\n const dir = subagentsDir();\n mkdirSync(dir, { recursive: true });\n const date = localDate();\n const reportPath = join(dir, `browse_${entry.taskId}_${date}.md`);\n writeFileSync(reportPath, result || \"(no output captured)\", \"utf-8\");\n\n const taskLabel = entry.task.length > 200 ? entry.task.slice(0, 200) + \"\u2026\" : entry.task;\n const msg = `\uD83C\uDF10 Browse task complete: ${taskLabel}\\nReport: ${reportPath}`;\n appendReminder({ chatId: entry.chatId, message: msg, createdAt: Date.now(), threadId: entry.threadId });\n logInfo(TAG, `\uD83C\uDF10 Browse \"${taskLabel}\" finished \u2014 ${reportPath}`);\n}\n\n/** Safety net: check for stale pending entries (runtime handles timeouts, this catches orphans). */\nexport function checkBrowseTasks(): void {\n const entries = readPendingBrowse();\n if (entries.length === 0) return;\n\n const now = Date.now();\n const remaining: PendingBrowseEntry[] = [];\n\n for (const entry of entries) {\n const elapsed = now - entry.startedAt;\n if (elapsed > entry.timeoutMs + 60_000) {\n // Stale entry \u2014 runtime should have cleaned up, remove orphan\n const taskLabel = entry.task.length > 200 ? entry.task.slice(0, 200) + \"\u2026\" : entry.task;\n logWarn(TAG, `Removing stale browse entry: ${taskLabel} (${Math.round(elapsed / 1000)}s old)`);\n } else {\n remaining.push(entry);\n }\n }\n\n if (remaining.length !== entries.length) writePendingBrowse(remaining);\n}\n", "#!/usr/bin/env node\n/**\n * abtars-browse \u2014 spawn a browser subagent for autonomous web tasks.\n *\n * Usage:\n * abtars-browse --task \"check X notifications\" --chat-id 7773842843\n * abtars-browse --task \"post on FB\" --chat-id 123 --timeout 600\n * abtars-browse --task \"research topic\" --chat-id 123 --dry-run\n *\n * Returns immediately. The subagent runs detached and results are delivered\n * via pending_reminders.json \u2192 bridge picks up \u2192 sends to chat.\n */\nimport { readFileSync, writeFileSync, existsSync, mkdirSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { abtarsHome } from \"../../paths.js\";\nimport { logAndSwallow } from \"../../components/log-and-swallow.js\";\n\nconst TAG = \"browse\";\nimport { randomBytes } from \"node:crypto\";\nimport { config as loadDotenv } from \"dotenv\";\nimport { localDate } from \"../../utils/date.js\";\n\n// --- Types ---\n\nexport interface BrowseArgs {\n task?: string;\n chatId?: string;\n threadId?: string;\n timeout?: string;\n engine?: string;\n dryRun: boolean;\n}\n\nexport interface PendingBrowseEntry {\n taskId: string;\n task: string;\n chatId: number;\n threadId?: number;\n pid: number;\n startedAt: number;\n timeoutMs: number;\n logFile: string;\n}\n\n// --- Arg parsing ---\n\nexport function parseArgs(argv: string[]): BrowseArgs {\n const args = argv.slice(2);\n const parsed: BrowseArgs = { dryRun: false };\n for (let i = 0; i < args.length; i++) {\n switch (args[i]) {\n case \"--task\": parsed.task = args[++i] ?? \"\"; break;\n case \"--chat-id\": parsed.chatId = args[++i] ?? \"\"; break;\n case \"--thread-id\": parsed.threadId = args[++i] ?? \"\"; break;\n case \"--timeout\": parsed.timeout = args[++i] ?? \"\"; break;\n case \"--engine\": parsed.engine = args[++i] ?? \"\"; break;\n case \"--dry-run\": parsed.dryRun = true; break;\n }\n }\n return parsed;\n}\n\nexport function validateArgs(args: BrowseArgs): { ok: true; task: string; chatId: number; threadId?: number; timeoutMs: number } | { ok: false; error: string } {\n if (!args.task) return { ok: false, error: \"--task is required\" };\n if (!args.chatId) return { ok: false, error: \"--chat-id is required\" };\n const chatId = parseInt(args.chatId, 10);\n if (!Number.isFinite(chatId)) return { ok: false, error: \"invalid --chat-id\" };\n const threadId = args.threadId ? parseInt(args.threadId, 10) : undefined;\n const timeoutMs = args.timeout ? parseInt(args.timeout, 10) * 1000 : 5 * 60 * 1000;\n if (!Number.isFinite(timeoutMs)) return { ok: false, error: \"invalid --timeout\" };\n const task = args.task.length > 2000 ? args.task.slice(0, 2000) + \"\u2026\" : args.task;\n return { ok: true, task, chatId, threadId, timeoutMs };\n}\n\n// --- Prompt loading ---\n\nexport function loadBrowsePrompt(task: string, _chatId: number, taskId?: string): string {\n const path = join(abtarsHome(), \"prompts\", \"browsing_prompt.md\");\n\n if (!existsSync(path)) {\n throw new Error(`browsing_prompt.md not found at ${path}`);\n }\n const template = readFileSync(path, \"utf-8\");\n\n const date = localDate();\n const reportFile = `browse_${taskId ?? \"unknown\"}_${date}.md`;\n\n const vars: Record<string, string> = {\n TASK: task,\n TASK_ID: taskId ?? \"unknown\",\n DATE: date,\n REPORT_FILE: reportFile,\n };\n\n let result = template;\n for (const [key, value] of Object.entries(vars)) {\n result = result.replaceAll(`\\${${key}}`, value);\n }\n return result;\n}\n\n// --- Pending browse file ---\n\nconst pendingPath = (): string => join(abtarsHome(), \"workspace\", \"browse\", \"pending_browse.json\");\n\nexport function readPendingBrowse(): PendingBrowseEntry[] {\n const p = pendingPath();\n if (!existsSync(p)) return [];\n try { return JSON.parse(readFileSync(p, \"utf-8\")) as PendingBrowseEntry[]; }\n catch (err) { logAndSwallow(TAG, \"readPendingBrowse\", err); return []; }\n}\n\nexport function writePendingBrowse(entries: PendingBrowseEntry[]): void {\n const dir = join(abtarsHome(), \"workspace\", \"browse\");\n mkdirSync(dir, { recursive: true });\n writeFileSync(pendingPath(), JSON.stringify(entries, null, 2), \"utf-8\");\n}\n\n// --- Main ---\n\nexport async function main(argv: string[] = process.argv): Promise<void> {\n if (argv.includes(\"--help\")) {\n console.log(`abtars-browse \u2014 delegate a browser task to the Browsie agent.\n\nUsage:\n abtars-browse --task \"check X notifications\" --chat-id ID\n abtars-browse --task \"research topic\" --chat-id ID --timeout 600\n abtars-browse --task \"research topic\" --chat-id ID --dry-run`);\n process.exit(0);\n }\n\n loadDotenv({ path: join(abtarsHome(), \".env\") });\n const raw = parseArgs(argv);\n const validation = validateArgs(raw);\n\n if (!validation.ok) {\n console.log(JSON.stringify({ ok: false, error: validation.error }));\n process.exit(1);\n }\n\n const { task, chatId, threadId, timeoutMs } = validation;\n const taskId = randomBytes(3).toString(\"hex\");\n\n // Dry-run: print prompt and exit\n if (raw.dryRun) {\n const prompt = loadBrowsePrompt(task, chatId, taskId);\n process.stdout.write(prompt + \"\\n\");\n return;\n }\n\n mkdirSync(join(abtarsHome(), \"subagents\"), { recursive: true });\n\n const prompt = loadBrowsePrompt(task, chatId, taskId);\n\n // Send spawn request to bridge via IPC\n const spawnSocket = join(abtarsHome(), \"browse-spawn.sock\");\n const net = await import(\"node:net\");\n const result = await new Promise<{ ok: boolean; taskId?: string; error?: string }>((resolve, reject) => {\n const conn = net.createConnection(spawnSocket);\n conn.on(\"connect\", () => {\n conn.write(JSON.stringify({ taskId, task, prompt, chatId, threadId, timeoutMs }) + \"\\n\");\n });\n let buf = \"\";\n conn.on(\"data\", (chunk) => {\n buf += chunk.toString();\n const nl = buf.indexOf(\"\\n\");\n if (nl === -1) return;\n conn.end();\n try { resolve(JSON.parse(buf.slice(0, nl))); } catch (e) { reject(e); }\n });\n conn.on(\"error\", reject);\n conn.setTimeout(10_000, () => { conn.destroy(); reject(new Error(\"IPC timeout\")); });\n });\n\n console.log(JSON.stringify(result));\n}\n\nconst isDirectRun = process.argv[1]?.endsWith(\"abtars-browse.ts\") ||\n process.argv[1]?.endsWith(\"abtars-browse.js\");\nif (isDirectRun) main();\n"],
|
|
5
|
-
"mappings": "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
|
|
4
|
+
"sourcesContent": ["/**\n * Browse task delivery \u2014 write report + notify user via reminder.\n * Called from runtime.spawn() onComplete/onError callbacks.\n */\n\nimport { writeFileSync, mkdirSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { abtarsHome } from \"../../paths.js\";\nimport { logInfo, logWarn } from \"../../components/logger.js\";\nimport { localDate } from \"../../utils/date.js\";\nimport { appendReminder } from \"../../components/tasks/task-checker.js\";\nimport { readPendingBrowse, writePendingBrowse } from \"./abtars-browse.js\";\nimport type { PendingBrowseEntry } from \"./abtars-browse.js\";\n\nconst TAG = \"browse-delivery\";\n\nconst subagentsDir = (): string => join(abtarsHome(), \"subagents\");\n\n/** Deliver result for a browse task. Called by runtime.spawn() callback. */\nexport function deliverBrowseResult(entry: PendingBrowseEntry, result: string): void {\n const dir = subagentsDir();\n mkdirSync(dir, { recursive: true });\n const date = localDate();\n const reportPath = join(dir, `browse_${entry.taskId}_${date}.md`);\n writeFileSync(reportPath, result || \"(no output captured)\", \"utf-8\");\n\n const taskLabel = entry.task.length > 200 ? entry.task.slice(0, 200) + \"\u2026\" : entry.task;\n const msg = `\uD83C\uDF10 Browse task complete: ${taskLabel}\\nReport: ${reportPath}`;\n appendReminder({ chatId: entry.chatId, message: msg, createdAt: Date.now(), threadId: entry.threadId });\n logInfo(TAG, `\uD83C\uDF10 Browse \"${taskLabel}\" finished \u2014 ${reportPath}`);\n}\n\n/** Safety net: check for stale pending entries (runtime handles timeouts, this catches orphans). */\nexport function checkBrowseTasks(): void {\n const entries = readPendingBrowse();\n if (entries.length === 0) return;\n\n const now = Date.now();\n const remaining: PendingBrowseEntry[] = [];\n\n for (const entry of entries) {\n const elapsed = now - entry.startedAt;\n if (elapsed > entry.timeoutMs + 60_000) {\n // Stale entry \u2014 runtime should have cleaned up, remove orphan\n const taskLabel = entry.task.length > 200 ? entry.task.slice(0, 200) + \"\u2026\" : entry.task;\n logWarn(TAG, `Removing stale browse entry: ${taskLabel} (${Math.round(elapsed / 1000)}s old)`);\n } else {\n remaining.push(entry);\n }\n }\n\n if (remaining.length !== entries.length) writePendingBrowse(remaining);\n}\n", "#!/usr/bin/env node\n/**\n * abtars-browse \u2014 spawn a browser subagent for autonomous web tasks.\n *\n * Usage:\n * abtars-browse --task \"check X notifications\" --chat-id 7773842843\n * abtars-browse --task \"post on FB\" --chat-id 123 --timeout 600\n * abtars-browse --task \"research topic\" --chat-id 123 --dry-run\n *\n * Returns immediately. The subagent runs detached and results are delivered\n * via pending_reminders.json \u2192 bridge picks up \u2192 sends to chat.\n */\nimport { readFileSync, writeFileSync, existsSync, mkdirSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { abtarsHome } from \"../../paths.js\";\nimport { logAndSwallow } from \"../../components/log-and-swallow.js\";\n\nconst TAG = \"browse\";\nimport { randomBytes } from \"node:crypto\";\nimport { config as loadDotenv } from \"dotenv\";\nimport { localDate } from \"../../utils/date.js\";\n\n// --- Types ---\n\nexport interface BrowseArgs {\n task?: string;\n chatId?: string;\n threadId?: string;\n timeout?: string;\n engine?: string;\n dryRun: boolean;\n}\n\nexport interface PendingBrowseEntry {\n taskId: string;\n task: string;\n chatId: number;\n threadId?: number;\n pid: number;\n startedAt: number;\n timeoutMs: number;\n logFile: string;\n}\n\n// --- Arg parsing ---\n\nexport function parseArgs(argv: string[]): BrowseArgs {\n const args = argv.slice(2);\n const parsed: BrowseArgs = { dryRun: false };\n for (let i = 0; i < args.length; i++) {\n switch (args[i]) {\n case \"--task\": parsed.task = args[++i] ?? \"\"; break;\n case \"--chat-id\": parsed.chatId = args[++i] ?? \"\"; break;\n case \"--thread-id\": parsed.threadId = args[++i] ?? \"\"; break;\n case \"--timeout\": parsed.timeout = args[++i] ?? \"\"; break;\n case \"--engine\": parsed.engine = args[++i] ?? \"\"; break;\n case \"--dry-run\": parsed.dryRun = true; break;\n }\n }\n return parsed;\n}\n\nexport function validateArgs(args: BrowseArgs): { ok: true; task: string; chatId: number; threadId?: number; timeoutMs: number } | { ok: false; error: string } {\n if (!args.task) return { ok: false, error: \"--task is required\" };\n if (!args.chatId) return { ok: false, error: \"--chat-id is required\" };\n const chatId = parseInt(args.chatId, 10);\n if (!Number.isFinite(chatId)) return { ok: false, error: \"invalid --chat-id\" };\n const threadId = args.threadId ? parseInt(args.threadId, 10) : undefined;\n const timeoutMs = args.timeout ? parseInt(args.timeout, 10) * 1000 : 5 * 60 * 1000;\n if (!Number.isFinite(timeoutMs)) return { ok: false, error: \"invalid --timeout\" };\n const task = args.task.length > 2000 ? args.task.slice(0, 2000) + \"\u2026\" : args.task;\n return { ok: true, task, chatId, threadId, timeoutMs };\n}\n\n// --- Prompt loading ---\n\nexport function loadBrowsePrompt(task: string, _chatId: number, taskId?: string): string {\n const path = join(abtarsHome(), \"prompts\", \"browsing_prompt.md\");\n\n if (!existsSync(path)) {\n throw new Error(`browsing_prompt.md not found at ${path}`);\n }\n const template = readFileSync(path, \"utf-8\");\n\n const date = localDate();\n const reportFile = `browse_${taskId ?? \"unknown\"}_${date}.md`;\n\n const vars: Record<string, string> = {\n TASK: task,\n TASK_ID: taskId ?? \"unknown\",\n DATE: date,\n REPORT_FILE: reportFile,\n };\n\n let result = template;\n for (const [key, value] of Object.entries(vars)) {\n result = result.replaceAll(`\\${${key}}`, value);\n }\n return result;\n}\n\n// --- Pending browse file ---\n\nconst pendingPath = (): string => join(abtarsHome(), \"workspace\", \"browse\", \"pending_browse.json\");\n\nexport function readPendingBrowse(): PendingBrowseEntry[] {\n const p = pendingPath();\n if (!existsSync(p)) return [];\n try { return JSON.parse(readFileSync(p, \"utf-8\")) as PendingBrowseEntry[]; }\n catch (err) { logAndSwallow(TAG, \"readPendingBrowse\", err); return []; }\n}\n\nexport function writePendingBrowse(entries: PendingBrowseEntry[]): void {\n const dir = join(abtarsHome(), \"workspace\", \"browse\");\n mkdirSync(dir, { recursive: true });\n writeFileSync(pendingPath(), JSON.stringify(entries, null, 2), \"utf-8\");\n}\n\n// --- Main ---\n\nexport async function main(argv: string[] = process.argv): Promise<void> {\n if (argv.includes(\"--help\")) {\n console.log(`abtars-browse \u2014 delegate a browser task to the Browsie agent.\n\nUsage:\n abtars-browse --task \"check X notifications\" --chat-id ID\n abtars-browse --task \"research topic\" --chat-id ID --timeout 600\n abtars-browse --task \"research topic\" --chat-id ID --dry-run`);\n process.exit(0);\n }\n\n loadDotenv({ path: join(abtarsHome(), \".env\") });\n const raw = parseArgs(argv);\n const validation = validateArgs(raw);\n\n if (!validation.ok) {\n console.log(JSON.stringify({ ok: false, error: validation.error }));\n process.exit(1);\n }\n\n const { task, chatId, threadId, timeoutMs } = validation;\n const taskId = randomBytes(3).toString(\"hex\");\n\n // Dry-run: print prompt and exit\n if (raw.dryRun) {\n const prompt = loadBrowsePrompt(task, chatId, taskId);\n process.stdout.write(prompt + \"\\n\");\n return;\n }\n\n mkdirSync(join(abtarsHome(), \"subagents\"), { recursive: true });\n\n const prompt = loadBrowsePrompt(task, chatId, taskId);\n\n // Send spawn request to bridge via IPC\n const spawnSocket = join(abtarsHome(), \"browser-socket\", \"browse-spawn.sock\");\n const net = await import(\"node:net\");\n const result = await new Promise<{ ok: boolean; taskId?: string; error?: string }>((resolve, reject) => {\n const conn = net.createConnection(spawnSocket);\n conn.on(\"connect\", () => {\n conn.write(JSON.stringify({ taskId, task, prompt, chatId, threadId, timeoutMs }) + \"\\n\");\n });\n let buf = \"\";\n conn.on(\"data\", (chunk) => {\n buf += chunk.toString();\n const nl = buf.indexOf(\"\\n\");\n if (nl === -1) return;\n conn.end();\n try { resolve(JSON.parse(buf.slice(0, nl))); } catch (e) { reject(e); }\n });\n conn.on(\"error\", reject);\n conn.setTimeout(10_000, () => { conn.destroy(); reject(new Error(\"IPC timeout\")); });\n });\n\n console.log(JSON.stringify(result));\n}\n\nconst isDirectRun = process.argv[1]?.endsWith(\"abtars-browse.ts\") ||\n process.argv[1]?.endsWith(\"abtars-browse.js\");\nif (isDirectRun) main();\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["writeFileSync", "mkdirSync", "join", "loadDotenv", "prompt", "TAG", "join", "mkdirSync", "writeFileSync"]
|
|
7
7
|
}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { createRequire as __bundleCreateRequire } from 'node:module'; import { fileURLToPath as __bundleFileURLToPath } from 'node:url'; import { dirname as __bundleDirname } from 'node:path'; const require = __bundleCreateRequire(import.meta.url); const __chunk_filename = __bundleFileURLToPath(import.meta.url); const __chunk_dirname = __bundleDirname(__chunk_filename);
|
|
3
|
+
import {
|
|
4
|
+
checkBrowseTasks,
|
|
5
|
+
deliverBrowseResult,
|
|
6
|
+
readPendingBrowse,
|
|
7
|
+
writePendingBrowse
|
|
8
|
+
} from "./chunk-LDKSCXGL.js";
|
|
9
|
+
import {
|
|
10
|
+
BrowserIpcServer,
|
|
11
|
+
BrowserManager,
|
|
12
|
+
BrowserTool,
|
|
13
|
+
DomainAllowlist
|
|
14
|
+
} from "./chunk-KSEIWT4T.js";
|
|
15
|
+
import {
|
|
16
|
+
getEnv,
|
|
17
|
+
init_env_schema
|
|
18
|
+
} from "./chunk-PZE3J7ER.js";
|
|
19
|
+
import {
|
|
20
|
+
init_logger,
|
|
21
|
+
logError,
|
|
22
|
+
logInfo,
|
|
23
|
+
logWarn
|
|
24
|
+
} from "./chunk-2BY6I4P5.js";
|
|
25
|
+
import {
|
|
26
|
+
abtarsHome,
|
|
27
|
+
init_paths
|
|
28
|
+
} from "./chunk-MJ6PHMOK.js";
|
|
29
|
+
import {
|
|
30
|
+
__export
|
|
31
|
+
} from "./chunk-7K2YZTLD.js";
|
|
32
|
+
|
|
33
|
+
// src/capabilities/browser/index.ts
|
|
34
|
+
var browser_exports = {};
|
|
35
|
+
__export(browser_exports, {
|
|
36
|
+
register: () => register
|
|
37
|
+
});
|
|
38
|
+
init_logger();
|
|
39
|
+
init_env_schema();
|
|
40
|
+
init_paths();
|
|
41
|
+
import * as net from "node:net";
|
|
42
|
+
import { join } from "node:path";
|
|
43
|
+
import { unlinkSync, mkdirSync, chmodSync } from "node:fs";
|
|
44
|
+
function register(api) {
|
|
45
|
+
const browserManager = new BrowserManager();
|
|
46
|
+
const allowlist = DomainAllowlist.fromEnv();
|
|
47
|
+
const browserTool = new BrowserTool(browserManager, allowlist);
|
|
48
|
+
let browserIpc = null;
|
|
49
|
+
const ensureBrowserIpc = async () => {
|
|
50
|
+
if (browserIpc || getEnv().browserDocker) return;
|
|
51
|
+
browserIpc = new BrowserIpcServer(browserTool);
|
|
52
|
+
await browserIpc.start();
|
|
53
|
+
logInfo("browser", `\u{1F50C} Browser IPC listening on ${browserIpc.socketPath}`);
|
|
54
|
+
};
|
|
55
|
+
const spawnSocketPath = join(abtarsHome(), "browser-socket", "browse-spawn.sock");
|
|
56
|
+
try {
|
|
57
|
+
mkdirSync(join(abtarsHome(), "browser-socket"), { recursive: true, mode: 448 });
|
|
58
|
+
try {
|
|
59
|
+
unlinkSync(spawnSocketPath);
|
|
60
|
+
} catch {
|
|
61
|
+
}
|
|
62
|
+
try {
|
|
63
|
+
chmodSync(join(abtarsHome(), "browser-socket"), 448);
|
|
64
|
+
} catch {
|
|
65
|
+
}
|
|
66
|
+
const spawnServer = net.createServer((conn) => {
|
|
67
|
+
let buf = "";
|
|
68
|
+
conn.on("data", (chunk) => {
|
|
69
|
+
buf += chunk.toString();
|
|
70
|
+
const nl = buf.indexOf("\n");
|
|
71
|
+
if (nl === -1) return;
|
|
72
|
+
const line = buf.slice(0, nl);
|
|
73
|
+
buf = buf.slice(nl + 1);
|
|
74
|
+
try {
|
|
75
|
+
const { taskId, task, prompt, chatId, threadId, timeoutMs } = JSON.parse(line);
|
|
76
|
+
const entry = {
|
|
77
|
+
taskId,
|
|
78
|
+
task,
|
|
79
|
+
chatId,
|
|
80
|
+
threadId,
|
|
81
|
+
pid: process.pid,
|
|
82
|
+
// bridge pid — runtime manages the actual transport
|
|
83
|
+
startedAt: Date.now(),
|
|
84
|
+
timeoutMs,
|
|
85
|
+
logFile: ""
|
|
86
|
+
// no log file — result comes from callback
|
|
87
|
+
};
|
|
88
|
+
const entries = readPendingBrowse();
|
|
89
|
+
entries.push(entry);
|
|
90
|
+
writePendingBrowse(entries);
|
|
91
|
+
api.runtime.spawn("browsie", prompt, {
|
|
92
|
+
timeoutMs,
|
|
93
|
+
onComplete: (_id, result) => {
|
|
94
|
+
deliverBrowseResult(entry, result);
|
|
95
|
+
const remaining = readPendingBrowse().filter((e) => e.taskId !== taskId);
|
|
96
|
+
writePendingBrowse(remaining);
|
|
97
|
+
},
|
|
98
|
+
onError: (_id, err) => {
|
|
99
|
+
logWarn("browser", `Browsie spawn failed for ${taskId}: ${err.message}`);
|
|
100
|
+
deliverBrowseResult(entry, `Browse task failed: ${err.message}`);
|
|
101
|
+
const remaining = readPendingBrowse().filter((e) => e.taskId !== taskId);
|
|
102
|
+
writePendingBrowse(remaining);
|
|
103
|
+
}
|
|
104
|
+
}).then(({ taskId: spawnId }) => {
|
|
105
|
+
conn.write(JSON.stringify({ ok: true, taskId, spawnId, status: "spawned" }) + "\n");
|
|
106
|
+
}).catch((err) => {
|
|
107
|
+
conn.write(JSON.stringify({ ok: false, error: err instanceof Error ? err.message : String(err) }) + "\n");
|
|
108
|
+
});
|
|
109
|
+
} catch (err) {
|
|
110
|
+
conn.write(JSON.stringify({ ok: false, error: err instanceof Error ? err.message : String(err) }) + "\n");
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
conn.on("error", () => {
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
spawnServer.on("error", (err) => {
|
|
117
|
+
logError("browser", `\u26A0\uFE0F Browse-spawn IPC socket error \u2014 browser degraded: ${err.message}`);
|
|
118
|
+
});
|
|
119
|
+
spawnServer.listen(spawnSocketPath, () => {
|
|
120
|
+
logInfo("browser", `\u{1F50C} Browse spawn IPC listening on ${spawnSocketPath}`);
|
|
121
|
+
});
|
|
122
|
+
} catch (err) {
|
|
123
|
+
logError("browser", `\u26A0\uFE0F Browse-spawn IPC failed \u2014 browser disabled: ${err instanceof Error ? err.message : String(err)}`);
|
|
124
|
+
}
|
|
125
|
+
api.registerHeartbeatTask({
|
|
126
|
+
name: "browse-checker",
|
|
127
|
+
execute: async () => {
|
|
128
|
+
await ensureBrowserIpc();
|
|
129
|
+
checkBrowseTasks();
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export {
|
|
135
|
+
register,
|
|
136
|
+
browser_exports
|
|
137
|
+
};
|
|
138
|
+
//# sourceMappingURL=chunk-MNKLPRGY.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/capabilities/browser/index.ts"],
|
|
4
|
+
"sourcesContent": ["import { logInfo, logWarn, logError } from \"../../components/logger.js\";\nimport { getEnv } from \"../../components/env-schema.js\";\n/**\n * Browser capability \u2014 browse-spawn IPC + browse-checker heartbeat.\n * Level 1 (lightpanda fetch) is handled by the agent via skill \u2014 no bridge code needed.\n * Level 2 (Browsie) uses runtime.spawn() via IPC socket.\n */\n\nimport { BrowserManager } from \"./browser-manager.js\";\nimport { BrowserTool } from \"./browser-tool.js\";\nimport { BrowserIpcServer } from \"./browser-ipc-server.js\";\nimport { DomainAllowlist } from \"./domain-allowlist.js\";\nimport { checkBrowseTasks, deliverBrowseResult } from \"./browse-delivery.js\";\nimport { readPendingBrowse, writePendingBrowse } from \"./abtars-browse.js\";\nimport type { PendingBrowseEntry } from \"./abtars-browse.js\";\nimport { abtarsHome } from \"../../paths.js\";\nimport type { CapabilityApi } from \"../capability.js\";\nimport * as net from \"node:net\";\nimport { join } from \"node:path\";\nimport { unlinkSync, mkdirSync, chmodSync } from \"node:fs\";\n\nexport function register(api: CapabilityApi): void {\n const browserManager = new BrowserManager();\n const allowlist = DomainAllowlist.fromEnv();\n const browserTool = new BrowserTool(browserManager, allowlist);\n let browserIpc: BrowserIpcServer | null = null;\n\n const ensureBrowserIpc = async (): Promise<void> => {\n if (browserIpc || getEnv().browserDocker) return;\n browserIpc = new BrowserIpcServer(browserTool);\n await browserIpc.start();\n logInfo(\"browser\", `\uD83D\uDD0C Browser IPC listening on ${browserIpc.socketPath}`);\n };\n\n // Browse-spawn IPC \u2014 CLI sends task, bridge spawns via runtime\n const spawnSocketPath = join(abtarsHome(), \"browser-socket\", \"browse-spawn.sock\");\n try {\n mkdirSync(join(abtarsHome(), \"browser-socket\"), { recursive: true, mode: 0o700 });\n try { unlinkSync(spawnSocketPath); } catch { /* doesn't exist \u2014 fine */ }\n try { chmodSync(join(abtarsHome(), \"browser-socket\"), 0o700); } catch { /* best effort */ }\n\n const spawnServer = net.createServer((conn) => {\n let buf = \"\";\n conn.on(\"data\", (chunk) => {\n buf += chunk.toString();\n const nl = buf.indexOf(\"\\n\");\n if (nl === -1) return;\n const line = buf.slice(0, nl);\n buf = buf.slice(nl + 1);\n\n try {\n const { taskId, task, prompt, chatId, threadId, timeoutMs } = JSON.parse(line);\n\n const entry: PendingBrowseEntry = {\n taskId, task, chatId, threadId,\n pid: process.pid, // bridge pid \u2014 runtime manages the actual transport\n startedAt: Date.now(), timeoutMs,\n logFile: \"\", // no log file \u2014 result comes from callback\n };\n const entries = readPendingBrowse();\n entries.push(entry);\n writePendingBrowse(entries);\n\n // Fire-and-forget via runtime\n api.runtime.spawn(\"browsie\", prompt, {\n timeoutMs,\n onComplete: (_id: string, result: string) => {\n deliverBrowseResult(entry, result);\n const remaining = readPendingBrowse().filter(e => e.taskId !== taskId);\n writePendingBrowse(remaining);\n },\n onError: (_id: string, err: Error) => {\n logWarn(\"browser\", `Browsie spawn failed for ${taskId}: ${err.message}`);\n deliverBrowseResult(entry, `Browse task failed: ${err.message}`);\n const remaining = readPendingBrowse().filter(e => e.taskId !== taskId);\n writePendingBrowse(remaining);\n },\n }).then(({ taskId: spawnId }) => {\n conn.write(JSON.stringify({ ok: true, taskId, spawnId, status: \"spawned\" }) + \"\\n\");\n }).catch((err) => {\n conn.write(JSON.stringify({ ok: false, error: err instanceof Error ? err.message : String(err) }) + \"\\n\");\n });\n } catch (err) {\n conn.write(JSON.stringify({ ok: false, error: err instanceof Error ? err.message : String(err) }) + \"\\n\");\n }\n });\n conn.on(\"error\", () => {});\n });\n\n spawnServer.on(\"error\", (err: Error) => {\n logError(\"browser\", `\u26A0\uFE0F Browse-spawn IPC socket error \u2014 browser degraded: ${err.message}`);\n });\n\n spawnServer.listen(spawnSocketPath, () => {\n logInfo(\"browser\", `\uD83D\uDD0C Browse spawn IPC listening on ${spawnSocketPath}`);\n });\n } catch (err) {\n logError(\"browser\", `\u26A0\uFE0F Browse-spawn IPC failed \u2014 browser disabled: ${err instanceof Error ? err.message : String(err)}`);\n }\n\n api.registerHeartbeatTask({\n name: \"browse-checker\",\n execute: async () => { await ensureBrowserIpc(); checkBrowseTasks(); },\n });\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|