ask-pro 0.1.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 (55) hide show
  1. package/.codex-plugin/plugin.json +30 -0
  2. package/LICENSE +21 -0
  3. package/README.md +231 -0
  4. package/assets/ask-pro_logo.png +0 -0
  5. package/dist/bin/ask-pro-cli.js +507 -0
  6. package/dist/scripts/run-cli.js +27 -0
  7. package/dist/src/ask-pro/atomicWrite.js +26 -0
  8. package/dist/src/ask-pro/browserRunner.js +796 -0
  9. package/dist/src/ask-pro/responseZip.js +349 -0
  10. package/dist/src/ask-pro/session.js +662 -0
  11. package/dist/src/ask-pro/sessionControllerLease.js +64 -0
  12. package/dist/src/ask-pro/toon.js +26 -0
  13. package/dist/src/ask-pro/zip.js +85 -0
  14. package/dist/src/browser/actions/assistantResponse.js +1245 -0
  15. package/dist/src/browser/actions/attachmentDataTransfer.js +140 -0
  16. package/dist/src/browser/actions/attachments.js +1720 -0
  17. package/dist/src/browser/actions/composerSendReadiness.js +369 -0
  18. package/dist/src/browser/actions/domEvents.js +31 -0
  19. package/dist/src/browser/actions/inputGuard.js +52 -0
  20. package/dist/src/browser/actions/modelPickerDom.js +68 -0
  21. package/dist/src/browser/actions/modelSelection.js +576 -0
  22. package/dist/src/browser/actions/navigation.js +510 -0
  23. package/dist/src/browser/actions/promptComposer.js +824 -0
  24. package/dist/src/browser/actions/remoteFileTransfer.js +37 -0
  25. package/dist/src/browser/actions/thinkingStatus.js +408 -0
  26. package/dist/src/browser/actions/thinkingTime.js +635 -0
  27. package/dist/src/browser/actions/windowState.js +47 -0
  28. package/dist/src/browser/attachRunning.js +31 -0
  29. package/dist/src/browser/chatgptModelCatalog.js +321 -0
  30. package/dist/src/browser/chromeLifecycle.js +807 -0
  31. package/dist/src/browser/config.js +110 -0
  32. package/dist/src/browser/constants.js +85 -0
  33. package/dist/src/browser/cookies.js +191 -0
  34. package/dist/src/browser/detect.js +337 -0
  35. package/dist/src/browser/domDebug.js +72 -0
  36. package/dist/src/browser/errors.js +20 -0
  37. package/dist/src/browser/format.js +16 -0
  38. package/dist/src/browser/index.js +2631 -0
  39. package/dist/src/browser/language.js +97 -0
  40. package/dist/src/browser/liveTabs.js +434 -0
  41. package/dist/src/browser/modelStrategy.js +13 -0
  42. package/dist/src/browser/pageActions.js +5 -0
  43. package/dist/src/browser/profilePaths.js +282 -0
  44. package/dist/src/browser/profileState.js +413 -0
  45. package/dist/src/browser/providerDomFlow.js +17 -0
  46. package/dist/src/browser/providers/chatgptDomProvider.js +50 -0
  47. package/dist/src/browser/reattach.js +534 -0
  48. package/dist/src/browser/reattachHelpers.js +387 -0
  49. package/dist/src/browser/utils.js +122 -0
  50. package/dist/src/browserMode.js +1 -0
  51. package/dist/src/version.js +39 -0
  52. package/package.json +114 -0
  53. package/scripts/refresh-local-plugin.mjs +179 -0
  54. package/scripts/refresh-local-plugin.ps1 +93 -0
  55. package/skills/ask-pro/SKILL.md +181 -0
