gpt-connector 0.1.0 → 0.3.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 (49) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/README.md +160 -19
  3. package/dist/src/asset-discovery.d.ts +2 -0
  4. package/dist/src/asset-discovery.js +58 -12
  5. package/dist/src/asset-discovery.js.map +1 -1
  6. package/dist/src/attachment-files.d.ts +25 -0
  7. package/dist/src/attachment-files.js +272 -0
  8. package/dist/src/attachment-files.js.map +1 -0
  9. package/dist/src/browser-launcher.d.ts +57 -0
  10. package/dist/src/browser-launcher.js +494 -0
  11. package/dist/src/browser-launcher.js.map +1 -0
  12. package/dist/src/cdp.js +3 -3
  13. package/dist/src/cdp.js.map +1 -1
  14. package/dist/src/cli.js +170 -9
  15. package/dist/src/cli.js.map +1 -1
  16. package/dist/src/connector.d.ts +12 -1
  17. package/dist/src/connector.js +370 -12
  18. package/dist/src/connector.js.map +1 -1
  19. package/dist/src/consult-job-store.d.ts +37 -0
  20. package/dist/src/consult-job-store.js +464 -0
  21. package/dist/src/consult-job-store.js.map +1 -0
  22. package/dist/src/contract.d.ts +86 -0
  23. package/dist/src/contract.js +42 -0
  24. package/dist/src/contract.js.map +1 -1
  25. package/dist/src/errors.d.ts +2 -2
  26. package/dist/src/errors.js +15 -2
  27. package/dist/src/errors.js.map +1 -1
  28. package/dist/src/factory-diagnostics.d.ts +28 -0
  29. package/dist/src/factory-diagnostics.js +109 -0
  30. package/dist/src/factory-diagnostics.js.map +1 -0
  31. package/dist/src/index.d.ts +5 -0
  32. package/dist/src/index.js +5 -0
  33. package/dist/src/index.js.map +1 -1
  34. package/dist/src/mcp-server.d.ts +8 -3
  35. package/dist/src/mcp-server.js +71 -5
  36. package/dist/src/mcp-server.js.map +1 -1
  37. package/dist/src/mcp.js +1 -1
  38. package/dist/src/mcp.js.map +1 -1
  39. package/dist/src/page-bridge.d.ts +2 -2
  40. package/dist/src/page-bridge.js +333 -12
  41. package/dist/src/page-bridge.js.map +1 -1
  42. package/dist/src/runtime-error-store.d.ts +157 -0
  43. package/dist/src/runtime-error-store.js +327 -0
  44. package/dist/src/runtime-error-store.js.map +1 -0
  45. package/dist/src/version.d.ts +1 -0
  46. package/dist/src/version.js +2 -0
  47. package/dist/src/version.js.map +1 -0
  48. package/docs/ai-installer-setup-contract.md +137 -0
  49. package/package.json +5 -3
package/CHANGELOG.md ADDED
@@ -0,0 +1,17 @@
1
+ # Changelog
2
+
3
+ ## 0.3.0 — 2026-07-14
4
+
5
+ - BugHub factory向けに `gpt-connector factory-diagnostics --json` を追加した。既存
6
+ `gpt-connector.diagnostics.v1` の `doctor` 契約は維持する。
7
+ - 明示的な canonical dotagents `collection.enabled: true` の時だけ動く、network I/O を
8
+ 持たない product-owned `runtime-errors` local aggregate を追加した。
9
+ - runtime error の公開面は固定 code/template と SHA-256 fingerprint のみを使う。prompt、
10
+ 応答、添付、識別子、credential、CDP dump、絶対 path、raw error は保存・出力しない。
11
+ - true headlessを使わず、cold startでは窓なしで専用profileのheadful Chromeを起動し、CDPで
12
+ ChatGPT targetを最初から最小化状態で作成・確認してからapp readyを待つ`gpt-connector browser start`
13
+ を追加した。既存endpointもapp probeより先に最小化する。現行macOS実測では最小化中も送受信を維持する。
14
+ - `gpt-connector browser show`で、正規専用profileの一意ChatGPT windowだけを明示的に表示へ戻せるようにした。認証要求時はstartが同じwindowを表示へ戻してから`AUTH_REQUIRED`を返す。
15
+ - window stateのCDP read-backを有界pollにし、非同期遷移直後の旧stateによるfalse failureを防いだ。
16
+ - cold startはhidden Chrome・background minimized targetから開始し、最小化確認後に正規PIDだけをunhideしてからprobeする。
17
+ - showはCDP stateのstale値に依存せず`Page.bringToFront`を送る。最終状態はWindowServerの正規PID/layer 0 window数で確認する。
package/README.md CHANGED
@@ -1,5 +1,8 @@
1
1
  # GPT Connector
