abelworkflow 1.1.3 → 1.2.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.
Files changed (98) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +30 -29
  3. package/extensions/gpt-responses-compat.ts +213 -0
  4. package/extensions/k2think-compat.ts +40 -0
  5. package/lib/cli/args.mjs +5 -19
  6. package/lib/cli/main.mjs +105 -72
  7. package/lib/cli/prompts.mjs +9 -2
  8. package/lib/config/dotenv.mjs +1 -1
  9. package/lib/config/jsonc.mjs +1 -1
  10. package/lib/config/store.mjs +197 -45
  11. package/lib/config/toml.mjs +147 -453
  12. package/lib/installer/assets.mjs +67 -45
  13. package/lib/installer/install.mjs +202 -45
  14. package/lib/installer/links.mjs +124 -101
  15. package/lib/installer/lock.mjs +82 -0
  16. package/lib/installer/state.mjs +14 -21
  17. package/lib/paths.mjs +9 -9
  18. package/lib/providers/claude.mjs +58 -114
  19. package/lib/providers/codex.mjs +101 -198
  20. package/lib/providers/pi.mjs +331 -497
  21. package/lib/providers/skills.mjs +88 -68
  22. package/lib/providers/url.mjs +35 -0
  23. package/lib/templates/workflow/commands/abel-design.md +23 -161
  24. package/lib/templates/workflow/commands/abel-diagnose.md +30 -56
  25. package/lib/templates/workflow/commands/abel-implement.md +30 -150
  26. package/lib/templates/workflow/commands/abel-init.md +1 -1
  27. package/lib/tools/cli-installer.mjs +29 -190
  28. package/package.json +7 -9
  29. package/skills/context7-auto-research/context7-api.cjs +75 -17
  30. package/skills/dev-browser/SKILL.md +15 -1
  31. package/skills/dev-browser/dist/scripts/start.d.ts +0 -1
  32. package/skills/dev-browser/dist/scripts/start.js +8 -36
  33. package/skills/dev-browser/dist/src/client.d.ts +3 -4
  34. package/skills/dev-browser/dist/src/client.js +117 -117
  35. package/skills/dev-browser/dist/src/entrypoint.d.ts +1 -1
  36. package/skills/dev-browser/dist/src/entrypoint.js +38 -31
  37. package/skills/dev-browser/dist/src/index.d.ts +0 -1
  38. package/skills/dev-browser/dist/src/index.js +0 -1
  39. package/skills/dev-browser/dist/src/page-api.d.ts +0 -1
  40. package/skills/dev-browser/dist/src/page-api.js +0 -1
  41. package/skills/dev-browser/dist/src/relay.d.ts +0 -1
  42. package/skills/dev-browser/dist/src/relay.js +53 -7
  43. package/skills/dev-browser/dist/src/runtime.d.ts +3 -14
  44. package/skills/dev-browser/dist/src/runtime.js +5 -15
  45. package/skills/dev-browser/dist/src/snapshot/browser-script.d.ts +0 -1
  46. package/skills/dev-browser/dist/src/snapshot/browser-script.js +0 -1
  47. package/skills/dev-browser/dist/src/snapshot/index.d.ts +0 -1
  48. package/skills/dev-browser/dist/src/snapshot/index.js +0 -1
  49. package/skills/dev-browser/dist/src/snapshot/inject.d.ts +0 -1
  50. package/skills/dev-browser/dist/src/snapshot/inject.js +0 -1
  51. package/skills/dev-browser/dist/src/standalone.d.ts +0 -1
  52. package/skills/dev-browser/dist/src/standalone.js +2 -3
  53. package/skills/dev-browser/dist/src/startup.d.ts +3 -12
  54. package/skills/dev-browser/dist/src/startup.js +6 -10
  55. package/skills/dev-browser/dist/src/target-registry.d.ts +0 -1
  56. package/skills/dev-browser/dist/src/target-registry.js +0 -1
  57. package/skills/dev-browser/dist/src/types.d.ts +0 -1
  58. package/skills/dev-browser/dist/src/types.js +0 -1
  59. package/skills/dev-browser/package-lock.json +1 -1
  60. package/skills/dev-browser/package.json +2 -2
  61. package/skills/grok-search/.env.example +1 -1
  62. package/skills/grok-search/SKILL.md +13 -16
  63. package/skills/grok-search/scripts/_dotenv.py +1 -1
  64. package/skills/grok-search/scripts/groksearch_cli.py +271 -195
  65. package/skills/time/SKILL.md +5 -2
  66. package/skills/time/scripts/time_cli.py +61 -22
  67. package/extensions/pi-gpt-responses-compat/index.ts +0 -25
  68. package/lib/templates/codex/config-base.toml +0 -103
  69. package/skills/dev-browser/dist/scripts/start.d.ts.map +0 -1
  70. package/skills/dev-browser/dist/scripts/start.js.map +0 -1
  71. package/skills/dev-browser/dist/src/client.d.ts.map +0 -1
  72. package/skills/dev-browser/dist/src/client.js.map +0 -1
  73. package/skills/dev-browser/dist/src/entrypoint.d.ts.map +0 -1
  74. package/skills/dev-browser/dist/src/entrypoint.js.map +0 -1
  75. package/skills/dev-browser/dist/src/index.d.ts.map +0 -1
  76. package/skills/dev-browser/dist/src/index.js.map +0 -1
  77. package/skills/dev-browser/dist/src/page-api.d.ts.map +0 -1
  78. package/skills/dev-browser/dist/src/page-api.js.map +0 -1
  79. package/skills/dev-browser/dist/src/relay.d.ts.map +0 -1
  80. package/skills/dev-browser/dist/src/relay.js.map +0 -1
  81. package/skills/dev-browser/dist/src/runtime.d.ts.map +0 -1
  82. package/skills/dev-browser/dist/src/runtime.js.map +0 -1
  83. package/skills/dev-browser/dist/src/snapshot/browser-script.d.ts.map +0 -1
  84. package/skills/dev-browser/dist/src/snapshot/browser-script.js.map +0 -1
  85. package/skills/dev-browser/dist/src/snapshot/index.d.ts.map +0 -1
  86. package/skills/dev-browser/dist/src/snapshot/index.js.map +0 -1
  87. package/skills/dev-browser/dist/src/snapshot/inject.d.ts.map +0 -1
  88. package/skills/dev-browser/dist/src/snapshot/inject.js.map +0 -1
  89. package/skills/dev-browser/dist/src/standalone.d.ts.map +0 -1
  90. package/skills/dev-browser/dist/src/standalone.js.map +0 -1
  91. package/skills/dev-browser/dist/src/startup.d.ts.map +0 -1
  92. package/skills/dev-browser/dist/src/startup.js.map +0 -1
  93. package/skills/dev-browser/dist/src/target-registry.d.ts.map +0 -1
  94. package/skills/dev-browser/dist/src/target-registry.js.map +0 -1
  95. package/skills/dev-browser/dist/src/types.d.ts.map +0 -1
  96. package/skills/dev-browser/dist/src/types.js.map +0 -1
  97. package/skills/grok-search/gitignore.template +0 -4
  98. package/skills/grok-search/scripts/groksearch_entry.py +0 -131