@@ -0,0 +1,64 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { mkdir, readdir, rename, rm, stat, writeFile } from "node:fs/promises";
3
+ import path from "node:path";
4
+ import { isProcessAlive } from "../browser/profileState.js";
5
+ const LEASE_FILENAME = ".controller.lease";
6
+ const OWNER_PATTERN = /^(\d+)-(.+)\.owner$/;
7
+ const REMOVE_OPTIONS = { recursive: true, force: true, maxRetries: 5, retryDelay: 20 };
8
+ export async function withSessionControllerLease(sessionDir, action) {
9
+ const id = randomUUID();
10
+ const leasePath = path.join(sessionDir, LEASE_FILENAME);
11
+ const candidatePath = `${leasePath}.${id}.candidate`;
12
+ const ownerName = `${process.pid}-${id}.owner`;
13
+ await mkdir(candidatePath);
14
+ let acquired = false;
15
+ try {
16
+ await writeFile(path.join(candidatePath, ownerName), "");
17
+ for (;;) {
18
+ try {
19
+ await rename(candidatePath, leasePath);
20
+ acquired = true;
21
+ break;
22
+ }
23
+ catch (error) {
24
+ if (!(await stat(leasePath).catch(() => null)))
25
+ throw error;
26
+ }
27
+ const existingOwner = (await readdir(leasePath)).find((entry) => OWNER_PATTERN.test(entry));
28
+ const existingPid = Number(existingOwner?.match(OWNER_PATTERN)?.[1]);
29
+ if (!existingOwner || !Number.isInteger(existingPid) || existingPid <= 0) {
30
+ throw new Error("ask-pro session controller lease is unreadable");
31
+ }
32
+ if (isProcessAlive(existingPid)) {
33
+ throw new Error(`ask-pro session controller is already running (pid ${existingPid})`);
34
+ }
35
+ try {
36
+ await rename(path.join(leasePath, existingOwner), path.join(leasePath, ownerName));
37
+ }
38
+ catch (error) {
39
+ if (error.code === "ENOENT")
40
+ continue;
41
+ throw error;
42
+ }
43
+ const stalePath = `${leasePath}.${id}.stale`;
44
+ await rename(leasePath, stalePath);
45
+ await rm(stalePath, REMOVE_OPTIONS);
46
+ }
47
+ try {
48
+ return await action();
49
+ }
50
+ finally {
51
+ const ownsLease = (await readdir(leasePath).catch(() => [])).includes(ownerName);
52
+ if (ownsLease) {
53
+ const retiredPath = `${leasePath}.${id}.retired`;
54
+ const retired = await rename(leasePath, retiredPath).then(() => true, () => false);
55
+ if (retired)
56
+ await rm(retiredPath, REMOVE_OPTIONS).catch(() => undefined);
57
+ }
58
+ }
59
+ }
60
+ finally {
61
+ if (!acquired)
62
+ await rm(candidatePath, REMOVE_OPTIONS).catch(() => undefined);
63
+ }
64
+ }
@@ -0,0 +1,26 @@
1
+ export function renderToonRecord(name, fields) {
2
+ const lines = [name];
3
+ for (const [key, value] of Object.entries(fields)) {
4
+ if (value === undefined)
5
+ continue;
6
+ lines.push(` ${formatKey(key)}: ${formatValue(value)}`);
7
+ }
8
+ return lines.join("\n");
9
+ }
10
+ function formatKey(key) {
11
+ return /^[A-Za-z_][A-Za-z0-9_-]*$/.test(key) ? key : JSON.stringify(key);
12
+ }
13
+ function formatValue(value) {
14
+ if (value === null)
15
+ return "null";
16
+ if (typeof value === "boolean")
17
+ return value ? "true" : "false";
18
+ if (typeof value === "number")
19
+ return Number.isFinite(value) ? String(value) : "null";
20
+ if (isBareString(value))
21
+ return value;
22
+ return JSON.stringify(value);
23
+ }
24
+ function isBareString(value) {
25
+ return /^[A-Za-z0-9_./@-]+$/.test(value);
26
+ }
@@ -0,0 +1,85 @@
1
+ const CRC_TABLE = (() => {
2
+ const table = new Uint32Array(256);
3
+ for (let i = 0; i < 256; i += 1) {
4
+ let value = i;
5
+ for (let bit = 0; bit < 8; bit += 1) {
6
+ value = value & 1 ? 0xedb88320 ^ (value >>> 1) : value >>> 1;
7
+ }
8
+ table[i] = value >>> 0;
9
+ }
10
+ return table;
11
+ })();
12
+ export function createStoredZip(entries) {
13
+ const chunks = [];
14
+ const central = [];
15
+ let offset = 0;
16
+ for (const entry of entries) {
17
+ const name = Buffer.from(normalizeZipName(entry.name), "utf8");
18
+ const data = Buffer.isBuffer(entry.data) ? entry.data : Buffer.from(entry.data, "utf8");
19
+ const crc32 = computeCrc32(data);
20
+ const localHeader = Buffer.alloc(30);
21
+ localHeader.writeUInt32LE(0x04034b50, 0);
22
+ localHeader.writeUInt16LE(20, 4);
23
+ localHeader.writeUInt16LE(0x0800, 6);
24
+ localHeader.writeUInt16LE(0, 8);
25
+ localHeader.writeUInt16LE(0, 10);
26
+ localHeader.writeUInt16LE(0, 12);
27
+ localHeader.writeUInt32LE(crc32, 14);
28
+ localHeader.writeUInt32LE(data.length, 18);
29
+ localHeader.writeUInt32LE(data.length, 22);
30
+ localHeader.writeUInt16LE(name.length, 26);
31
+ localHeader.writeUInt16LE(0, 28);
32
+ chunks.push(localHeader, name, data);
33
+ central.push({ name, crc32, size: data.length, offset });
34
+ offset += localHeader.length + name.length + data.length;
35
+ }
36
+ const centralStart = offset;
37
+ for (const entry of central) {
38
+ const header = Buffer.alloc(46);
39
+ header.writeUInt32LE(0x02014b50, 0);
40
+ header.writeUInt16LE(20, 4);
41
+ header.writeUInt16LE(20, 6);
42
+ header.writeUInt16LE(0x0800, 8);
43
+ header.writeUInt16LE(0, 10);
44
+ header.writeUInt16LE(0, 12);
45
+ header.writeUInt16LE(0, 14);
46
+ header.writeUInt32LE(entry.crc32, 16);
47
+ header.writeUInt32LE(entry.size, 20);
48
+ header.writeUInt32LE(entry.size, 24);
49
+ header.writeUInt16LE(entry.name.length, 28);
50
+ header.writeUInt16LE(0, 30);
51
+ header.writeUInt16LE(0, 32);
52
+ header.writeUInt16LE(0, 34);
53
+ header.writeUInt16LE(0, 36);
54
+ header.writeUInt32LE(0, 38);
55
+ header.writeUInt32LE(entry.offset, 42);
56
+ chunks.push(header, entry.name);
57
+ offset += header.length + entry.name.length;
58
+ }
59
+ const centralSize = offset - centralStart;
60
+ const end = Buffer.alloc(22);
61
+ end.writeUInt32LE(0x06054b50, 0);
62
+ end.writeUInt16LE(0, 4);
63
+ end.writeUInt16LE(0, 6);
64
+ end.writeUInt16LE(central.length, 8);
65
+ end.writeUInt16LE(central.length, 10);
66
+ end.writeUInt32LE(centralSize, 12);
67
+ end.writeUInt32LE(centralStart, 16);
68
+ end.writeUInt16LE(0, 20);
69
+ chunks.push(end);
70
+ return Buffer.concat(chunks);
71
+ }
72
+ function normalizeZipName(name) {
73
+ const normalized = name.replace(/\\/g, "/").replace(/^\/+/, "");
74
+ if (!normalized || normalized.includes("..")) {
75
+ throw new Error(`Invalid zip entry name: ${name}`);
76
+ }
77
+ return normalized;
78
+ }
79
+ function computeCrc32(data) {
80
+ let crc = 0xffffffff;
81
+ for (const byte of data) {
82
+ crc = CRC_TABLE[(crc ^ byte) & 0xff] ^ (crc >>> 8);
83
+ }
84
+ return (crc ^ 0xffffffff) >>> 0;
85
+ }