2
2
 
3
+ [![npm version](https://img.shields.io/npm/v/gpt-connector.svg)](https://www.npmjs.com/package/gpt-connector)
4
+ [![license](https://img.shields.io/npm/l/gpt-connector.svg)](LICENSE)
5
+
3
6
  Codex開発枠から、ログイン済みChatGPT公式Web runtimeの通常Chatを呼び出すローカルconnector。
4
7
 
5
8
  ブラウザは認証・integrity・attestation・conversation lifecycleの実行環境として使う。composer、送信button、回答DOM、React fiberは操作・参照しない。
@@ -7,6 +10,8 @@ Codex開発枠から、ログイン済みChatGPT公式Web runtimeの通常Chat
7
10
  > [!WARNING]
8
11
  > consumer Chatの非公開Web runtimeとminified bundleに依存する実験的実装。OpenAIの公開・安定APIではない。bundle contractが変わった場合は`RUNTIME_DRIFT`で停止し、別方式へ自動fallbackしない。
9
12
 
13
+ 現在版は[`gpt-connector@0.3.0`](https://www.npmjs.com/package/gpt-connector)。ソースと変更履歴は[GitHub repository](https://github.com/kitepon-rgb/gpt-connector)を正とする。
14
+
10
15
  ## 成立済み機能
11
16
 
12
17
  - 通常Chatのone-shot送信と自動archive。
@@ -16,6 +21,12 @@ Codex開発枠から、ログイン済みChatGPT公式Web runtimeの通常Chat
16
21
  - model/thinking effort明示選択。
17
22
  - Work-only modelの除外。
18
23
  - 非対応model/effortの送信前拒否。
24
+ - 全regular fileのChatGPT正規添付。known extensionは標準MIME、unknown extensionは`application/octet-stream`。
25
+ - workspaceRoot境界、glob、MIME、size、秘密file denylistの送信前検証。
26
+ - 256KiB CDP chunk転送とpage側SHA-256照合。
27
+ - server attachment metadata read-backとモデル読取確認。
28
+ - caller既知slugによるconsult冪等性、terminal result回収、owner-only durable job台帳。
29
+ - upload/conversationを作らないdry-run、既存diagnostics、factory diagnostics。
19
30
  - CLIとstdio MCP adapter。
20
31
 
21
32
  ## 前提
@@ -23,9 +34,10 @@ Codex開発枠から、ログイン済みChatGPT公式Web runtimeの通常Chat
23
34
  - macOS
24
35
  - Google Chrome
25
36
  - Node.js 26以上
26
- - pnpm 11以上
27
37
  - ChatGPTへログインできるaccount
28
38
 
39
+ sourceからbuildする場合だけpnpm 11以上も必要。
40
+
29
41
  ## npm global install
30
42
 
31
43
  ```bash
@@ -33,18 +45,33 @@ npm install --global gpt-connector
33
45
  ```
34
46
 
35
47
  専用Chromeを起動する。通常ChromeとOracle profileは使用しない。
48
+ true headlessは使わず、cold startでは窓なしで専用profileのheadful Chromeを起動する。CDP browser endpointからChatGPT targetを最初から最小化状態で作成し、最小化を確認してからapp readyを待つ。既存endpointではapp probeより先に専用ChatGPT windowを最小化する。現行macOS実測では最小化中も送受信を維持する。
49
+
50
+ Chromeのhidden状態はflashを覆うcold準備中だけに使い、最小化確認後は正規PIDだけをunhideしてからprobeする。hiddenのまま運用せず、Oracleのhide fallbackでもない。
51
+
52
+ `browser start`が成功を返す時点では専用ChatGPT windowは最小化済みである。認証が必要になった場合だけwindowを表示へ戻す。手動でログイン/確認するには次を使う。
53
+
54
+ window stateのCDP read-backは遷移直後の旧stateを単発判定せず、有界時間内に期待stateへ収束したことを確認する。
55
+
56
+ ChromeのCDPはshow後も最小化状態を返すことがあるため、表示/非表示の最終判定は正規PIDのWindowServer layer 0 window数で行う。start成功時は0、show成功時は1件以上である。
57
+ 実機では同時cold startが`started` 1件/`already_ready` 1件へ収束し、新規専用Chrome PIDで15秒・10ms監視中のlayer 0 on-screen最大値は0だった。`models`とchat(`ACCEPTED_NO_FLASH_OK`)の後も0を維持し、show→startは0→1→0を確認した。
58
+
59
+ ```bash
60
+ gpt-connector browser show
61
+ ```
62
+
63
+ Chrome更新時はrelease smokeとして`browser start`、`models`、最小化中の`chat`、必要時の`browser show`を確認する。
36
64
 
37
65
  ```bash
38
- open -na 'Google Chrome' --args \
39
- --remote-debugging-port=9223 \
40
- --user-data-dir="$HOME/.gpt-connector/browser-profile" \
41
- --no-first-run \
42
- --no-default-browser-check \
43
- https://chatgpt.com/
66
+ gpt-connector browser start
44
67
  ```
45
68
 
46
69
  初回だけ、開いた専用ChromeでChatGPTへ手動ログインする。connectorはpassword、cookie、tokenを読み出さない。
47
70
 
71
+ ### AI installer向けセットアップ
72
+
73
+ CodexなどのAIが導入する場合は、[AI installer向けセットアップ契約](docs/ai-installer-setup-contract.md)に従う。AIはinstall、専用Chrome起動、read-only診断、MCP設定を担当し、人間には専用ChromeでのChatGPTログインだけを依頼する。通常ChromeやOracleのprofile、認証情報は使用しない。
74
+
48
75
  ## source setup
49
76
 
50
77
  ```bash
@@ -71,7 +98,75 @@ gpt-connector chat \
71
98
  --prompt 'Reply with exactly: OK'
72
99
  ```
73
100
 
74
- CLIは短命processなのでone-shot専用。複数turn sessionはMCP adapterを使う。
101
+ CLIの`chat`はone-shot専用。`consult` jobはdurable台帳へ残るため、別processの`sessions`から回収できる。複数turnの会話sessionはMCP adapterを使う。
102
+
103
+ 正規添付のdry-run:
104
+
105
+ ```bash
106
+ gpt-connector consult \
107
+ --endpoint http://127.0.0.1:9223 \
108
+ --workspace-root "$PWD" \
109
+ --file 'docs/*.md' \
110
+ --prompt '添付資料を監査してください' \
111
+ --slug review-001 \
112
+ --model gpt-5-6-thinking \
113
+ --effort extended \
114
+ --dry-run
115
+ ```
116
+
117
+ `--dry-run`を外すと、検証済みbytesをChatGPTへ正規添付して通常Chatへ送る。caller timeout後は同じconsultを作り直さず、次で回収する。
118
+
119
+ ```bash
120
+ gpt-connector sessions --slug review-001
121
+ ```
122
+
123
+ read-only診断:
124
+
125
+ ```bash
126
+ gpt-connector doctor
127
+ gpt-connector --version
128
+ ```
129
+
130
+ `doctor`は`gpt-connector.diagnostics.v1` JSONを返します。接続可能なら`overall: "ready"`、CDPや認証などが未準備なら`overall: "not_ready"`と安定`reasonCode`をstdoutへ返し、exit codeは非0です。診断はuploadや会話作成を行いません。
131
+
132
+ ## BugHub factory 契約
133
+
134
+ 既存の `doctor` と別に、factory consumer 用の versioned read-only JSON を提供します。
135
+
136
+ ```bash
137
+ gpt-connector factory-diagnostics --json
138
+ gpt-connector runtime-errors diagnostics --json
139
+ gpt-connector runtime-errors snapshot --after-cursor 0 --limit 256 --json
140
+ ```
141
+
142
+ `factory-diagnostics` は package version、既存 diagnostics schema、overall、consult job の
143
+ state/job schema と migration、CDP、official origin、auth、runtime bridge、stdio MCP contractを
144
+ 固定 check ID で返します。Chrome/CDP/auth が未準備なら `not_ready`、live connector を提供しない
145
+ host は `unsupported`、検査できない項目は `unverified` です。いずれも upload、conversation、archive、
146
+ job 作成を行いません。
147
+
148
+ `runtime-errors` は product-owned local aggregate であり、network I/O は実装しません。canonical
149
+ dotagents factory config(POSIX: `~/.config/dotagents/factory-reporter.json`、Windows native:
150
+ `%LOCALAPPDATA%\\dotagents\\factory-reporter\\config.json`)が厳密な JSON shape で
151
+ `collection.enabled: true` の場合だけ collection を開始します。設定なし・不正設定・
152
+ `reporting.enabled`・token/credentialの存在は collection を有効にしません。既定はOFFです。
153
+
154
+ 公開操作はすべて `--json` 必須です。
155
+
156
+ ```bash
157
+ gpt-connector runtime-errors snapshot --json
158
+ gpt-connector runtime-errors diagnostics --json
159
+ gpt-connector runtime-errors ack 12 --json
160
+ gpt-connector runtime-errors resolve <sha256-fingerprint> --json
161
+ gpt-connector runtime-errors reopen <sha256-fingerprint> --json
162
+ gpt-connector runtime-errors compact --json
163
+ ```
164
+
165
+ recordは固定 code/template、SHA-256 fingerprint、count、first/last seen、status、cursorだけを持ちます。
166
+ ack cursor は単調で、compact は retention を過ぎた resolved かつ ack 済み recordだけを削除します。
167
+ stateは製品所有directoryへ owner-only atomic writeし、symlink・権限 drift・schema改ざんを拒否します。
168
+ prompt、assistant response、file名/内容/digest、conversation/session/job ID、cookie/token、CDP dump、
169
+ 絶対path、生stack/stderrは入力・保存・出力できません。
75
170
 
76
171
  ## Codex MCP
77
172
 
@@ -84,10 +179,13 @@ startup_timeout_sec = 20
84
179
  tool_timeout_sec = 240
85
180
  enabled = true
86
181
  required = false
87
- enabled_tools = ["chatgpt_models", "chatgpt_chat", "chatgpt_close"]
182
+ enabled_tools = ["chatgpt_models", "chatgpt_chat", "chatgpt_close", "consult", "sessions", "diagnostics"]
88
183
 
89
184
  [mcp_servers.gpt_connector.env]
90
185
  GPT_CONNECTOR_CDP_ENDPOINT = "http://127.0.0.1:9223"
186
+ # 任意。未指定時は $XDG_STATE_HOME/gpt-connector、
187
+ # XDG_STATE_HOME未設定時は ~/.local/state/gpt-connector
188
+ GPT_CONNECTOR_STATE_DIR = "/absolute/product-owned/state/gpt-connector"
91
189
  ```
92
190
 
93
191
  設定の正本はOpenAI公式の[Model Context Protocol設定](https://learn.chatgpt.com/docs/extend/mcp#configure-with-configtoml)。
@@ -96,14 +194,34 @@ GPT_CONNECTOR_CDP_ENDPOINT = "http://127.0.0.1:9223"
96
194
  2. 専用Chromeを起動してログインする。
97
195
  3. `.codex/config.toml`を置いたprojectで新しいCodex taskを開く。
98
196
  4. `chatgpt_models`でlive catalogを確認する。
99
- 5. `chatgpt_chat`を呼ぶ。
100
- 6. `keepOpen=true`でsessionを作った場合は、最後に`chatgpt_close`を呼ぶ。
197
+ 5. second opinionはcaller既知slugを付けて`consult`を呼ぶ。
198
+ 6. timeout時は再送せず、同じslugを`sessions`へ渡す。
199
+ 7. 既存互換の複数turnで`keepOpen=true`を使った場合は、最後に`chatgpt_close`を呼ぶ。
101
200
 
102
201
  MCP tools:
103
202
 
104
203
  - `chatgpt_models`: 通常Chat model/effort一覧。
105
204
  - `chatgpt_chat`: 新規またはsession継続。既定`keepOpen=false`で応答後archive。
106
205
  - `chatgpt_close`: sessionをarchiveしてhandleを破棄。deleteは行わない。
206
+ - `consult`: slug冪等化、任意の正規添付、model/effort、dry-runを持つsecond opinion入口。
207
+ - `sessions`: exact slug 1件の状態/terminal resultを返す。uploadや会話を作らず、connector未起動時は台帳を直接読む。
208
+ - `diagnostics`: 接続、bridge build、job/session/operation/upload buffer件数だけを返すread-only診断。
209
+
210
+ 移行期間にCodex側のMCP server idを`oracle`へすれば、tool名は`oracle.consult`/`oracle.sessions`になる。別adapter packageやOracleへの自動fallbackは使わない。
211
+
212
+ ## attachment contract
213
+
214
+ - `workspaceRoot`はabsolute directory、`files`はそこからのrelative pathまたはglob。
215
+ - spec順、glob内POSIX path順、realpath first occurrenceで決定的に解決する。
216
+ - absolute file path、`..`、root外symlink、directory、empty fileを拒否する。
217
+ - regular fileは形式を問わず元bytesのまま公式uploadへ渡す。一般的なtext、image、PDF、Office、archive、audio、videoには標準MIME、未知拡張子には`application/octet-stream`を使う。localで内容解析・変換は行わず、ChatGPTが解釈できる形式かは公式runtimeが判断する。
218
+ - 最大20 file、20MiB/file、64MiB total。
219
+ - `.env*`、key/certificate、credential/secret名など明白な秘密fileをoverrideなしで拒否する。
220
+ - ChatGPTへ渡すのはbytes、basename、MIMEだけ。ローカルabsolute pathはpage contextやtool resultへ渡さない。
221
+ - upload済みfileの削除手段は未成立。結果は`retention=unknown`、`cleanup=not_supported`と返し、archiveをfile cleanupとは表現しない。
222
+ - OpenAI公式は一般的なtext、spreadsheet、presentation、documentを対応対象として例示する一方、`.gdoc`は非対応としている。pass-through可能であることは、モデルが内容を解釈できる保証ではない。
223
+
224
+ 詳細は[`docs/native-attachment-contract.md`](docs/native-attachment-contract.md)。
107
225
 
108
226
  ## model/effort contract
109
227
 
@@ -124,39 +242,62 @@ MCP tools:
124
242
  - one-shotと`chatgpt_close`はserverの`is_archived=true`をread-backしてから成功を返す。
125
243
  - delete機能はない。
126
244
 
245
+ `consult` jobは別契約:
246
+
247
+ - callerが`^[a-z0-9][a-z0-9._-]{2,63}$`のslugを事前指定する。
248
+ - 同slug/同fingerprintは既存snapshotを返し、再upload/再送しない。
249
+ - 同slugへ異なるinputは`JOB_CONFLICT`。
250
+ - stateは`queued | uploading | submitted | running | succeeded | failed`。
251
+ - terminal jobはowner-only JSONへatomic保存し、process再起動後も`sessions`で回収できる。
252
+ - 再起動前の非terminal jobは完了有無を断定せず`JOB_RECOVERY_UNAVAILABLE`へ固定し、自動再送しない。
253
+
127
254
  ## failure codes
128
255
 
256
+ - `INVALID_INPUT`
129
257
  - `AUTH_REQUIRED`
130
258
  - `CDP_UNAVAILABLE`
131
259
  - `RUNTIME_DRIFT`
132
260
  - `MODEL_NOT_AVAILABLE`
133
261
  - `EFFORT_NOT_SUPPORTED`
262
+ - `FILE_NOT_FOUND`
263
+ - `FILE_OUTSIDE_ROOT`
264
+ - `SENSITIVE_FILE_BLOCKED`
265
+ - `FILE_TYPE_NOT_SUPPORTED`
266
+ - `FILE_EMPTY`
267
+ - `FILE_LIMIT_EXCEEDED`
268
+ - `UPLOAD_FAILED`
269
+ - `UPLOAD_TIMEOUT`
270
+ - `ATTACHMENT_READBACK_FAILED`
134
271
  - `CHAT_FAILED`
135
272
  - `STREAM_INCOMPLETE`
136
273
  - `SESSION_NOT_FOUND`
137
274
  - `SESSION_BUSY`
138
275
  - `ARCHIVE_FAILED`
276
+ - `JOB_NOT_FOUND`
277
+ - `JOB_CONFLICT`
278
+ - `JOB_RECOVERY_UNAVAILABLE`
139
279
 
140
280
  ## 秘密情報とログ
141
281
 
142
282
  - cookie、authorization、access/refresh token、integrity、attestation、conduit tokenを取得・保存しない。
143
283
  - CDP生dumpを保存しない。
144
284
  - server conversation IDをtool resultやlogへ出さない。
145
- - prompt/responseconnector側でlogしない。tool resultにはrequested assistant本文だけを返す。
285
+ - prompt、file本文、absolute pathをlogやjob台帳へ保存しない。
286
+ - terminal assistant responseはcaller timeout後の回収に必要なため、fingerprint/状態/結果とともにowner-only job台帳へ保存する。
287
+ - job台帳は製品所有state directoryに置き、他ツールの管理directoryやhookへ便乗しない。
146
288
  - `.browser-profile/`、log、temporary dumpはgit管理外。
147
289
 
148
290
  ## architecture
149
291
 
150
292
  ```text
151
- Codex ──stdio MCP──> GptConnector core ──raw CDP──> ChatGPT page main world
152
-
153
- └─ official factory
154
- builder
155
- sender
156
- → state getter
293
+ Codex ──stdio MCP──> resolver/job store ──> GptConnector core ──raw CDP──> ChatGPT page main world
294
+
295
+ └─ slug status ├─ official upload client
296
+ ├─ builder/sender
297
+ └─ state/server read-back
157
298
  ```
158
299
 
159
- runtime roleasset marker、function source signature、object method shape、read-only catalog probeで一意検出する。候補が0件または複数なら実行しない。
300
+ runtime roleは上限付きasset import graph、function source signature、object method shape、read-only catalog probeで一意検出する。候補が0件または複数なら実行しない。DOM selector、file input、React fiber、座標操作は本番経路に含まない。
160
301
 
161
302
  ## license
162
303
 
@@ -2,8 +2,10 @@ import type { CdpClient } from "./cdp.js";
2
2
  export interface RuntimeAssets {
3
3
  readonly coreUrl: string;
4
4
  readonly conversationUrl: string;
5
+ readonly uploadUrl: string;
5
6
  readonly coreFingerprint: string;
6
7
  readonly conversationFingerprint: string;
8
+ readonly uploadFingerprint: string;
7
9
  }
8
10
  export declare function listLoadedAssetUrls(client: CdpClient): Promise<readonly string[]>;
9
11
  export declare function discoverRuntimeAssets(urls: readonly string[], fetchImplementation?: typeof fetch): Promise<RuntimeAssets>;
@@ -12,6 +12,13 @@ const conversationMarkers = [
12
12
  "selectedSkillIds",
13
13
  "build_request_params.prompt_message",
14
14
  ];
15
+ const uploadMarkers = [
16
+ "process_upload_stream",
17
+ "attachLibraryFile",
18
+ "uploadFile:async",
19
+ ];
20
+ const maxAssetCount = 800;
21
+ const assetBatchSize = 12;
15
22
  function allowedAssetUrl(value) {
16
23
  try {
17
24
  const url = new URL(value);
@@ -26,6 +33,21 @@ function allowedAssetUrl(value) {
26
33
  function fingerprint(source) {
27
34
  return createHash("sha256").update(source).digest("hex").slice(0, 16);
28
35
  }
36
+ function importedAssetUrls(baseUrl, source) {
37
+ const matches = source.matchAll(/(?:https:\/\/(?:chatgpt\.com|[a-z0-9.-]+\.oaistatic\.com))?\/(?:cdn\/assets|assets|_next\/static\/chunks)\/[a-zA-Z0-9_-]+\.js|(?:\.\.?\/)[a-zA-Z0-9_-]+\.js/gu);
38
+ const urls = [];
39
+ for (const match of matches) {
40
+ try {
41
+ const url = new URL(match[0], baseUrl).href;
42
+ if (allowedAssetUrl(url))
43
+ urls.push(url);
44
+ }
45
+ catch {
46
+ // 不正なimport-like文字列はasset候補にしない。
47
+ }
48
+ }
49
+ return [...new Set(urls)];
50
+ }
29
51
  function findUnique(role, candidates, markers) {
30
52
  const matches = candidates.filter(({ source }) => markers.every((marker) => source.includes(marker)));
31
53
  if (matches.length !== 1) {
@@ -36,6 +58,10 @@ function findUnique(role, candidates, markers) {
36
58
  export async function listLoadedAssetUrls(client) {
37
59
  const expression = String.raw `(() => Array.from(new Set([
38
60
  ...Array.from(document.scripts, (element) => element.src),
61
+ ...Array.from(document.scripts)
62
+ .filter((element) => !element.src && element.type === "module")
63
+ .flatMap((element) => element.textContent?.match(/\/(?:cdn\/assets|_next\/static\/chunks)\/[a-zA-Z0-9_-]+\.js/g) ?? [])
64
+ .map((path) => new URL(path, location.origin).href),
39
65
  ...Array.from(document.head.children)
40
66
  .filter((element) => element.tagName === "LINK" && element.rel === "modulepreload")
41
67
  .map((element) => element.href),
@@ -48,26 +74,46 @@ export async function listLoadedAssetUrls(client) {
48
74
  return [...new Set(raw.filter(allowedAssetUrl))];
49
75
  }
50
76
  export async function discoverRuntimeAssets(urls, fetchImplementation = fetch) {
51
- const candidates = await Promise.all(urls.map(async (url) => {
52
- let response;
53
- try {
54
- response = await fetchImplementation(url);
77
+ const queue = [...new Set(urls.filter(allowedAssetUrl))];
78
+ const queued = new Set(queue);
79
+ const fetched = [];
80
+ while (queue.length > 0 && fetched.length < maxAssetCount) {
81
+ const remaining = maxAssetCount - fetched.length;
82
+ const batch = queue.splice(0, Math.min(assetBatchSize, remaining));
83
+ const candidates = await Promise.all(batch.map(async (url) => {
84
+ let response;
85
+ try {
86
+ response = await fetchImplementation(url);
87
+ }
88
+ catch {
89
+ return null;
90
+ }
91
+ if (!response.ok)
92
+ return null;
93
+ return { url, source: await response.text() };
94
+ }));
95
+ for (const candidate of candidates) {
96
+ if (candidate === null)
97
+ continue;
98
+ fetched.push(candidate);
99
+ for (const importedUrl of importedAssetUrls(candidate.url, candidate.source)) {
100
+ if (queued.has(importedUrl))
101
+ continue;
102
+ queued.add(importedUrl);
103
+ queue.push(importedUrl);
104
+ }
55
105
  }
56
- catch {
57
- return null;
58
- }
59
- if (!response.ok)
60
- return null;
61
- return { url, source: await response.text() };
62
- }));
63
- const fetched = candidates.filter((candidate) => candidate !== null);
106
+ }
64
107
  const core = findUnique("core", fetched, coreMarkers);
65
108
  const conversation = findUnique("conversation", fetched, conversationMarkers);
109
+ const upload = findUnique("upload", fetched, uploadMarkers);
66
110
  return {
67
111
  coreUrl: core.url,
68
112
  conversationUrl: conversation.url,
113
+ uploadUrl: upload.url,
69
114
  coreFingerprint: fingerprint(core.source),
70
115
  conversationFingerprint: fingerprint(conversation.source),
116
+ uploadFingerprint: fingerprint(upload.source),
71
117
  };
72
118
  }
73
119
  //# sourceMappingURL=asset-discovery.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"asset-discovery.js","sourceRoot":"","sources":["../../src/asset-discovery.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"asset-discovery.js","sourceRoot":"","sources":["../../src/asset-discovery.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAiBxD,MAAM,WAAW,GAAG;IAClB,yBAAyB;IACzB,eAAe;IACf,2BAA2B;CACnB,CAAC;AAEX,MAAM,mBAAmB,GAAG;IAC1B,eAAe;IACf,gBAAgB;IAChB,kBAAkB;IAClB,qCAAqC;CAC7B,CAAC;AAEX,MAAM,aAAa,GAAG;IACpB,uBAAuB;IACvB,mBAAmB;IACnB,kBAAkB;CACV,CAAC;AAEX,MAAM,aAAa,GAAG,GAAG,CAAC;AAC1B,MAAM,cAAc,GAAG,EAAE,CAAC;AAE1B,SAAS,eAAe,CAAC,KAAa;IACpC,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC;QAC3B,OAAO,CACL,GAAG,CAAC,QAAQ,KAAK,QAAQ;YACzB,CAAC,GAAG,CAAC,QAAQ,KAAK,aAAa,IAAI,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAC;YAC3E,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC,CAC7B,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,SAAS,WAAW,CAAC,MAAc;IACjC,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AACxE,CAAC;AAED,SAAS,iBAAiB,CAAC,OAAe,EAAE,MAAc;IACxD,MAAM,OAAO,GAAG,MAAM,CAAC,QAAQ,CAC7B,+JAA+J,CAChK,CAAC;IACF,MAAM,IAAI,GAAa,EAAE,CAAC;IAC1B,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC;YAC5C,IAAI,eAAe,CAAC,GAAG,CAAC;gBAAE,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC3C,CAAC;QAAC,MAAM,CAAC;YACP,iCAAiC;QACnC,CAAC;IACH,CAAC;IACD,OAAO,CAAC,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;AAC5B,CAAC;AAED,SAAS,UAAU,CACjB,IAAY,EACZ,UAAqC,EACrC,OAA0B;IAE1B,MAAM,OAAO,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CAC/C,OAAO,CAAC,KAAK,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CACnD,CAAC;IAEF,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,MAAM,IAAI,cAAc,CACtB,eAAe,EACf,GAAG,IAAI,uBAAuB,EAC9B,EAAE,KAAK,EAAE,OAAO,CAAC,MAAM,EAAE,CAC1B,CAAC;IACJ,CAAC;IAED,OAAO,OAAO,CAAC,CAAC,CAAE,CAAC;AACrB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,MAAiB;IACzD,MAAM,UAAU,GAAG,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;yBAUN,CAAC;IAExB,MAAM,GAAG,GAAG,MAAM,eAAe,CAAU,MAAM,EAAE,UAAU,CAAC,CAAC;IAC/D,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,IAAI,KAAK,QAAQ,CAAC,EAAE,CAAC;QACxE,MAAM,IAAI,cAAc,CAAC,eAAe,EAAE,6BAA6B,CAAC,CAAC;IAC3E,CAAC;IAED,OAAO,CAAC,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;AACnD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,IAAuB,EACvB,sBAAoC,KAAK;IAEzC,MAAM,KAAK,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;IACzD,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC;IAC9B,MAAM,OAAO,GAAqB,EAAE,CAAC;IAErC,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,OAAO,CAAC,MAAM,GAAG,aAAa,EAAE,CAAC;QAC1D,MAAM,SAAS,GAAG,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC;QACjD,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,cAAc,EAAE,SAAS,CAAC,CAAC,CAAC;QACnE,MAAM,UAAU,GAAG,MAAM,OAAO,CAAC,GAAG,CAClC,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,EAAkC,EAAE;YACtD,IAAI,QAAkB,CAAC;YACvB,IAAI,CAAC;gBACH,QAAQ,GAAG,MAAM,mBAAmB,CAAC,GAAG,CAAC,CAAC;YAC5C,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,IAAI,CAAC;YACd,CAAC;YACD,IAAI,CAAC,QAAQ,CAAC,EAAE;gBAAE,OAAO,IAAI,CAAC;YAC9B,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC;QAChD,CAAC,CAAC,CACH,CAAC;QAEF,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;YACnC,IAAI,SAAS,KAAK,IAAI;gBAAE,SAAS;YACjC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACxB,KAAK,MAAM,WAAW,IAAI,iBAAiB,CAAC,SAAS,CAAC,GAAG,EAAE,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC;gBAC7E,IAAI,MAAM,CAAC,GAAG,CAAC,WAAW,CAAC;oBAAE,SAAS;gBACtC,MAAM,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;gBACxB,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;YAC1B,CAAC;QACH,CAAC;IACH,CAAC;IAED,MAAM,IAAI,GAAG,UAAU,CAAC,MAAM,EAAE,OAAO,EAAE,WAAW,CAAC,CAAC;IACtD,MAAM,YAAY,GAAG,UAAU,CAAC,cAAc,EAAE,OAAO,EAAE,mBAAmB,CAAC,CAAC;IAC9E,MAAM,MAAM,GAAG,UAAU,CAAC,QAAQ,EAAE,OAAO,EAAE,aAAa,CAAC,CAAC;IAE5D,OAAO;QACL,OAAO,EAAE,IAAI,CAAC,GAAG;QACjB,eAAe,EAAE,YAAY,CAAC,GAAG;QACjC,SAAS,EAAE,MAAM,CAAC,GAAG;QACrB,eAAe,EAAE,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC;QACzC,uBAAuB,EAAE,WAAW,CAAC,YAAY,CAAC,MAAM,CAAC;QACzD,iBAAiB,EAAE,WAAW,CAAC,MAAM,CAAC,MAAM,CAAC;KAC9C,CAAC;AACJ,CAAC"}
@@ -0,0 +1,25 @@
1
+ export declare const attachmentLimits: {
2
+ readonly maxFiles: 20;
3
+ readonly maxFileBytes: number;
4
+ readonly maxTotalBytes: number;
5
+ };
6
+ export interface AttachmentFile {
7
+ readonly relativePath: string;
8
+ readonly name: string;
9
+ readonly bytes: number;
10
+ readonly mimeType: string;
11
+ readonly sha256: string;
12
+ }
13
+ export interface PreparedAttachmentFile extends AttachmentFile {
14
+ readonly content: Uint8Array;
15
+ }
16
+ export interface AttachmentFileResolution<TFile extends AttachmentFile = AttachmentFile> {
17
+ readonly files: readonly TFile[];
18
+ readonly totalBytes: number;
19
+ }
20
+ export interface ResolveAttachmentFilesInput {
21
+ readonly workspaceRoot: string;
22
+ readonly specs: readonly string[];
23
+ }
24
+ export declare function prepareAttachmentFiles(input: ResolveAttachmentFilesInput): Promise<AttachmentFileResolution<PreparedAttachmentFile>>;
25
+ export declare function resolveAttachmentFiles(input: ResolveAttachmentFilesInput): Promise<AttachmentFileResolution>;