@@ -1,3 +1,4 @@
1
+ import { isIP } from "node:net";
1
2
  export const DEFAULT_HOST = "localhost";
2
3
  const DEFAULT_PORT = 9222;
3
4
  const DEFAULT_CDP_PORT = 9223;
@@ -12,18 +13,24 @@ export function formatWsUrl(host, port, path = "") {
12
13
  return `ws://${formatHostForUrl(host)}:${port}${path}`;
13
14
  }
14
15
  export function resolveHostForProbe(host) {
15
- const normalizedHost = host.startsWith("[") && host.endsWith("]") ? host.slice(1, -1) : host;
16
- if (normalizedHost === "0.0.0.0") {
17
- return "127.0.0.1";
18
- }
19
- if (normalizedHost === "::") {
20
- return "::1";
21
- }
22
- return normalizedHost;
16
+ return normalizeLoopbackHost(host);
17
+ }
18
+ export function normalizeLoopbackHost(host) {
19
+ const normalized = host === "[::1]" ? "::1" : host.toLowerCase();
20
+ if (normalized === "localhost" || normalized === "::1")
21
+ return normalized;
22
+ if (isIP(normalized) === 4 && normalized.split(".")[0] === "127")
23
+ return normalized;
24
+ throw new Error(`Invalid host: ${host}. Only loopback hosts are allowed`);
23
25
  }
