demobites 1.25.0 → 1.26.0
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/launcher/index.mjs +3 -3
- package/package.json +1 -1
- package/skill/scripts/signin.mjs +49 -6
package/launcher/index.mjs
CHANGED
|
@@ -510,10 +510,10 @@ if (arg === "listen") {
|
|
|
510
510
|
writeJson(LOCK, { pid: process.pid, since: new Date().toISOString(), cwd: process.cwd(), service: SERVICE, repo });
|
|
511
511
|
const noteState = (extra) => writeJson(STATE, { at: new Date().toISOString(), machine_id: listen.machine_id, name, base, workspace: cfg.workspace?.name ?? null, ...extra });
|
|
512
512
|
const readiness = () => {
|
|
513
|
-
let signins = [];
|
|
514
|
-
try {
|
|
513
|
+
let signins = [], whos = {};
|
|
514
|
+
try { const l = JSON.parse(fs.readFileSync(path.join(process.cwd(), ".recorder", "signins.json"), "utf8")); signins = Object.keys(l.origins || {}); whos = l.who && typeof l.who === "object" ? l.who : {}; } catch { /* none */ }
|
|
515
515
|
const repos = Object.entries(readJson(reposFile(process.cwd())) ?? {}).filter(([, v]) => v && typeof v.folder === "string" && fs.existsSync(v.folder)).map(([site, v]) => ({ site, folder: v.folder, repo: v.repo ?? null }));
|
|
516
|
-
return { ...agentInfo, chrome: haveChrome, recorder: pkg.version, signins, cwd: process.cwd(), platform: process.platform, repo, repos };
|
|
516
|
+
return { ...agentInfo, chrome: haveChrome, recorder: pkg.version, signins, whos, cwd: process.cwd(), platform: process.platform, repo, repos };
|
|
517
517
|
};
|
|
518
518
|
// The code bound to a job's site (1.22.0): the planner reads there.
|
|
519
519
|
const codeFor = (url) => { try { const site = siteOf(new URL(url).hostname); const b = (readJson(reposFile(process.cwd())) ?? {})[site]; return b && fs.existsSync(b.folder) ? { site, ...b } : null; } catch { return null; } };
|
package/package.json
CHANGED
package/skill/scripts/signin.mjs
CHANGED
|
@@ -101,13 +101,54 @@ const wallCheck = async () => {
|
|
|
101
101
|
});
|
|
102
102
|
} catch { return { wall: true }; }
|
|
103
103
|
};
|
|
104
|
+
// WHO SIGNED IN (1.26.0, founder 2026-10-17: "three different users sign in, three tabs… get some data about
|
|
105
|
+
// the signed-in email or username"): never a credential, only what the app itself shows once you are in —
|
|
106
|
+
// an email in the page, an account menu's label, the address a Google chooser was told. Best effort; null
|
|
107
|
+
// is fine. It goes to the ledger beside the origin and to the app as `who`.
|
|
108
|
+
let chooserEmail = null;
|
|
109
|
+
const whoAmI = async () => {
|
|
110
|
+
try {
|
|
111
|
+
await page.waitForTimeout(2500);
|
|
112
|
+
const found = await page.evaluate(() => {
|
|
113
|
+
const EMAIL = /[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}/i;
|
|
114
|
+
const pick = (s) => { const m = String(s || "").match(EMAIL); return m ? m[0] : null; };
|
|
115
|
+
const attrs = [];
|
|
116
|
+
for (const el of document.querySelectorAll("[aria-label], [title], img[alt], [data-email], [data-user-email]")) {
|
|
117
|
+
for (const a of ["aria-label", "title", "alt", "data-email", "data-user-email"]) { const v = el.getAttribute(a); if (v) attrs.push(v); }
|
|
118
|
+
}
|
|
119
|
+
for (const v of attrs) { const e = pick(v); if (e) return { email: e }; }
|
|
120
|
+
const text = document.body?.innerText || "";
|
|
121
|
+
const e = pick(text);
|
|
122
|
+
if (e) return { email: e };
|
|
123
|
+
for (const v of attrs) if (/account|profile|avatar|signed in as|logged in as|user menu/i.test(v)) { const name = v.replace(/^(open|toggle)\s+/i, "").replace(/\s*(menu|avatar|profile|account)\s*$/i, "").trim(); if (name && name.length <= 60 && !/^(account|profile|avatar|user)$/i.test(name)) return { name }; }
|
|
124
|
+
return null;
|
|
125
|
+
});
|
|
126
|
+
if (found?.email) return found.email.toLowerCase();
|
|
127
|
+
if (chooserEmail) return chooserEmail;
|
|
128
|
+
if (found?.name) return found.name;
|
|
129
|
+
} catch { /* nothing */ }
|
|
130
|
+
return chooserEmail;
|
|
131
|
+
};
|
|
132
|
+
const noteChooser = async (here) => {
|
|
133
|
+
if (!/accounts\.google\.com|login\.microsoftonline\.com|okta\.com|auth0\.com/i.test(here.host)) return;
|
|
134
|
+
try {
|
|
135
|
+
const v = await page.evaluate(() => {
|
|
136
|
+
const el = document.querySelector("[data-identifier], [data-email], input[type=email], #identifierId, input[name=loginfmt]");
|
|
137
|
+
const s = el?.getAttribute?.("data-identifier") || el?.getAttribute?.("data-email") || el?.value || "";
|
|
138
|
+
const m = String(s).match(/[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}/i); return m ? m[0] : null;
|
|
139
|
+
});
|
|
140
|
+
if (v) chooserEmail = v.toLowerCase();
|
|
141
|
+
} catch { /* nothing */ }
|
|
142
|
+
};
|
|
143
|
+
const remember = (origin, who) => { try { const l = readLedger(); l.origins = { ...(l.origins ?? {}), [origin]: new Date().toISOString() }; if (who) l.who = { ...(l.who ?? {}), [origin]: who }; fs.mkdirSync(path.dirname(ledgerPath), { recursive: true }); fs.writeFileSync(ledgerPath, JSON.stringify(l, null, 2) + "\n"); } catch { /* the session still lives in the profile */ } };
|
|
104
144
|
await page.waitForTimeout(4000);
|
|
105
145
|
const first = await wallCheck();
|
|
106
146
|
if (!first.wall) {
|
|
107
147
|
const origin = new URL(page.url()).origin;
|
|
108
148
|
console.log(`✓ No sign-in needed for ${origin}.`);
|
|
109
|
-
|
|
110
|
-
|
|
149
|
+
const who = await whoAmI();
|
|
150
|
+
remember(origin, who);
|
|
151
|
+
await postEvent("signed_in", { origin, none: true, ...(who ? { who } : {}) });
|
|
111
152
|
await ctx.close();
|
|
112
153
|
process.exit(0);
|
|
113
154
|
}
|
|
@@ -119,10 +160,12 @@ while (Date.now() - started < timeoutMs) {
|
|
|
119
160
|
await page.waitForTimeout(1000);
|
|
120
161
|
let here;
|
|
121
162
|
try { here = new URL(page.url()); } catch { continue; }
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
163
|
+
await noteChooser(here);
|
|
164
|
+
if (here.pathname !== startPath && !/sign-?in|log-?in|auth|sso|oauth|callback/i.test(here.pathname) && !/accounts\.google\.com|login\.microsoftonline\.com|okta\.com|auth0\.com/i.test(here.host)) {
|
|
165
|
+
const who = await whoAmI();
|
|
166
|
+
console.log(`✓ Signed in${who ? ` as ${who}` : ""}. The session is saved for ${here.origin}; next time there is no question and no window.`);
|
|
167
|
+
await postEvent("signed_in", { origin: here.origin, ...(who ? { who } : {}) });
|
|
168
|
+
remember(here.origin, who);
|
|
126
169
|
await ctx.close();
|
|
127
170
|
process.exit(0);
|
|
128
171
|
}
|