pi-chrome 0.13.0 → 0.14.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.
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"manifest_version": 3,
|
|
3
3
|
"name": "Pi Chrome Connector",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.14.0",
|
|
5
5
|
"description": "Lets Pi control tabs in Chrome via a local connector at 127.0.0.1.",
|
|
6
6
|
"permissions": ["tabs", "scripting", "storage", "activeTab", "alarms", "webNavigation", "debugger"],
|
|
7
7
|
"host_permissions": ["<all_urls>", "http://127.0.0.1:17318/*"],
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
import { getSettingsListTheme } from "@earendil-works/pi-coding-agent";
|
|
2
3
|
import { StringEnum } from "@earendil-works/pi-ai";
|
|
4
|
+
import { Container, type SettingItem, SettingsList, Text } from "@earendil-works/pi-tui";
|
|
3
5
|
import { Type } from "typebox";
|
|
4
6
|
import { existsSync, readFileSync, statSync } from "node:fs";
|
|
5
7
|
import { mkdir, writeFile } from "node:fs/promises";
|
|
@@ -679,6 +681,81 @@ Usage rules:
|
|
|
679
681
|
ctx.ui.notify(await statusSummary(), "info");
|
|
680
682
|
};
|
|
681
683
|
|
|
684
|
+
// Interactive dialog: each row is a setting whose value cycles with Space/Enter. Enter on
|
|
685
|
+
// the last value also saves; Esc / 'q' closes. The description below changes with the
|
|
686
|
+
// current value so users always see what the active setting means.
|
|
687
|
+
const openSettingsDialog = async (ctx: ExtensionContext): Promise<void> => {
|
|
688
|
+
// Read current click mode (might fail if extension permission missing).
|
|
689
|
+
let clicksMode: string = "auto";
|
|
690
|
+
let permissionGranted = false;
|
|
691
|
+
try {
|
|
692
|
+
const t = (await bridge.send("trusted.status", {}, 5_000)) as { mode?: string; permissionGranted?: boolean };
|
|
693
|
+
clicksMode = t.mode ?? "auto";
|
|
694
|
+
permissionGranted = !!t.permissionGranted;
|
|
695
|
+
} catch {}
|
|
696
|
+
|
|
697
|
+
const clicksItem: SettingItem = {
|
|
698
|
+
id: "clicks",
|
|
699
|
+
label: "Click realism",
|
|
700
|
+
currentValue: clicksMode,
|
|
701
|
+
values: ["auto", "on", "off"],
|
|
702
|
+
description: permissionGranted
|
|
703
|
+
? (CLICKS_DESC[clicksMode] ?? "")
|
|
704
|
+
: "Real-looking clicks unavailable: reload the Chrome extension in chrome://extensions and accept the new permission prompt.",
|
|
705
|
+
};
|
|
706
|
+
const quietItem: SettingItem = {
|
|
707
|
+
id: "quiet",
|
|
708
|
+
label: "Quiet mode",
|
|
709
|
+
currentValue: backgroundDefault ? "on" : "off",
|
|
710
|
+
values: ["on", "off"],
|
|
711
|
+
description: QUIET_DESC[backgroundDefault ? "on" : "off"] ?? "",
|
|
712
|
+
};
|
|
713
|
+
const items: SettingItem[] = [clicksItem, quietItem];
|
|
714
|
+
|
|
715
|
+
await ctx.ui.custom<void>((_tui, theme, _kb, done) => {
|
|
716
|
+
const container = new Container();
|
|
717
|
+
container.addChild(new Text(theme.fg("accent", theme.bold("pi-chrome settings")), 1, 1));
|
|
718
|
+
container.addChild(new Text(theme.fg("muted", "\u2191\u2193 navigate · space/enter cycle · esc close"), 1, 0));
|
|
719
|
+
|
|
720
|
+
let list: SettingsList;
|
|
721
|
+
list = new SettingsList(
|
|
722
|
+
items,
|
|
723
|
+
Math.min(items.length + 2, 8),
|
|
724
|
+
getSettingsListTheme(),
|
|
725
|
+
(id, newValue) => {
|
|
726
|
+
if (id === "clicks") {
|
|
727
|
+
if (!permissionGranted) {
|
|
728
|
+
ctx.ui.notify("Click mode locked: reload the Chrome extension first.", "warning");
|
|
729
|
+
// Revert by snapping back to the previous value.
|
|
730
|
+
list.updateValue("clicks", clicksItem.currentValue);
|
|
731
|
+
return;
|
|
732
|
+
}
|
|
733
|
+
// Mutate description so the help text matches the new value.
|
|
734
|
+
clicksItem.currentValue = newValue;
|
|
735
|
+
clicksItem.description = CLICKS_DESC[newValue] ?? "";
|
|
736
|
+
list.invalidate();
|
|
737
|
+
void bridge.send("trusted.mode", { mode: newValue }, 5_000).catch((err) => {
|
|
738
|
+
ctx.ui.notify(`Couldn't switch click mode: ${(err as Error).message}`, "warning");
|
|
739
|
+
});
|
|
740
|
+
} else if (id === "quiet") {
|
|
741
|
+
backgroundDefault = newValue === "on";
|
|
742
|
+
quietItem.currentValue = newValue;
|
|
743
|
+
quietItem.description = QUIET_DESC[newValue] ?? "";
|
|
744
|
+
list.invalidate();
|
|
745
|
+
}
|
|
746
|
+
},
|
|
747
|
+
() => done(undefined),
|
|
748
|
+
);
|
|
749
|
+
container.addChild(list);
|
|
750
|
+
|
|
751
|
+
return {
|
|
752
|
+
render: (w) => container.render(w),
|
|
753
|
+
invalidate: () => container.invalidate(),
|
|
754
|
+
handleInput: (data: string) => list.handleInput(data),
|
|
755
|
+
};
|
|
756
|
+
});
|
|
757
|
+
};
|
|
758
|
+
|
|
682
759
|
pi.registerCommand("chrome", {
|
|
683
760
|
description:
|
|
684
761
|
"All pi-chrome controls in one place.\n /chrome status — one-line snapshot of connection + current modes.\n /chrome doctor — full health check.\n /chrome onboard — install the Chrome companion extension.\n /chrome clicks [auto|off|on|status] — how realistic should pi-chrome's clicks be.\n /chrome quiet [on|off|status|toggle] — whether Chrome pops to the front when pi-chrome acts.\nRun with no arguments for an interactive picker that shows current state.",
|
|
@@ -727,32 +804,7 @@ Usage rules:
|
|
|
727
804
|
handler: async (args, ctx) => {
|
|
728
805
|
const tokens = (args || "").trim().split(/\s+/).filter(Boolean);
|
|
729
806
|
if (tokens.length === 0) {
|
|
730
|
-
|
|
731
|
-
// Compute next-cycle targets so the picker labels describe the toggle action.
|
|
732
|
-
let clicksNow = "?";
|
|
733
|
-
try {
|
|
734
|
-
const t = (await bridge.send("trusted.status", {}, 3_000)) as { mode?: string };
|
|
735
|
-
clicksNow = t.mode ?? "?";
|
|
736
|
-
} catch {}
|
|
737
|
-
const clicksNext = (() => {
|
|
738
|
-
const idx = CLICKS_CYCLE.indexOf(clicksNow as typeof CLICKS_CYCLE[number]);
|
|
739
|
-
return idx >= 0 ? CLICKS_CYCLE[(idx + 1) % CLICKS_CYCLE.length] : "auto";
|
|
740
|
-
})();
|
|
741
|
-
const quietNow = backgroundDefault ? "on" : "off";
|
|
742
|
-
const quietNext = backgroundDefault ? "off" : "on";
|
|
743
|
-
const picked = await ctx.ui.select(`pi-chrome — ${header}`, [
|
|
744
|
-
`status — print the line above (so you can copy it).`,
|
|
745
|
-
`doctor — full health check; explains anything broken.`,
|
|
746
|
-
`onboard — install the Chrome companion extension (first-time setup).`,
|
|
747
|
-
`clicks: ${clicksNow} → switch to ${clicksNext} — ${CLICKS_DESC[clicksNext] ?? ""}`,
|
|
748
|
-
`quiet: ${quietNow} → switch to ${quietNext} — ${QUIET_DESC[quietNext] ?? ""}`,
|
|
749
|
-
]);
|
|
750
|
-
if (!picked) return;
|
|
751
|
-
if (picked.startsWith("status")) return statusHandler(ctx);
|
|
752
|
-
if (picked.startsWith("doctor")) return doctorHandler(ctx);
|
|
753
|
-
if (picked.startsWith("onboard")) return onboardHandler(ctx);
|
|
754
|
-
if (picked.startsWith("clicks")) return trustedHandler(ctx, ""); // cycles
|
|
755
|
-
if (picked.startsWith("quiet")) return backgroundHandler(ctx, ""); // toggles
|
|
807
|
+
await openSettingsDialog(ctx);
|
|
756
808
|
return;
|
|
757
809
|
}
|
|
758
810
|
const [head, ...rest] = tokens;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-chrome",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.14.0",
|
|
4
4
|
"description": "Drive your existing logged-in Chrome from Pi — no re-login, no throwaway profile, watch the agent work in real time (or toggle quiet background mode).",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pi-package",
|