@proagentstore/cli 0.3.0 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser-runner/runner.js +34 -7
- package/dist/index.js +14 -16
- package/package.json +1 -1
|
@@ -377,7 +377,9 @@ export class LocalRunner {
|
|
|
377
377
|
this.store.putTask(task);
|
|
378
378
|
this.addTaskEvent(task, "task.completed", `Task completed: ${task.type}`, output);
|
|
379
379
|
await this.endTakeover(taskId);
|
|
380
|
-
|
|
380
|
+
// This path only CLEARED a challenge — the form was NOT submitted (output.submitted
|
|
381
|
+
// is false). Report it accurately so the console doesn't show a false "submitted".
|
|
382
|
+
return { submitted: false, resumed: true, output };
|
|
381
383
|
}
|
|
382
384
|
/**
|
|
383
385
|
* Always attach files via Playwright, never a native OS dialog: intercept any
|
|
@@ -584,6 +586,19 @@ export class LocalRunner {
|
|
|
584
586
|
}
|
|
585
587
|
});
|
|
586
588
|
}
|
|
589
|
+
/** Close every page except the active one. ATS forms open popups/extra tabs that
|
|
590
|
+
* otherwise stay open in the persistent context until shutdown; over many
|
|
591
|
+
* applications they accumulate (memory/handles). Called when a task finishes. */
|
|
592
|
+
async closeStalePages() {
|
|
593
|
+
const ctx = this.browserContext;
|
|
594
|
+
if (!ctx)
|
|
595
|
+
return;
|
|
596
|
+
for (const p of ctx.pages()) {
|
|
597
|
+
if (p !== this.activePage && !p.isClosed()) {
|
|
598
|
+
await p.close().catch(() => undefined);
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
}
|
|
587
602
|
/** The page the brain drives and the human takes over — created on demand. */
|
|
588
603
|
async getActivePage() {
|
|
589
604
|
const context = await this.getBrowserContext();
|
|
@@ -716,28 +731,39 @@ export class LocalRunner {
|
|
|
716
731
|
/** Whether the brain can resume: a solved captcha (auto), a human "Resume" for a stuck step, or a provided value. */
|
|
717
732
|
async browserHandoffStatus(taskId) {
|
|
718
733
|
const session = this.takeovers.get(taskId);
|
|
719
|
-
|
|
734
|
+
// No live takeover session (the runner restarted mid-handoff, or it expired): stay
|
|
735
|
+
// UNRESOLVED. The old code fell through and relaunched a blank page via
|
|
736
|
+
// getActivePage(), which detected no challenge and reported solved:true — so the
|
|
737
|
+
// brain resumed the application WITHOUT the human's captcha/value. A status poll
|
|
738
|
+
// must never relaunch the browser or claim a lost handoff is done.
|
|
739
|
+
if (!session)
|
|
740
|
+
return { solved: false, challenge: null };
|
|
741
|
+
const page = session.page;
|
|
720
742
|
if (page.isClosed())
|
|
721
743
|
return { solved: true, challenge: null };
|
|
722
744
|
// A needs_input handoff resumes once the user supplies the value.
|
|
723
|
-
if (session
|
|
745
|
+
if (session.reason === "needs_input")
|
|
724
746
|
return { solved: !!session.inputValue, challenge: null, value: session.inputValue };
|
|
725
747
|
// A stuck handoff resumes only when the human explicitly clicks Resume —
|
|
726
748
|
// there's nothing to auto-detect.
|
|
727
|
-
if (session
|
|
749
|
+
if (session.reason === "stuck")
|
|
728
750
|
return { solved: !!session.humanDone, challenge: null };
|
|
729
751
|
// A challenge resumes when the token/widget clears OR the human clicks Done —
|
|
730
752
|
// custom captchas (e.g. PageUp's "not a robot") have no detectable token, so
|
|
731
753
|
// the human's explicit Done is the authority; never strand them.
|
|
732
754
|
const challenge = await detectHumanChallenge(page);
|
|
733
|
-
const solved = !challenge || (await challengeSolved(page)) || !!session
|
|
755
|
+
const solved = !challenge || (await challengeSolved(page)) || !!session.humanDone;
|
|
734
756
|
return { solved, challenge };
|
|
735
757
|
}
|
|
736
758
|
/** The user supplied the value the agent asked for (ask-and-hold). */
|
|
737
759
|
browserSubmitInput(taskId, value) {
|
|
738
760
|
const session = this.takeovers.get(taskId);
|
|
739
|
-
|
|
740
|
-
|
|
761
|
+
// No live takeover (session expired / runner restarted): the value can't be
|
|
762
|
+
// delivered. Don't discard it silently AND resurrect the already-terminal task as
|
|
763
|
+
// "running" — report failure so the console can say "session expired, re-run".
|
|
764
|
+
if (!session)
|
|
765
|
+
return { ok: false };
|
|
766
|
+
session.inputValue = value;
|
|
741
767
|
const task = this.store.getTask(taskId);
|
|
742
768
|
if (task) {
|
|
743
769
|
task.status = "running";
|
|
@@ -777,6 +803,7 @@ export class LocalRunner {
|
|
|
777
803
|
this.store.putTask(task);
|
|
778
804
|
this.addTaskEvent(task, success ? "task.completed" : "task.failed", detail || `Application ${outcome}`, { outcome, detail });
|
|
779
805
|
}
|
|
806
|
+
await this.closeStalePages().catch(() => undefined);
|
|
780
807
|
return { ok: true };
|
|
781
808
|
}
|
|
782
809
|
ensureChromiumInstalled() {
|
package/dist/index.js
CHANGED
|
@@ -171,6 +171,7 @@ var initCommand = new Command2("init").description("Scaffold a new ProAgentStore
|
|
|
171
171
|
category: "general",
|
|
172
172
|
model: "@cf/meta/llama-3.2-3b-instruct",
|
|
173
173
|
template,
|
|
174
|
+
capabilities: { surfaces: [], runtime: null, workflow: null },
|
|
174
175
|
serverConfig: {
|
|
175
176
|
durableObject: template === "worker",
|
|
176
177
|
cron: template === "cron" ? "0 8 * * *" : void 0,
|
|
@@ -378,7 +379,6 @@ import { Command as Command3 } from "commander";
|
|
|
378
379
|
var CONFIG_DIR = join3(homedir(), ".config", "proagentstore");
|
|
379
380
|
var TOKEN_FILE = join3(CONFIG_DIR, "session.json");
|
|
380
381
|
var API_BASE = "https://api.proagentstore.online";
|
|
381
|
-
var FAS_API = "https://api.freeappstore.online";
|
|
382
382
|
function loadSession() {
|
|
383
383
|
try {
|
|
384
384
|
if (!existsSync3(TOKEN_FILE)) return null;
|
|
@@ -421,34 +421,32 @@ var loginCommand = new Command3("login").description("Sign in with Google or Git
|
|
|
421
421
|
res.end();
|
|
422
422
|
return;
|
|
423
423
|
}
|
|
424
|
-
const
|
|
425
|
-
if (!
|
|
424
|
+
const session = url.searchParams.get("session");
|
|
425
|
+
if (!session) {
|
|
426
426
|
res.writeHead(400, { "Content-Type": "text/html" });
|
|
427
427
|
res.end("<h1>Sign-in failed</h1><p>No session received.</p>");
|
|
428
428
|
clearTimeout(timeout);
|
|
429
429
|
server.close();
|
|
430
|
-
reject(new Error("No
|
|
430
|
+
reject(new Error("No session in callback"));
|
|
431
431
|
return;
|
|
432
432
|
}
|
|
433
433
|
try {
|
|
434
|
-
const
|
|
435
|
-
|
|
436
|
-
headers: { "Content-Type": "application/json" },
|
|
437
|
-
body: JSON.stringify({ fas_session: fasSession })
|
|
434
|
+
const meRes = await fetch(`${API_BASE}/v1/auth/me`, {
|
|
435
|
+
headers: { Authorization: `Bearer ${session}` }
|
|
438
436
|
});
|
|
439
|
-
|
|
440
|
-
|
|
437
|
+
if (!meRes.ok) throw new Error("Session validation failed");
|
|
438
|
+
const me = await meRes.json();
|
|
441
439
|
saveSession({
|
|
442
|
-
token:
|
|
443
|
-
user:
|
|
440
|
+
token: session,
|
|
441
|
+
user: { id: me.id, login: me.login, avatar: me.avatar },
|
|
444
442
|
expiresAt: Date.now() + 29 * 24 * 60 * 60 * 1e3
|
|
445
443
|
// ~29 days
|
|
446
444
|
});
|
|
447
445
|
res.writeHead(200, { "Content-Type": "text/html" });
|
|
448
|
-
res.end(`<h1>Signed in as ${
|
|
446
|
+
res.end(`<h1>Signed in as ${me.login}</h1><p>You can close this tab and return to the terminal.</p><script>window.close()</script>`);
|
|
449
447
|
clearTimeout(timeout);
|
|
450
448
|
server.close();
|
|
451
|
-
resolve5(
|
|
449
|
+
resolve5(session);
|
|
452
450
|
} catch (err) {
|
|
453
451
|
res.writeHead(500, { "Content-Type": "text/html" });
|
|
454
452
|
res.end(`<h1>Sign-in failed</h1><p>${err instanceof Error ? err.message : String(err)}</p>`);
|
|
@@ -459,8 +457,8 @@ var loginCommand = new Command3("login").description("Sign in with Google or Git
|
|
|
459
457
|
});
|
|
460
458
|
server.listen(port, "127.0.0.1");
|
|
461
459
|
});
|
|
462
|
-
const oauthBase = provider === "google" ? `${
|
|
463
|
-
const oauthUrl = `${oauthBase}?
|
|
460
|
+
const oauthBase = provider === "google" ? `${API_BASE}/v1/auth/google/start` : `${API_BASE}/v1/auth/github/start`;
|
|
461
|
+
const oauthUrl = `${oauthBase}?return_to=${encodeURIComponent(callbackUrl)}`;
|
|
464
462
|
const open = (await import("child_process")).exec;
|
|
465
463
|
const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
|
|
466
464
|
open(`${cmd} "${oauthUrl}"`);
|