gpt-connector 0.1.0 → 0.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.
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.2.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。
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
@@ -71,7 +83,36 @@ gpt-connector chat \
71
83
  --prompt 'Reply with exactly: OK'
72
84
  ```
73
85
 
74
- CLIは短命processなのでone-shot専用。複数turn sessionはMCP adapterを使う。
86
+ CLIの`chat`はone-shot専用。`consult` jobはdurable台帳へ残るため、別processの`sessions`から回収できる。複数turnの会話sessionはMCP adapterを使う。
87
+
88
+ 正規添付のdry-run:
89
+
90
+ ```bash
91
+ gpt-connector consult \
92
+ --endpoint http://127.0.0.1:9223 \
93
+ --workspace-root "$PWD" \
94
+ --file 'docs/*.md' \
95
+ --prompt '添付資料を監査してください' \
96
+ --slug review-001 \
97
+ --model gpt-5-6-thinking \
98
+ --effort extended \
99
+ --dry-run
100
+ ```
101
+
102
+ `--dry-run`を外すと、検証済みbytesをChatGPTへ正規添付して通常Chatへ送る。caller timeout後は同じconsultを作り直さず、次で回収する。
103
+
104
+ ```bash
105
+ gpt-connector sessions --slug review-001
106
+ ```
107
+
108
+ read-only診断:
109
+
110
+ ```bash
111
+ gpt-connector doctor
112
+ gpt-connector --version
113
+ ```
114
+
115
+ `doctor`は`gpt-connector.diagnostics.v1` JSONを返します。接続可能なら`overall: "ready"`、CDPや認証などが未準備なら`overall: "not_ready"`と安定`reasonCode`をstdoutへ返し、exit codeは非0です。診断はuploadや会話作成を行いません。
75
116
 
76
117
  ## Codex MCP
77
118
 
@@ -84,10 +125,13 @@ startup_timeout_sec = 20
84
125
  tool_timeout_sec = 240
85
126
  enabled = true
86
127
  required = false
87
- enabled_tools = ["chatgpt_models", "chatgpt_chat", "chatgpt_close"]
128
+ enabled_tools = ["chatgpt_models", "chatgpt_chat", "chatgpt_close", "consult", "sessions", "diagnostics"]
88
129
 
89
130
  [mcp_servers.gpt_connector.env]
90
131
  GPT_CONNECTOR_CDP_ENDPOINT = "http://127.0.0.1:9223"
132
+ # 任意。未指定時は $XDG_STATE_HOME/gpt-connector、
133
+ # XDG_STATE_HOME未設定時は ~/.local/state/gpt-connector
134
+ GPT_CONNECTOR_STATE_DIR = "/absolute/product-owned/state/gpt-connector"
91
135
  ```
92
136
 