24
26
  export function parseEntrypointArgs(argv, env = process.env) {
25
27
  let index = 0;
26
28
  let mode = "standalone";
29
+ let host = env.HOST ?? DEFAULT_HOST;
30
+ let port = env.PORT ?? String(DEFAULT_PORT);
31
+ let portLabel = env.PORT === undefined ? "port" : "PORT";
32
+ let cdpPort = String(DEFAULT_CDP_PORT);
33
+ let headless = env.HEADLESS?.trim().toLowerCase() === "true";
27
34
  const first = argv[0];
28
35
  if (first && !first.startsWith("--")) {
29
36
  if (first !== "standalone" && first !== "extension") {
@@ -32,36 +39,42 @@ export function parseEntrypointArgs(argv, env = process.env) {
32
39
  mode = first;
33
40
  index = 1;
34
41
  }
35
- const args = {
36
- mode,
37
- host: env.HOST?.trim() || DEFAULT_HOST,
38
- port: readEnvPort(env.PORT, "PORT") ?? DEFAULT_PORT,
39
- cdpPort: DEFAULT_CDP_PORT,
40
- headless: env.HEADLESS?.trim().toLowerCase() === "true",
41
- };
42
42
  while (index < argv.length) {
43
43
  const token = argv[index++];
44
44
  switch (token) {
45
45
  case "--headless":
46
- args.headless = true;
46
+ if (mode === "extension") {
47
+ throw new Error("--headless is only valid in standalone mode");
48
+ }
49
+ headless = true;
47
50
  break;
48
51
  case "--host":
49
- args.host = readValue(argv, index - 1);
52
+ host = readValue(argv, index - 1);
50
53
  index += 1;
51
54
  break;
52
55
  case "--port":
53
- args.port = parsePort(readValue(argv, index - 1), "port");
56
+ port = readValue(argv, index - 1);
57
+ portLabel = "port";
54
58
  index += 1;
55
59
  break;
56
60
  case "--cdp-port":
57
- args.cdpPort = parsePort(readValue(argv, index - 1), "cdpPort");
61
+ if (mode === "extension") {
62
+ throw new Error("--cdp-port is only valid in standalone mode");
63
+ }
64
+ cdpPort = readValue(argv, index - 1);
58
65
  index += 1;
59
66
  break;
60
67
  default:
61
68
  throw new Error(`Unknown argument: ${token}`);
62
69
  }
63
70
  }
64
- return args;
71
+ return {
72
+ mode,
73
+ host: normalizeLoopbackHost(host),
74
+ port: parsePort(port, portLabel),
75
+ cdpPort: parsePort(cdpPort, "cdpPort"),
76
+ headless,
77
+ };
65
78
  }
66
79
  export function formatReadinessLines(info) {
67
80
  if (info.mode === "standalone") {
@@ -84,23 +97,17 @@ export function formatReadinessLines(info) {
84
97
  }
85
98
  function readValue(argv, optionIndex) {
86
99
  const value = argv[optionIndex + 1];
87
- if (!value || value.startsWith("--")) {
100
+ if (value === undefined || value.startsWith("--")) {
88
101
  throw new Error(`Missing value for ${argv[optionIndex]}`);
89
102
  }
90
103
  return value;
91
104
  }
92
105
  function parsePort(value, label) {
93
- const port = Number.parseInt(value, 10);
94
- if (!Number.isInteger(port) || port < 1 || port > 65535) {
106
+ if (!/^\d+$/.test(value))
107
+ throw new Error(`Invalid ${label}: ${value}`);
108
+ const port = Number(value);
109
+ if (port < 1 || port > 65535) {
95
110
  throw new Error(`Invalid ${label}: ${value}`);
96
111
  }
97
112
  return port;
98
113
  }
99
- function readEnvPort(value, label) {
100
- const normalized = value?.trim();
101
- if (!normalized) {
102
- return undefined;
103
- }
104
- return parsePort(normalized, label);
105
- }
106
- //# sourceMappingURL=entrypoint.js.map
@@ -1,4 +1,3 @@
1
1
  export { createStandaloneApp, createStandalonePageBackend, serve } from "./standalone.js";
2
2
  export type { DevBrowserServer } from "./standalone.js";
3
3
  export type { GetPageResponse, ListPagesResponse, ServeOptions, ServerInfoResponse, } from "./types.js";
4
- //# sourceMappingURL=index.d.ts.map
@@ -1,2 +1 @@
1
1
  export { createStandaloneApp, createStandalonePageBackend, serve } from "./standalone.js";
2
- //# sourceMappingURL=index.js.map
@@ -22,4 +22,3 @@ export declare function createPageApi({ backend, wsEndpoint, }: {
22
22
  wsEndpoint: string;
23
23
  }): Hono<import("hono/types").BlankEnv, import("hono/types").BlankSchema, "/">;
24
24
  export {};
25
- //# sourceMappingURL=page-api.d.ts.map
@@ -101,4 +101,3 @@ function backendError(c, error) {
101
101
  }
102
102
  return c.json({ error: error instanceof Error ? error.message : "internal server error" }, 500);
103
103
  }
104
- //# sourceMappingURL=page-api.js.map
@@ -24,4 +24,3 @@ export declare function createExtensionPageBackend({ registry, isConnected, send
24
24
  }): PageBackend;
25
25
  export declare function serveRelay(options?: RelayOptions): Promise<RelayServer>;
26
26
  export {};
27
- //# sourceMappingURL=relay.d.ts.map
@@ -1,7 +1,7 @@
1
1
  import { serve } from "@hono/node-server";
2
2
  import { createNodeWebSocket } from "@hono/node-ws";
3
3
  import { Hono } from "hono";
4
- import { formatHttpUrl, formatWsUrl } from "./entrypoint.js";
4
+ import { formatHttpUrl, formatWsUrl, normalizeLoopbackHost } from "./entrypoint.js";
5
5
  import { PageBackendError, createPageApi, } from "./page-api.js";
6
6
  import { createTargetRegistry, } from "./target-registry.js";
7
7
  export const WEBSOCKET_POLICY_VIOLATION_CODE = 1008;
@@ -39,6 +39,37 @@ function isCdpCommand(value) {
39
39
  && (value.params === undefined || isRecord(value.params))
40
40
  && (value.sessionId === undefined || typeof value.sessionId === "string");
41
41
  }
42
+ function isTargetInfo(value) {
43
+ return isRecord(value)
44
+ && typeof value.targetId === "string"
45
+ && typeof value.type === "string"
46
+ && typeof value.title === "string"
47
+ && typeof value.url === "string"
48
+ && typeof value.attached === "boolean";
49
+ }
50
+ function isExtensionEvent(value) {
51
+ if (!isRecord(value) || value.method !== "forwardCDPEvent" || !isRecord(value.params)) {
52
+ return false;
53
+ }
54
+ const event = value.params;
55
+ if (typeof event.method !== "string"
56
+ || (event.params !== undefined && !isRecord(event.params))
57
+ || (event.sessionId !== undefined && typeof event.sessionId !== "string")) {
58
+ return false;
59
+ }
60
+ if (event.method === "Target.attachedToTarget") {
61
+ return isRecord(event.params)
62
+ && typeof event.params.sessionId === "string"
63
+ && isTargetInfo(event.params.targetInfo);
64
+ }
65
+ if (event.method === "Target.detachedFromTarget") {
66
+ return isRecord(event.params) && typeof event.params.sessionId === "string";
67
+ }
68
+ if (event.method === "Target.targetInfoChanged") {
69
+ return isRecord(event.params) && isTargetInfo(event.params.targetInfo);
70
+ }
71
+ return true;
72
+ }
42
73
  export function createExtensionPageBackend({ registry, isConnected, sendCommand, timeoutMs, }) {
43
74
  const pending = new Map();
44
75
  async function create(name) {
@@ -72,7 +103,10 @@ export function createExtensionPageBackend({ registry, isConnected, sendCommand,
72
103
  async list() {
73
104
  return registry.list();
74
105
  },
75
- async getOrCreate(name) {
106
+ async getOrCreate(name, viewport) {
107
+ if (viewport) {
108
+ throw new PageBackendError(400, "viewport is not supported in extension mode");
109
+ }
76
110
  const existing = registry.getByName(name);
77
111
  if (existing)
78
112
  return { name, targetId: existing.targetId };
@@ -118,7 +152,10 @@ export function createExtensionPageBackend({ registry, isConnected, sendCommand,
118
152
  }
119
153
  export async function serveRelay(options = {}) {
120
154
  const requestedPort = options.port ?? 9222;
121
- const host = options.host ?? "127.0.0.1";
155
+ const host = normalizeLoopbackHost(options.host ?? "127.0.0.1");
156
+ if (!Number.isInteger(requestedPort) || requestedPort < 1 || requestedPort > 65535) {
157
+ throw new Error(`Invalid port: ${requestedPort}. Must be between 1 and 65535`);
158
+ }
122
159
  const targetTimeoutMs = options.targetTimeoutMs ?? 5000;
123
160
  const wsEndpoint = formatWsUrl(host, requestedPort, "/cdp");
124
161
  const registry = createTargetRegistry();
@@ -219,6 +256,12 @@ export async function serveRelay(options = {}) {
219
256
  extensionWs = null;
220
257
  closePlaywrightClients(error.message);
221
258
  }
259
+ function closeInvalidExtension(ws, code, reason) {
260
+ if (extensionWs === ws) {
261
+ disconnectExtension(new PageBackendError(502, reason));
262
+ }
263
+ ws.close(code, reason);
264
+ }
222
265
  async function sendToExtension(method, params, timeoutMs = 30_000) {
223
266
  const ws = extensionWs;
224
267
  if (!ws)
@@ -427,11 +470,11 @@ export async function serveRelay(options = {}) {
427
470
  parsed = JSON.parse(event.data.toString());
428
471
  }
429
472
  catch {
430
- ws.close(1000, "Invalid JSON");
473
+ closeInvalidExtension(ws, 1000, "Invalid JSON");
431
474
  return;
432
475
  }
433
476
  if (!isRecord(parsed)) {
434
- ws.close(1003, "Invalid extension message");
477
+ closeInvalidExtension(ws, 1003, "Invalid extension message");
435
478
  return;
436
479
  }
437
480
  const message = parsed;
@@ -450,7 +493,11 @@ export async function serveRelay(options = {}) {
450
493
  }
451
494
  if (message.method !== "forwardCDPEvent")
452
495
  return;
453
- const { method, params, sessionId } = message.params;
496
+ if (!isExtensionEvent(parsed)) {
497
+ closeInvalidExtension(ws, 1003, "Invalid extension message");
498
+ return;
499
+ }
500
+ const { method, params, sessionId } = parsed.params;
454
501
  if (method === "Target.attachedToTarget") {
455
502
  const attached = params;
456
503
  const target = {
@@ -518,4 +565,3 @@ function waitForListening(server) {
518
565
  function errorMessage(error) {
519
566
  return error instanceof Error ? error.message : String(error);
520
567
  }
521
- //# sourceMappingURL=relay.js.map
@@ -1,7 +1,3 @@
1
- export interface RuntimeCommand {
2
- command: string;
3
- args: string[];
4
- }
5
1
  export interface TcpPortProbe {
6
2
  once(event: "error" | "listening", listener: () => void): this;
7
3
  listen(port: number, host: string): unknown;
@@ -27,19 +23,12 @@ export interface InvalidRuntimeDependenciesOptions {
27
23
  lockedDependencies: Record<string, string>;
28
24
  readPackageVersion: (packageJsonPath: string) => string | undefined;
29
25
  }
30
- export declare function getRuntimeDependencyInstallCommand(): RuntimeCommand;
31
- export declare function getPlaywrightInstallCommand({ skillDir, nodeExecutable, }: {
32
- skillDir: string;
33
- nodeExecutable?: string;
34
- }): RuntimeCommand;
26
+ export declare function assertRuntimeDependenciesAvailable({ invalidDependencies, }: {
27
+ invalidDependencies: string[];
28
+ }): void;
35
29
  export declare function isTcpPortInUse(port: number, host?: string, createProbe?: TcpPortProbeFactory): Promise<boolean>;
36
30
  export declare function isPlaywrightChromiumInstalled({ headless, findExecutable, exists, }: ChromiumInstallCheckOptions): boolean;
37
31
  export declare function getLockedRuntimeDependencies(lockfile: RuntimePackageLock): Record<string, string>;
38
32
  export declare function getInvalidRuntimeDependencies({ skillDir, lockedDependencies, readPackageVersion, }: InvalidRuntimeDependenciesOptions): string[];
39
- export declare function resolveRuntimePaths(skillDir: string): {
40
- skillDir: string;
41
- };
42
33
  export declare function resolveImportMetaDir(moduleUrl: string): string;
43
34
  export declare function resolveSkillDirFromEntrypoint(moduleUrl: string): string;
44
- export declare function shouldUseShellForPackageCommands(platform: NodeJS.Platform): boolean;
45
- //# sourceMappingURL=runtime.d.ts.map
@@ -1,14 +1,11 @@
1
1
  import { createServer } from "node:net";
2
2
  import { basename, dirname, join } from "node:path";
3
3
  import { fileURLToPath } from "node:url";
4
- export function getRuntimeDependencyInstallCommand() {
5
- return { command: "npm", args: ["ci", "--omit=dev"] };
6
- }
7
- export function getPlaywrightInstallCommand({ skillDir, nodeExecutable = process.execPath, }) {
8
- return {
9
- command: nodeExecutable,
10
- args: [join(skillDir, "node_modules", "playwright", "cli.js"), "install", "chromium"],
11
- };
4
+ export function assertRuntimeDependenciesAvailable({ invalidDependencies, }) {
5
+ if (invalidDependencies.length === 0)
6
+ return;
7
+ throw new Error(`Runtime dependencies missing or out of date: ${invalidDependencies.join(", ")}. ` +
8
+ "From the dev-browser skill directory, run: npm ci --omit=dev");
12
9
  }
13
10
  export async function isTcpPortInUse(port, host = "127.0.0.1", createProbe = createServer) {
14
11
  return await new Promise((resolve) => {
@@ -38,9 +35,6 @@ export function getInvalidRuntimeDependencies({ skillDir, lockedDependencies, re
38
35
  ? []
39
36
  : [name]);
40
37
  }
41
- export function resolveRuntimePaths(skillDir) {
42
- return { skillDir };
43
- }
44
38
  export function resolveImportMetaDir(moduleUrl) {
45
39
  return dirname(fileURLToPath(moduleUrl));
46
40
  }
@@ -48,7 +42,3 @@ export function resolveSkillDirFromEntrypoint(moduleUrl) {
48
42
  const parentDir = dirname(resolveImportMetaDir(moduleUrl));
49
43
  return basename(parentDir) === "dist" ? dirname(parentDir) : parentDir;
50
44
  }
51
- export function shouldUseShellForPackageCommands(platform) {
52
- return platform === "win32";
53
- }
54
- //# sourceMappingURL=runtime.js.map
@@ -20,4 +20,3 @@ export declare function getSnapshotScript(): string;
20
20
  * Clear the cached script (useful for development/testing)
21
21
  */
22
22
  export declare function clearSnapshotScriptCache(): void;
23
- //# sourceMappingURL=browser-script.d.ts.map
@@ -866,4 +866,3 @@ function selectSnapshotRef(ref) {
866
866
  export function clearSnapshotScriptCache() {
867
867
  cachedScript = null;
868
868
  }
869
- //# sourceMappingURL=browser-script.js.map
@@ -11,4 +11,3 @@
11
11
  * // Now window.__devBrowser_getAISnapshot() and window.__devBrowser_selectSnapshotRef(ref) are available
12
12
  */
13
13
  export { getSnapshotScript, clearSnapshotScriptCache } from "./browser-script.js";
14
- //# sourceMappingURL=index.d.ts.map
@@ -11,4 +11,3 @@
11
11
  * // Now window.__devBrowser_getAISnapshot() and window.__devBrowser_selectSnapshotRef(ref) are available
12
12
  */
13
13
  export { getSnapshotScript, clearSnapshotScriptCache } from "./browser-script.js";
14
- //# sourceMappingURL=index.js.map
@@ -10,4 +10,3 @@
10
10
  * - window.__devBrowserRefs: Map of ref -> Element (persists across connections)
11
11
  */
12
12
  export { getSnapshotScript, clearSnapshotScriptCache } from "./browser-script.js";
13
- //# sourceMappingURL=inject.d.ts.map
@@ -10,4 +10,3 @@
10
10
  * - window.__devBrowserRefs: Map of ref -> Element (persists across connections)
11
11
  */
12
12
  export { getSnapshotScript, clearSnapshotScriptCache } from "./browser-script.js";
13
- //# sourceMappingURL=inject.js.map
@@ -29,4 +29,3 @@ export declare function createStandaloneApp({ backend, wsEndpoint, }: {
29
29
  }): Hono<import("hono/types").BlankEnv, import("hono/types").BlankSchema, "/">;
30
30
  export declare function serve(options?: ServeOptions): Promise<DevBrowserServer>;
31
31
  export type { ServeOptions } from "./types.js";
32
- //# sourceMappingURL=standalone.d.ts.map
@@ -2,7 +2,7 @@ import { once } from "node:events";
2
2
  import { serve as serveNode } from "@hono/node-server";
3
3
  import { Hono } from "hono";
4
4
  import { chromium } from "playwright";
5
- import { formatHttpUrl } from "./entrypoint.js";
5
+ import { formatHttpUrl, normalizeLoopbackHost } from "./entrypoint.js";
6
6
  import { createPageApi, } from "./page-api.js";
7
7
  export function createStandalonePageBackend(context) {
8
8
  const pages = new Map();
@@ -81,7 +81,7 @@ export function createStandaloneApp({ backend, wsEndpoint, }) {
81
81
  }
82
82
  export async function serve(options = {}) {
83
83
  const port = options.port ?? 9222;
84
- const host = options.host ?? "localhost";
84
+ const host = normalizeLoopbackHost(options.host ?? "localhost");
85
85
  const cdpPort = options.cdpPort ?? 9223;
86
86
  validatePorts(port, cdpPort);
87
87
  const context = await chromium.launchPersistentContext("", {
@@ -171,4 +171,3 @@ function closeServer(server) {
171
171
  server.close((error) => (error ? reject(error) : resolve()));
172
172
  });
173
173
  }
174
- //# sourceMappingURL=standalone.js.map
@@ -1,8 +1,4 @@
1
1
  import { type EntrypointArgs } from "./entrypoint.js";
2
- import type { RuntimeCommand } from "./runtime.js";
3
- export interface RuntimePaths {
4
- skillDir: string;
5
- }
6
2
  interface StandaloneServer {
7
3
  port: number;
8
4
  wsEndpoint: string;
@@ -14,7 +10,6 @@ interface ExtensionServer {
14
10
  stop: () => Promise<void>;
15
11
  }
16
12
  export interface RunEntrypointDeps {
17
- runtimePaths: RuntimePaths;
18
13
  serveStandalone: (options: {
19
14
  port: number;
20
15
  host: string;
@@ -31,11 +26,8 @@ export interface RunEntrypointDeps {
31
26
  ensureBrowser?: () => Promise<void>;
32
27
  preflightStandalone?: () => Promise<boolean>;
33
28
  }
34
- export interface EnsurePlaywrightChromiumDeps {
29
+ export interface PlaywrightChromiumPreflightDeps {
35
30
  isInstalled: () => boolean;
36
- installCommand: RuntimeCommand;
37
- runCommand: (command: string, args: string[]) => Promise<void>;
38
- log: (line: string) => void;
39
31
  }
40
32
  export interface PreflightStandaloneStartupDeps {
41
33
  checkServer: (host: string, port: number) => Promise<{
@@ -45,11 +37,10 @@ export interface PreflightStandaloneStartupDeps {
45
37
  wsEndpoint?: unknown;
46
38
  };
47
39
  }>;
48
- isPortInUse: (port: number) => Promise<boolean>;
40
+ isPortInUse: (port: number, host: string) => Promise<boolean>;
49
41
  log: (line: string) => void;
50
42
  }
51
43
  export declare function preflightStandaloneStartup(args: EntrypointArgs, deps: PreflightStandaloneStartupDeps): Promise<boolean>;
52
- export declare function ensurePlaywrightChromium(deps: EnsurePlaywrightChromiumDeps): Promise<void>;
44
+ export declare function assertPlaywrightChromiumAvailable(deps: PlaywrightChromiumPreflightDeps): void;
53
45
  export declare function runEntrypoint(args: EntrypointArgs, deps: RunEntrypointDeps): Promise<void>;
54
46
  export {};
55
- //# sourceMappingURL=startup.d.ts.map
@@ -8,22 +8,19 @@ export async function preflightStandaloneStartup(args, deps) {
8
8
  deps.log(`Server already running on port ${args.port}`);
9
9
  return false;
10
10
  }
11
- if (await deps.isPortInUse(args.port)) {
11
+ if (await deps.isPortInUse(args.port, args.host)) {
12
12
  throw new Error(`HTTP port ${args.port} is already in use. Stop the existing service or use --port.`);
13
13
  }
14
- if (await deps.isPortInUse(args.cdpPort)) {
14
+ if (await deps.isPortInUse(args.cdpPort, "127.0.0.1")) {
15
15
  throw new Error(`CDP port ${args.cdpPort} is already in use. Close the existing browser or use --cdp-port.`);
16
16
  }
17
17
  return true;
18
18
  }
19
- export async function ensurePlaywrightChromium(deps) {
20
- if (deps.isInstalled()) {
21
- deps.log("Playwright Chromium already installed.");
19
+ export function assertPlaywrightChromiumAvailable(deps) {
20
+ if (deps.isInstalled())
22
21
  return;
23
- }
24
- deps.log("Playwright Chromium not found. Installing (this may take a minute)...");
25
- await deps.runCommand(deps.installCommand.command, deps.installCommand.args);
26
- deps.log("Chromium installed successfully.");
22
+ throw new Error("Playwright Chromium is missing. From the dev-browser skill directory, run: " +
23
+ "node node_modules/playwright/cli.js install chromium");
27
24
  }
28
25
  export async function runEntrypoint(args, deps) {
29
26
  if (args.mode === "extension") {
@@ -78,4 +75,3 @@ export async function runEntrypoint(args, deps) {
78
75
  throw error;
79
76
  }
80
77
  }
81
- //# sourceMappingURL=startup.js.map
@@ -26,4 +26,3 @@ export declare function createTargetRegistry(): {
26
26
  waitForDetach: (targetId: string, timeoutMs: number) => Promise<void>;
27
27
  disconnect: (error: Error) => void;
28
28
  };
29
- //# sourceMappingURL=target-registry.d.ts.map
@@ -132,4 +132,3 @@ function rejectAll(waiters, error) {
132
132
  }
133
133
  waiters.clear();
134
134
  }
135
- //# sourceMappingURL=target-registry.js.map
@@ -24,4 +24,3 @@ export interface ServerInfoResponse {
24
24
  mode: "standalone" | "extension";
25
25
  extensionConnected?: boolean;
26
26
  }
27
- //# sourceMappingURL=types.d.ts.map
@@ -1,2 +1 @@
1
1
  export {};
2
- //# sourceMappingURL=types.js.map
@@ -11,7 +11,7 @@
11
11
  "@hono/node-server": "^1.19.13",
12
12
  "@hono/node-ws": "^1.3.1",
13
13
  "hono": "^4.12.30",
14
- "playwright": "^1.49.0"
14
+ "playwright": "^1.56.0"
15
15
  },
16
16
  "devDependencies": {
17
17
  "@types/node": "^22.0.0",
@@ -13,7 +13,7 @@
13
13
  }
14
14
  },
15
15
  "scripts": {
16
- "build": "tsc -p tsconfig.json",
16
+ "build": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\" && tsc -p tsconfig.json",
17
17
  "typecheck": "tsc -p tsconfig.json --noEmit",
18
18
  "start": "node dist/scripts/start.js standalone",
19
19
  "start-server": "node dist/scripts/start.js standalone",
@@ -25,7 +25,7 @@
25
25
  "@hono/node-server": "^1.19.13",
26
26
  "@hono/node-ws": "^1.3.1",
27
27
  "hono": "^4.12.30",
28
- "playwright": "^1.49.0"
28
+ "playwright": "^1.56.0"
29
29
  },
30
30
  "devDependencies": {
31
31
  "@types/node": "^22.0.0",
@@ -1,5 +1,5 @@
1
1
  # GrokSearch 命令行工具配置
2
- # 将此文件复制为 .env 并填入你的配置值
2
+ # 使用外部环境变量或已部署 Skill 的受限配置;不要在源码目录创建 .env
3
3
 
4
4
  # 必填项:Grok API 端点(OpenAI 兼容格式)
5
5
  GROK_API_URL=
@@ -11,28 +11,26 @@ Use this skill for web search, webpage retrieval, and current-information lookup
11
11
 
12
12
  ## Rules
13
13
 
14
- - Always call `python "<SKILL_DIR>/scripts/groksearch_entry.py" ...`.
15
- - Do not call `scripts/groksearch_cli.py` directly.
16
- - The entrypoint auto-loads `<SKILL_DIR>/.env`.
14
+ - Install dependencies in an environment you choose before first use: `python -m pip install -r "<SKILL_DIR>/requirements.txt"`.
15
+ - Always call `python "<SKILL_DIR>/scripts/groksearch_cli.py" ...` from that environment.
16
+ - Provide credentials through external environment variables. AbelWorkflow installations may use the restricted installed config at `<SKILL_DIR>/.env`; do not create a source-tree `.env`.
17
17
  - Required env: `GROK_API_URL`, `GROK_API_KEY`.
18
- - Optional env: `GROK_MODEL`, `GROK_DEBUG`, `GROK_RETRY_*`, `TAVILY_API_KEY`, `TAVILY_API_URL`, `TAVILY_ENABLED`, `GROKSEARCH_VENV_DIR`, `GROKSEARCH_PYTHON`, `AGENTS_SKILLS_PYTHON`.
18
+ - Optional env: `GROK_MODEL`, `GROK_DEBUG`, `GROK_RETRY_*`, `TAVILY_API_KEY`, `TAVILY_API_URL`, `TAVILY_ENABLED`.
19
19
  - For time-sensitive answers, include source URLs and the relevant date.
20
20
  - Start with `web_search`; use `web_fetch` for page content; use `web_map` for site structure.
21
21
 
22
22
  ## Commands
23
23
 
24
24
  ```bash
25
- cp "<SKILL_DIR>/.env.example" "<SKILL_DIR>/.env"
25
+ python -m pip install -r "<SKILL_DIR>/requirements.txt"
26
26
 
27
- python "<SKILL_DIR>/scripts/groksearch_entry.py" web_search --query "search terms" [--platform "GitHub"] [--min-results 3] [--max-results 10] [--model "grok-4.20-non-reasoning"] [--extra-sources 3]
27
+ python "<SKILL_DIR>/scripts/groksearch_cli.py" web_search --query "search terms" [--platform "GitHub"] [--min-results 3] [--max-results 10] [--model "grok-4.20-non-reasoning"] [--extra-sources 3]
28
28
 
29
- python "<SKILL_DIR>/scripts/groksearch_entry.py" web_fetch --url "https://..." [--out file.md] [--fallback-grok]
29
+ python "<SKILL_DIR>/scripts/groksearch_cli.py" web_fetch --url "https://..." [--out file.md] [--fallback-grok]
30
30
 
31
- python "<SKILL_DIR>/scripts/groksearch_entry.py" web_map --url "https://..." [--instructions "focus area"] [--max-depth 2] [--limit 80]
31
+ python "<SKILL_DIR>/scripts/groksearch_cli.py" web_map --url "https://..." [--instructions "focus area"] [--max-depth 2] [--limit 80]
32
32
 
33
- python "<SKILL_DIR>/scripts/groksearch_entry.py" get_config_info [--no-test]
34
-
35
- python "<SKILL_DIR>/scripts/groksearch_entry.py" toggle_builtin_tools --action on|off|status [--root /path/to/project]
33
+ python "<SKILL_DIR>/scripts/groksearch_cli.py" get_config_info [--no-test]
36
34
  ```
37
35
 
38
36
  ## Tool Routing Policy
@@ -40,8 +38,8 @@ python "<SKILL_DIR>/scripts/groksearch_entry.py" toggle_builtin_tools --action o
40
38
 
41
39
  | Scenario | Disabled | Use Instead |
42
40
  |----------|----------|-------------|
43
- | Web Search | `WebSearch` | CLI `web_search` via `groksearch_entry.py` |
44
- | Web Fetch | `WebFetch` | CLI `web_fetch` via `groksearch_entry.py` |
41
+ | Web Search | `WebSearch` | CLI `web_search` via `groksearch_cli.py` |
42
+ | Web Fetch | `WebFetch` | CLI `web_fetch` via `groksearch_cli.py` |
45
43
 
46
44
  ### Tool Capability Matrix
47
45
 
@@ -51,7 +49,6 @@ python "<SKILL_DIR>/scripts/groksearch_entry.py" toggle_builtin_tools --action o
51
49
  | `web_fetch` | `url`(required), `out`/`fallback_grok`(optional) | Structured Markdown |
52
50
  | `web_map` | `url`(required), `instructions`/`max_depth`/`max_breadth`/`limit`/`timeout`(optional) | JSON string |
53
51
  | `get_config_info` | `no_test`(optional) | `{api_url,status,connection_test}` |
54
- | `toggle_builtin_tools` | `action`(on/off/status), `root`(optional) | `{blocked,deny_list}` |
55
52
 
56
53
  ## Search Workflow
57
54
 
@@ -84,6 +81,6 @@ python "<SKILL_DIR>/scripts/groksearch_entry.py" toggle_builtin_tools --action o
84
81
  | Prohibited | Correct |
85
82
  |------------|---------|
86
83
  | No source citation | Include `Source [1](URL)` |
87
- | Assume current repo has `skills/grok-search` | Check global skill directories under `$HOME` first, then project-level `.claude/.codex/.agents`, then call `<SKILL_DIR>/scripts/groksearch_entry.py` |
88
- | Call `scripts/groksearch_cli.py` directly | Call `python scripts/groksearch_entry.py ...` |
84
+ | Assume current repo has `skills/grok-search` | Check global skill directories under `$HOME` first, then project-level `.claude/.codex/.agents`, then call `<SKILL_DIR>/scripts/groksearch_cli.py` |
85
+ | Expect automatic environment setup | Choose an environment and install `requirements.txt` explicitly |
89
86
  | Use built-in WebSearch/WebFetch | Use GrokSearch CLI |
@@ -25,7 +25,7 @@ def load_dotenv() -> bool:
25
25
  if not key or key in seen_keys:
26
26
  continue
27
27
  seen_keys.add(key)
28
- if not os.environ.get(key):
28
+ if key not in os.environ:
29
29
  os.environ[key] = value
30
30
  return True
31
31
  except IOError: