- หน้าแรก
- Documentation
- ส่วนขยาย
- การโหลดส่วนขยาย (โมดูล TypeScript/JavaScript)
การโหลดส่วนขยาย (โมดูล TypeScript/JavaScript)
เอกสารนี้ครอบคลุมวิธีที่ตัวแทนการเขียนโค้ดค้นพบและโหลดโมดูลส่วนขยาย (.ts/.js) เมื่อเริ่มต้นทำงาน
เอกสารนี้ไม่ครอบคลุมส่วนขยายไฟล์ manifest gemini-extension.json (มีเอกสารแยกต่างหาก)
หน้าที่ของระบบย่อยนี้
หัวข้อที่มีชื่อว่า “หน้าที่ของระบบย่อยนี้”การโหลดส่วนขยายจะสร้างรายการไฟล์ entry ของโมดูล นำเข้าแต่ละโมดูลด้วย Bun รันฟังก์ชัน factory และส่งคืน:
- คำจำกัดความส่วนขยายที่โหลดแล้ว
- ข้อผิดพลาดการโหลดต่อพาธ (โดยไม่หยุดการโหลดทั้งหมด)
- อ็อบเจกต์ runtime ของส่วนขยายที่ใช้ร่วมกัน ซึ่ง
ExtensionRunnerจะใช้ในภายหลัง
ไฟล์ implementation หลัก
หัวข้อที่มีชื่อว่า “ไฟล์ implementation หลัก”src/extensibility/extensions/loader.ts— การค้นพบพาธ + การนำเข้า/การรันsrc/extensibility/extensions/index.ts— การส่งออกสาธารณะsrc/extensibility/extensions/runner.ts— การรัน runtime/event หลังการโหลดsrc/discovery/builtin.ts— ผู้ให้บริการค้นพบอัตโนมัติแบบ native สำหรับโมดูลส่วนขยายsrc/config/settings.ts— โหลดการตั้งค่าextensions/disabledExtensionsที่ผสานแล้ว
ข้อมูลนำเข้าสำหรับการโหลดส่วนขยาย
หัวข้อที่มีชื่อว่า “ข้อมูลนำเข้าสำหรับการโหลดส่วนขยาย”1) โมดูลส่วนขยาย native ที่ค้นพบอัตโนมัติ
หัวข้อที่มีชื่อว่า “1) โมดูลส่วนขยาย native ที่ค้นพบอัตโนมัติ”discoverAndLoadExtensions() จะสอบถามผู้ให้บริการค้นพบก่อนสำหรับรายการที่มีความสามารถ extension-module จากนั้นเก็บเฉพาะรายการที่เป็น provider native
ตำแหน่ง native ที่มีผล:
- โปรเจกต์:
<cwd>/.xcsh/extensions - ผู้ใช้:
~/.xcsh/agent/extensions
รูทของพาธมาจาก native provider (SOURCE_PATHS.native)
หมายเหตุ:
- การค้นพบอัตโนมัติแบบ native ใช้
.xcshเป็นฐาน - Legacy
.piยังคงรองรับในคีย์ manifest ของpackage.json(pi.extensions) แต่ไม่ใช่ในฐานะ native root ที่นี่
2) พาธที่กำหนดค่าไว้อย่างชัดเจน
หัวข้อที่มีชื่อว่า “2) พาธที่กำหนดค่าไว้อย่างชัดเจน”หลังการค้นพบอัตโนมัติ พาธที่กำหนดค่าไว้จะถูกผนวกและแก้ไข
แหล่งพาธที่กำหนดค่าไว้ในพาธเริ่มต้น session หลัก (sdk.ts):
- พาธที่ระบุผ่าน CLI (
--extension/-eและ--hookจะถูกถือว่าเป็นพาธส่วนขยายด้วย) - อาร์เรย์
extensionsของการตั้งค่า (การตั้งค่าส่วนกลาง + โปรเจกต์ที่ผสานแล้ว)
ไฟล์การตั้งค่าส่วนกลาง:
~/.xcsh/agent/config.yml(หรือไดเรกทอรี agent แบบกำหนดเองผ่านPI_CODING_AGENT_DIR)
ไฟล์การตั้งค่าโปรเจกต์:
<cwd>/.xcsh/settings.json
ตัวอย่าง:
extensions: - ~/my-exts/safety.ts - ./local/ext-pack{ "extensions": ["./.xcsh/extensions/my-extra"]}ตัวควบคุมการเปิดใช้งาน/ปิดใช้งาน
หัวข้อที่มีชื่อว่า “ตัวควบคุมการเปิดใช้งาน/ปิดใช้งาน”ปิดใช้งานการค้นพบ
หัวข้อที่มีชื่อว่า “ปิดใช้งานการค้นพบ”- CLI:
--no-extensions - ตัวเลือก SDK:
disableExtensionDiscovery
การแบ่งพฤติกรรม:
- SDK: เมื่อ
disableExtensionDiscovery=trueยังคงโหลดadditionalExtensionPathsผ่านloadExtensions() - การสร้างพาธของ CLI (
main.ts) จะล้างพาธส่วนขยาย CLI เมื่อตั้งค่า--no-extensionsดังนั้น-e/--hookอย่างชัดเจนจะไม่ถูกส่งต่อในโหมดนั้น
ปิดใช้งานโมดูลส่วนขยายเฉพาะ
หัวข้อที่มีชื่อว่า “ปิดใช้งานโมดูลส่วนขยายเฉพาะ”การตั้งค่า disabledExtensions กรองตามรูปแบบ extension id:
extension-module:<derivedName>
derivedName อ้างอิงจากพาธ entry (getExtensionNameFromPath) ตัวอย่างเช่น:
/x/foo.ts->foo/x/bar/index.ts->bar
ตัวอย่าง:
disabledExtensions: - extension-module:fooการแก้ไขพาธและ entry
หัวข้อที่มีชื่อว่า “การแก้ไขพาธและ entry”การทำให้พาธเป็นมาตรฐาน
หัวข้อที่มีชื่อว่า “การทำให้พาธเป็นมาตรฐาน”สำหรับพาธที่กำหนดค่าไว้:
- ทำให้ unicode spaces เป็นมาตรฐาน
- ขยาย
~ - หากเป็นพาธสัมพัทธ์ ให้แก้ไขเทียบกับ
cwdปัจจุบัน
หากพาธที่กำหนดค่าไว้เป็นไฟล์
หัวข้อที่มีชื่อว่า “หากพาธที่กำหนดค่าไว้เป็นไฟล์”จะถูกใช้โดยตรงเป็นตัวเลือก module entry
หากพาธที่กำหนดค่าไว้เป็นไดเรกทอรี
หัวข้อที่มีชื่อว่า “หากพาธที่กำหนดค่าไว้เป็นไดเรกทอรี”ลำดับการแก้ไข:
package.jsonในไดเรกทอรีนั้นที่มีxcsh.extensions(หรือ legacypi.extensions) -> ใช้ entries ที่ประกาศไว้index.tsindex.js- มิฉะนั้นสแกนหนึ่งระดับเพื่อหา extension entries:
*.ts/*.jsโดยตรงindex.ts/index.jsใน subdirpackage.jsonใน subdir ที่มีxcsh.extensions/pi.extensions
กฎและข้อจำกัด:
- ไม่มีการค้นพบแบบ recursive เกินหนึ่งระดับ subdirectory
- entries ที่ประกาศไว้ใน manifest
extensionsจะถูกแก้ไขเทียบกับไดเรกทอรีแพ็กเกจนั้น - entries ที่ประกาศไว้จะถูกรวมเฉพาะเมื่อไฟล์มีอยู่/อนุญาตให้เข้าถึงได้
- ในคู่
*/index.{ts,js}TypeScript จะถูกเลือกมากกว่า JavaScript - symlinks ถูกถือว่าเป็นไฟล์/ไดเรกทอรีที่ใช้ได้
พฤติกรรมการละเว้นแตกต่างกันตามแหล่งที่มา
หัวข้อที่มีชื่อว่า “พฤติกรรมการละเว้นแตกต่างกันตามแหล่งที่มา”- การค้นพบอัตโนมัติแบบ native (
discoverExtensionModulePathsใน discovery helpers) ใช้ native glob ที่มีgitignore: trueและhidden: false - การสแกนไดเรกทอรีที่กำหนดค่าไว้อย่างชัดเจนใน
loader.tsใช้กฎreaddirและไม่ใช้การกรอง gitignore
ลำดับการโหลดและลำดับความสำคัญ
หัวข้อที่มีชื่อว่า “ลำดับการโหลดและลำดับความสำคัญ”discoverAndLoadExtensions() สร้างรายการลำดับเดียวแล้วเรียก loadExtensions()
ลำดับ:
- โมดูลที่ค้นพบอัตโนมัติแบบ native
- พาธที่กำหนดค่าไว้อย่างชัดเจน (ตามลำดับที่ระบุ)
ใน sdk.ts ลำดับที่กำหนดค่าไว้คือ:
- พาธเพิ่มเติมจาก CLI
extensionsของการตั้งค่า
การขจัดข้อมูลซ้ำ:
- อ้างอิงจากพาธสัมบูรณ์
- พาธที่พบก่อนจะชนะ
- รายการซ้ำที่ตามมาจะถูกละเว้น
ผลที่ตามมา: หากโมดูลพาธเดียวกันถูกค้นพบอัตโนมัติและกำหนดค่าไว้อย่างชัดเจน จะถูกโหลดครั้งเดียวที่ตำแหน่งแรก (ขั้นตอนการค้นพบอัตโนมัติ)
การนำเข้าโมดูลและข้อกำหนด factory
หัวข้อที่มีชื่อว่า “การนำเข้าโมดูลและข้อกำหนด factory”แต่ละพาธที่เป็นตัวเลือกจะถูกโหลดด้วย dynamic import:
await import(resolvedPath)- factory คือ
module.default ?? module - factory ต้องเป็นฟังก์ชัน (
ExtensionFactory)
หากการส่งออกไม่ใช่ฟังก์ชัน พาธนั้นจะล้มเหลวพร้อมข้อผิดพลาดที่มีโครงสร้าง และการโหลดจะดำเนินต่อไป
การจัดการความล้มเหลวและการแยกส่วน
หัวข้อที่มีชื่อว่า “การจัดการความล้มเหลวและการแยกส่วน”ระหว่างการโหลด
หัวข้อที่มีชื่อว่า “ระหว่างการโหลด”ต่อพาธส่วนขยาย ความล้มเหลวจะถูกจับเก็บเป็น { path, error } และไม่หยุดไม่ให้พาธอื่นโหลด
กรณีทั่วไป:
- การนำเข้าล้มเหลว / ไม่พบไฟล์
- การส่งออก factory ไม่ถูกต้อง (ไม่ใช่ฟังก์ชัน)
- ข้อยกเว้นที่เกิดขึ้นระหว่างการรัน factory
โมเดลการแยกส่วน runtime
หัวข้อที่มีชื่อว่า “โมเดลการแยกส่วน runtime”- ส่วนขยายไม่ถูก sandbox (กระบวนการ/runtime เดียวกัน)
- ส่วนขยายใช้
EventBusหนึ่งตัวและExtensionRuntimeinstance หนึ่งตัวร่วมกัน - ระหว่างการโหลด เมธอด action ของ runtime จะ throw
ExtensionRuntimeNotInitializedErrorโดยตั้งใจ โดย action wiring จะเกิดขึ้นในภายหลังในExtensionRunner.initialize()
หลังการโหลด
หัวข้อที่มีชื่อว่า “หลังการโหลด”เมื่อ events ทำงานผ่าน ExtensionRunner ข้อยกเว้นของ handler จะถูกจับและส่งออกเป็น extension errors แทนที่จะทำให้ runner loop พัง
ตัวอย่าง layout ผู้ใช้/โปรเจกต์ขั้นต่ำ
หัวข้อที่มีชื่อว่า “ตัวอย่าง layout ผู้ใช้/โปรเจกต์ขั้นต่ำ”ระดับผู้ใช้
หัวข้อที่มีชื่อว่า “ระดับผู้ใช้”~/.xcsh/agent/ config.yml extensions/ guardrails.ts audit/ index.tsระดับโปรเจกต์
หัวข้อที่มีชื่อว่า “ระดับโปรเจกต์”<repo>/ .xcsh/ settings.json extensions/ checks/ package.json lint-gates.tschecks/package.json:
{ "xcsh": { "extensions": ["./src/check-a.ts", "./src/check-b.js"] }}คีย์ manifest แบบ legacy ยังคงรองรับ:
{ "pi": { "extensions": ["./index.ts"] }}