93
137
  設定の正本はOpenAI公式の[Model Context Protocol設定](https://learn.chatgpt.com/docs/extend/mcp#configure-with-configtoml)。
@@ -96,14 +140,34 @@ GPT_CONNECTOR_CDP_ENDPOINT = "http://127.0.0.1:9223"
96
140
  2. 専用Chromeを起動してログインする。
97
141
  3. `.codex/config.toml`を置いたprojectで新しいCodex taskを開く。
98
142
  4. `chatgpt_models`でlive catalogを確認する。
99
- 5. `chatgpt_chat`を呼ぶ。
100
- 6. `keepOpen=true`でsessionを作った場合は、最後に`chatgpt_close`を呼ぶ。
143
+ 5. second opinionはcaller既知slugを付けて`consult`を呼ぶ。
144
+ 6. timeout時は再送せず、同じslugを`sessions`へ渡す。
145
+ 7. 既存互換の複数turnで`keepOpen=true`を使った場合は、最後に`chatgpt_close`を呼ぶ。
101
146
 
102
147
  MCP tools:
103
148
 
104
149
  - `chatgpt_models`: 通常Chat model/effort一覧。
105
150
  - `chatgpt_chat`: 新規またはsession継続。既定`keepOpen=false`で応答後archive。
106
151
  - `chatgpt_close`: sessionをarchiveしてhandleを破棄。deleteは行わない。
152
+ - `consult`: slug冪等化、任意の正規添付、model/effort、dry-runを持つsecond opinion入口。
153
+ - `sessions`: exact slug 1件の状態/terminal resultを返す。uploadや会話を作らず、connector未起動時は台帳を直接読む。
154
+ - `diagnostics`: 接続、bridge build、job/session/operation/upload buffer件数だけを返すread-only診断。
155
+
156
+ 移行期間にCodex側のMCP server idを`oracle`へすれば、tool名は`oracle.consult`/`oracle.sessions`になる。別adapter packageやOracleへの自動fallbackは使わない。
157
+
158
+ ## attachment contract
159
+
160
+ - `workspaceRoot`はabsolute directory、`files`はそこからのrelative pathまたはglob。
161
+ - spec順、glob内POSIX path順、realpath first occurrenceで決定的に解決する。
162
+ - absolute file path、`..`、root外symlink、directory、empty fileを拒否する。
163
+ - regular fileは形式を問わず元bytesのまま公式uploadへ渡す。一般的なtext、image、PDF、Office、archive、audio、videoには標準MIME、未知拡張子には`application/octet-stream`を使う。localで内容解析・変換は行わず、ChatGPTが解釈できる形式かは公式runtimeが判断する。
164
+ - 最大20 file、20MiB/file、64MiB total。
165
+ - `.env*`、key/certificate、credential/secret名など明白な秘密fileをoverrideなしで拒否する。
166
+ - ChatGPTへ渡すのはbytes、basename、MIMEだけ。ローカルabsolute pathはpage contextやtool resultへ渡さない。
167
+ - upload済みfileの削除手段は未成立。結果は`retention=unknown`、`cleanup=not_supported`と返し、archiveをfile cleanupとは表現しない。
168
+ - OpenAI公式は一般的なtext、spreadsheet、presentation、documentを対応対象として例示する一方、`.gdoc`は非対応としている。pass-through可能であることは、モデルが内容を解釈できる保証ではない。
169
+
170
+ 詳細は[`docs/native-attachment-contract.md`](docs/native-attachment-contract.md)。
107
171
 
108
172
  ## model/effort contract
109
173
 
@@ -124,39 +188,62 @@ MCP tools:
124
188
  - one-shotと`chatgpt_close`はserverの`is_archived=true`をread-backしてから成功を返す。
125
189
  - delete機能はない。
126
190
 
191
+ `consult` jobは別契約:
192
+
193
+ - callerが`^[a-z0-9][a-z0-9._-]{2,63}$`のslugを事前指定する。
194
+ - 同slug/同fingerprintは既存snapshotを返し、再upload/再送しない。
195
+ - 同slugへ異なるinputは`JOB_CONFLICT`。
196
+ - stateは`queued | uploading | submitted | running | succeeded | failed`。
197
+ - terminal jobはowner-only JSONへatomic保存し、process再起動後も`sessions`で回収できる。
198
+ - 再起動前の非terminal jobは完了有無を断定せず`JOB_RECOVERY_UNAVAILABLE`へ固定し、自動再送しない。
199
+
127
200
  ## failure codes
128
201
 
202
+ - `INVALID_INPUT`
129
203
  - `AUTH_REQUIRED`
130
204
  - `CDP_UNAVAILABLE`
131
205
  - `RUNTIME_DRIFT`
132
206
  - `MODEL_NOT_AVAILABLE`
133
207
  - `EFFORT_NOT_SUPPORTED`
208
+ - `FILE_NOT_FOUND`
209
+ - `FILE_OUTSIDE_ROOT`
210
+ - `SENSITIVE_FILE_BLOCKED`
211
+ - `FILE_TYPE_NOT_SUPPORTED`
212
+ - `FILE_EMPTY`
213
+ - `FILE_LIMIT_EXCEEDED`
214
+ - `UPLOAD_FAILED`
215
+ - `UPLOAD_TIMEOUT`
216
+ - `ATTACHMENT_READBACK_FAILED`
134
217
  - `CHAT_FAILED`
135
218
  - `STREAM_INCOMPLETE`
136
219
  - `SESSION_NOT_FOUND`
137
220
  - `SESSION_BUSY`
138
221
  - `ARCHIVE_FAILED`
222
+ - `JOB_NOT_FOUND`
223
+ - `JOB_CONFLICT`
224
+ - `JOB_RECOVERY_UNAVAILABLE`
139
225
 
140
226
  ## 秘密情報とログ
141
227
 
142
228
  - cookie、authorization、access/refresh token、integrity、attestation、conduit tokenを取得・保存しない。
143
229
  - CDP生dumpを保存しない。
144
230
  - server conversation IDをtool resultやlogへ出さない。
145
- - prompt/responseconnector側でlogしない。tool resultにはrequested assistant本文だけを返す。
231
+ - prompt、file本文、absolute pathをlogやjob台帳へ保存しない。
232
+ - terminal assistant responseはcaller timeout後の回収に必要なため、fingerprint/状態/結果とともにowner-only job台帳へ保存する。
233
+ - job台帳は製品所有state directoryに置き、他ツールの管理directoryやhookへ便乗しない。
146
234
  - `.browser-profile/`、log、temporary dumpはgit管理外。
147
235
 
148
236
  ## architecture
149
237
 
150
238
  ```text
151
- Codex ──stdio MCP──> GptConnector core ──raw CDP──> ChatGPT page main world
152
-
153
- └─ official factory
154
- builder
155
- sender
156
- → state getter
239
+ Codex ──stdio MCP──> resolver/job store ──> GptConnector core ──raw CDP──> ChatGPT page main world
240
+
241
+ └─ slug status ├─ official upload client
242
+ ├─ builder/sender
243
+ └─ state/server read-back
157
244
  ```
158
245
 
159
- runtime roleasset marker、function source signature、object method shape、read-only catalog probeで一意検出する。候補が0件または複数なら実行しない。
246
+ runtime roleは上限付きasset import graph、function source signature、object method shape、read-only catalog probeで一意検出する。候補が0件または複数なら実行しない。DOM selector、file input、React fiber、座標操作は本番経路に含まない。
160
247
 
161
248
  ## license
162
249
 
@@ -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":"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"}
@@ -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>;
@@ -0,0 +1,272 @@
1
+ import { createHash } from "node:crypto";
2
+ import { constants } from "node:fs";
3
+ import { glob, open, realpath, stat } from "node:fs/promises";
4
+ import { isAbsolute, relative, sep } from "node:path";
5
+ import { ConnectorError } from "./errors.js";
6
+ export const attachmentLimits = {
7
+ maxFiles: 20,
8
+ maxFileBytes: 20 * 1024 * 1024,
9
+ maxTotalBytes: 64 * 1024 * 1024,
10
+ };
11
+ const mimeTypes = new Map([
12
+ [".md", "text/markdown"],
13
+ [".csv", "text/csv"],
14
+ [".tsv", "text/tab-separated-values"],
15
+ [".json", "application/json"],
16
+ [".xml", "application/xml"],
17
+ [".html", "text/html"],
18
+ [".css", "text/css"],
19
+ [".svg", "image/svg+xml"],
20
+ [".png", "image/png"],
21
+ [".jpg", "image/jpeg"],
22
+ [".jpeg", "image/jpeg"],
23
+ [".gif", "image/gif"],
24
+ [".webp", "image/webp"],
25
+ [".bmp", "image/bmp"],
26
+ [".tif", "image/tiff"],
27
+ [".tiff", "image/tiff"],
28
+ [".heic", "image/heic"],
29
+ [".heif", "image/heif"],
30
+ [".pdf", "application/pdf"],
31
+ [".rtf", "application/rtf"],
32
+ [".doc", "application/msword"],
33
+ [".docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document"],
34
+ [".odt", "application/vnd.oasis.opendocument.text"],
35
+ [".xls", "application/vnd.ms-excel"],
36
+ [".xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"],
37
+ [".ods", "application/vnd.oasis.opendocument.spreadsheet"],
38
+ [".ppt", "application/vnd.ms-powerpoint"],
39
+ [".pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation"],
40
+ [".odp", "application/vnd.oasis.opendocument.presentation"],
41
+ [".zip", "application/zip"],
42
+ [".tar", "application/x-tar"],
43
+ [".gz", "application/gzip"],
44
+ [".tgz", "application/gzip"],
45
+ [".bz2", "application/x-bzip2"],
46
+ [".7z", "application/x-7z-compressed"],
47
+ [".rar", "application/vnd.rar"],
48
+ [".epub", "application/epub+zip"],
49
+ [".mp3", "audio/mpeg"],
50
+ [".wav", "audio/wav"],
51
+ [".m4a", "audio/mp4"],
52
+ [".ogg", "audio/ogg"],
53
+ [".flac", "audio/flac"],
54
+ [".aac", "audio/aac"],
55
+ [".mp4", "video/mp4"],
56
+ [".mov", "video/quicktime"],
57
+ [".webm", "video/webm"],
58
+ [".mkv", "video/x-matroska"],
59
+ ]);
60
+ const textExtensions = new Set([
61
+ ".txt", ".md", ".rst", ".json", ".jsonl", ".yaml", ".yml", ".toml", ".ini",
62
+ ".xml", ".csv", ".tsv", ".js", ".mjs", ".cjs", ".ts", ".mts", ".cts", ".jsx",
63
+ ".tsx", ".py", ".rb", ".go", ".rs", ".java", ".kt", ".swift", ".c", ".h", ".cpp",
64
+ ".hpp", ".cs", ".php", ".sh", ".bash", ".zsh", ".fish", ".ps1", ".sql", ".css", ".scss",
65
+ ".html", ".diff", ".patch",
66
+ ]);
67
+ function fail(code, message) {
68
+ throw new ConnectorError(code, message);
69
+ }
70
+ function normalizedRelativePath(value) {
71
+ return value.split(sep).join("/");
72
+ }
73
+ function hasParentSegment(spec) {
74
+ return spec.split(/[\\/]/u).some((segment) => segment === "..");
75
+ }
76
+ function validateSpec(spec) {
77
+ if (spec.length === 0 || spec.includes("\0") || isAbsolute(spec) || hasParentSegment(spec)) {
78
+ fail("INVALID_INPUT", "添付file specはworkspaceRoot相対pathまたはglobで指定してください。");
79
+ }
80
+ }
81
+ function extensionOf(relativePath) {
82
+ const name = relativePath.slice(relativePath.lastIndexOf("/") + 1);
83
+ const dot = name.lastIndexOf(".");
84
+ return dot <= 0 ? "" : name.slice(dot).toLowerCase();
85
+ }
86
+ function isSensitive(relativePath) {
87
+ const name = relativePath.slice(relativePath.lastIndexOf("/") + 1).toLowerCase();
88
+ return name === ".env" || name.startsWith(".env.") || name === ".npmrc" || name === ".netrc" ||
89
+ [".pem", ".key", ".p12", ".pfx", ".kdbx"].some((extension) => name.endsWith(extension)) ||
90
+ name.startsWith("id_rsa") || name.startsWith("id_ed25519") ||
91
+ (name.startsWith("credentials") && name.endsWith(".json")) ||
92
+ (name.startsWith("service-account") && name.endsWith(".json")) || name.startsWith("secrets.");
93
+ }
94
+ function isInsideRoot(root, candidate) {
95
+ const pathFromRoot = relative(root, candidate);
96
+ return pathFromRoot === "" || (!pathFromRoot.startsWith(`..${sep}`) && pathFromRoot !== ".." && !isAbsolute(pathFromRoot));
97
+ }
98
+ function sameFileIdentity(left, right) {
99
+ return left.dev === right.dev && left.ino === right.ino;
100
+ }
101
+ function zeroPreparedContents(files) {
102
+ for (const file of files)
103
+ file.content.fill(0);
104
+ }
105
+ async function matchesForSpec(workspaceRoot, spec) {
106
+ try {
107
+ const matches = [];
108
+ for await (const match of glob(spec, { cwd: workspaceRoot, followSymlinks: false })) {
109
+ matches.push(normalizedRelativePath(match));
110
+ }
111
+ return matches.sort((left, right) => (left < right ? -1 : left > right ? 1 : 0));
112
+ }
113
+ catch {
114
+ fail("INVALID_INPUT", "添付file specを解決できませんでした。");
115
+ }
116
+ }
117
+ function metadataOf(relativePath, content) {
118
+ const extension = extensionOf(relativePath);
119
+ const mimeType = mimeTypes.get(extension) ??
120
+ (textExtensions.has(extension) ? "text/plain" : "application/octet-stream");
121
+ return {
122
+ relativePath,
123
+ name: relativePath.slice(relativePath.lastIndexOf("/") + 1),
124
+ bytes: content.byteLength,
125
+ mimeType,
126
+ sha256: createHash("sha256").update(content).digest("hex"),
127
+ };
128
+ }
129
+ export async function prepareAttachmentFiles(input) {
130
+ if (!isAbsolute(input.workspaceRoot)) {
131
+ fail("INVALID_INPUT", "workspaceRootはabsolute directoryで指定してください。");
132
+ }
133
+ if (input.specs.length > attachmentLimits.maxFiles) {
134
+ fail("FILE_LIMIT_EXCEEDED", "添付file specは20件以下にしてください。");
135
+ }
136
+ for (const spec of input.specs)
137
+ validateSpec(spec);
138
+ let workspaceRealPath;
139
+ try {
140
+ const workspaceStat = await stat(input.workspaceRoot);
141
+ if (!workspaceStat.isDirectory()) {
142
+ fail("INVALID_INPUT", "workspaceRootはdirectoryで指定してください。");
143
+ }
144
+ workspaceRealPath = await realpath(input.workspaceRoot);
145
+ }
146
+ catch (error) {
147
+ if (error instanceof ConnectorError)
148
+ throw error;
149
+ fail("INVALID_INPUT", "workspaceRootは読み取り可能なdirectoryで指定してください。");
150
+ }
151
+ const files = [];
152
+ const seenRealPaths = new Set();
153
+ let totalBytes = 0;
154
+ let expandedCount = 0;
155
+ try {
156
+ for (const spec of input.specs) {
157
+ const matches = await matchesForSpec(workspaceRealPath, spec);
158
+ if (matches.length === 0) {
159
+ fail("FILE_NOT_FOUND", "添付file specに一致するfileがありません。");
160
+ }
161
+ expandedCount += matches.length;
162
+ if (expandedCount > attachmentLimits.maxFiles) {
163
+ fail("FILE_LIMIT_EXCEEDED", "glob展開後の添付fileは20件以下にしてください。");
164
+ }
165
+ for (const relativePath of matches) {
166
+ const absolutePath = `${workspaceRealPath}${sep}${relativePath.split("/").join(sep)}`;
167
+ let candidateRealPath;
168
+ try {
169
+ candidateRealPath = await realpath(absolutePath);
170
+ }
171
+ catch {
172
+ fail("FILE_NOT_FOUND", "添付fileを解決できませんでした。");
173
+ }
174
+ if (!isInsideRoot(workspaceRealPath, candidateRealPath)) {
175
+ fail("FILE_OUTSIDE_ROOT", "添付fileはworkspaceRoot外を参照できません。");
176
+ }
177
+ if (seenRealPaths.has(candidateRealPath))
178
+ continue;
179
+ let initialPathStat;
180
+ try {
181
+ initialPathStat = await stat(candidateRealPath);
182
+ }
183
+ catch (error) {
184
+ if (error instanceof ConnectorError)
185
+ throw error;
186
+ fail("FILE_NOT_FOUND", "添付fileを読み取れませんでした。");
187
+ }
188
+ if (!initialPathStat.isFile()) {
189
+ fail("FILE_TYPE_NOT_SUPPORTED", "添付対象はregular fileである必要があります。");
190
+ }
191
+ const canonicalRelativePath = normalizedRelativePath(relative(workspaceRealPath, candidateRealPath));
192
+ if (isSensitive(relativePath) || isSensitive(canonicalRelativePath)) {
193
+ fail("SENSITIVE_FILE_BLOCKED", "秘密情報を含む可能性があるfileは添付できません。");
194
+ }
195
+ if (initialPathStat.size === 0) {
196
+ fail("FILE_EMPTY", "空のfileは添付できません。");
197
+ }
198
+ if (initialPathStat.size > attachmentLimits.maxFileBytes) {
199
+ fail("FILE_LIMIT_EXCEEDED", "添付fileは20MiB以下にしてください。");
200
+ }
201
+ let content;
202
+ try {
203
+ const handle = await open(candidateRealPath, constants.O_RDONLY | constants.O_NOFOLLOW);
204
+ try {
205
+ const descriptorStat = await handle.stat();
206
+ const resolvedAfterOpen = await realpath(absolutePath);
207
+ if (!isInsideRoot(workspaceRealPath, resolvedAfterOpen)) {
208
+ fail("FILE_OUTSIDE_ROOT", "添付fileはworkspaceRoot外を参照できません。");
209
+ }
210
+ const finalPathStat = await stat(resolvedAfterOpen);
211
+ if (!descriptorStat.isFile() || !sameFileIdentity(descriptorStat, finalPathStat) ||
212
+ !sameFileIdentity(descriptorStat, initialPathStat)) {
213
+ fail("FILE_OUTSIDE_ROOT", "添付fileの解決中にpathが変更されました。");
214
+ }
215
+ content = new Uint8Array(await handle.readFile());
216
+ }
217
+ finally {
218
+ await handle.close();
219
+ }
220
+ }
221
+ catch (error) {
222
+ if (error instanceof ConnectorError)
223
+ throw error;
224
+ fail("FILE_NOT_FOUND", "添付fileを読み取れませんでした。");
225
+ }
226
+ try {
227
+ if (content.byteLength === 0) {
228
+ fail("FILE_EMPTY", "空のfileは添付できません。");
229
+ }
230
+ if (content.byteLength > attachmentLimits.maxFileBytes) {
231
+ fail("FILE_LIMIT_EXCEEDED", "添付fileは20MiB以下にしてください。");
232
+ }
233
+ if (totalBytes + content.byteLength > attachmentLimits.maxTotalBytes) {
234
+ fail("FILE_LIMIT_EXCEEDED", "添付file合計は64MiB以下にしてください。");
235
+ }
236
+ const metadata = metadataOf(relativePath, content);
237
+ files.push({ ...metadata, content });
238
+ totalBytes += content.byteLength;
239
+ seenRealPaths.add(candidateRealPath);
240
+ }
241
+ catch (error) {
242
+ content.fill(0);
243
+ throw error;
244
+ }
245
+ }
246
+ }
247
+ return { files, totalBytes };
248
+ }
249
+ catch (error) {
250
+ zeroPreparedContents(files);
251
+ throw error;
252
+ }
253
+ }
254
+ export async function resolveAttachmentFiles(input) {
255
+ const prepared = await prepareAttachmentFiles(input);
256
+ try {
257
+ return {
258
+ files: prepared.files.map((file) => ({
259
+ relativePath: file.relativePath,
260
+ name: file.name,
261
+ bytes: file.bytes,
262
+ mimeType: file.mimeType,
263
+ sha256: file.sha256,
264
+ })),
265
+ totalBytes: prepared.totalBytes,
266
+ };
267
+ }
268
+ finally {
269
+ zeroPreparedContents(prepared.files);
270
+ }
271
+ }
272
+ //# sourceMappingURL=attachment-files.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attachment-files.js","sourceRoot":"","sources":["../../src/attachment-files.ts"],"names":[],"mappings":"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"}