- หน้าแรก
- Documentation
- ส่วนขยาย
- ตัวจัดการปลั๊กอินและการติดตั้งภายใน
ตัวจัดการปลั๊กอินและการติดตั้งภายใน
เอกสารนี้อธิบายว่าการทำงานของ xcsh plugin เปลี่ยนแปลงสถานะปลั๊กอินบนดิสก์อย่างไร และปลั๊กอินที่ติดตั้งแล้วกลายเป็นความสามารถขณะรันไทม์ได้อย่างไร (ปัจจุบันเป็นเครื่องมือ รวมถึงการแก้ไขเส้นทาง hooks/commands ที่พร้อมใช้งาน)
ขอบเขตและสถาปัตยกรรม
หัวข้อที่มีชื่อว่า “ขอบเขตและสถาปัตยกรรม”มีการนำไปใช้งานของการจัดการปลั๊กอินสองแบบในโค้ดเบส:
- เส้นทางที่ใช้งานโดยคำสั่ง CLI:
PluginManager(src/extensibility/plugins/manager.ts) - โมดูลช่วยเหลือรุ่นเก่า: ฟังก์ชัน installer (
src/extensibility/plugins/installer.ts)
การเรียกใช้คำสั่ง xcsh plugin ... ผ่าน PluginManager
installer.ts ยังคงบันทึกการตรวจสอบความปลอดภัยที่สำคัญและพฤติกรรมของระบบไฟล์ แต่ไม่ใช่เส้นทางที่ใช้โดย src/commands/plugin.ts + src/cli/plugin-cli.ts
วงจรชีวิต: จากการเรียกใช้ CLI ไปสู่ความพร้อมใช้งานขณะรันไทม์
หัวข้อที่มีชื่อว่า “วงจรชีวิต: จากการเรียกใช้ CLI ไปสู่ความพร้อมใช้งานขณะรันไทม์”xcsh plugin <action> ... -> src/commands/plugin.ts -> runPluginCommand(...) in src/cli/plugin-cli.ts -> PluginManager method (install/list/uninstall/link/...) -> mutate ~/.xcsh/plugins/{package.json,node_modules,xcsh-plugins.lock.json} -> runtime discovery: discoverAndLoadCustomTools(...) -> getAllPluginToolPaths(cwd) -> custom tool loader imports tool modulesจุดเข้าของคำสั่ง
หัวข้อที่มีชื่อว่า “จุดเข้าของคำสั่ง”src/commands/plugin.tsกำหนดคำสั่ง/แฟล็ก และส่งต่อไปยังrunPluginCommandsrc/cli/plugin-cli.tsแมปคำสั่งย่อยไปยังเมธอดของPluginManager:install,uninstall,list,link,doctor,features,config,enable,disable
- ไม่มีการกระทำ
updateอย่างชัดเจน การอัปเดตทำโดยการรันinstallซ้ำด้วยสเปคแพ็กเกจ/เวอร์ชันใหม่
รูปแบบข้อมูลบนดิสก์
หัวข้อที่มีชื่อว่า “รูปแบบข้อมูลบนดิสก์”สถานะปลั๊กอินส่วนกลางอยู่ภายใต้ ~/.xcsh/plugins:
package.json— ไฟล์ manifest ของการพึ่งพาที่ใช้โดยbun install/bun uninstallnode_modules/— แพ็กเกจปลั๊กอินที่ติดตั้งแล้วหรือ symlinksxcsh-plugins.lock.json— สถานะขณะรันไทม์:- เปิด/ปิดใช้งานต่อปลั๊กอิน
- ชุดฟีเจอร์ที่เลือกต่อปลั๊กอิน
- การตั้งค่าปลั๊กอินที่บันทึกไว้
การแทนที่ระดับโปรเจกต์อยู่ที่:
<cwd>/.xcsh/plugin-overrides.json
การแทนที่เป็นแบบอ่านอย่างเดียวจากมุมมองของ manager/loader (ไม่มีเส้นทางการเขียนที่นี่) และสามารถปิดใช้งานปลั๊กอินหรือแทนที่ฟีเจอร์/การตั้งค่าสำหรับโปรเจกต์นี้
การแยกวิเคราะห์สเปคปลั๊กอินและการตีความ metadata
หัวข้อที่มีชื่อว่า “การแยกวิเคราะห์สเปคปลั๊กอินและการตีความ metadata”ไวยากรณ์สเปคการติดตั้ง
หัวข้อที่มีชื่อว่า “ไวยากรณ์สเปคการติดตั้ง”parsePluginSpec (parser.ts) รองรับ:
pkg->features: null(พฤติกรรมค่าเริ่มต้น)pkg[*]-> เปิดใช้งานทุกฟีเจอร์ใน manifestpkg[]-> ไม่เปิดใช้งานฟีเจอร์เสริมpkg[a,b]-> เปิดใช้งานฟีเจอร์ที่ระบุชื่อ@scope/pkg@1.2.3[feat]-> แพ็กเกจแบบมีขอบเขต + มีเวอร์ชัน พร้อมการเลือกฟีเจอร์อย่างชัดเจน
extractPackageName ตัดส่วนต่อท้ายเวอร์ชันออกสำหรับการค้นหาเส้นทางบนดิสก์หลังการติดตั้ง
แหล่งที่มาของ manifest และฟิลด์ที่จำเป็น
หัวข้อที่มีชื่อว่า “แหล่งที่มาของ manifest และฟิลด์ที่จำเป็น”Manifest ถูกแก้ไขดังนี้:
package.json.xcsh- ทางเลือกสำรอง
package.json.pi - ทางเลือกสำรอง
{ version: package.version }
ผลกระทบ:
- ไม่มีการตรวจสอบ schema อย่างเข้มงวดใน manager/loader
- แพ็กเกจที่ขาด manifest
xcsh/piยังคงสามารถติดตั้งและแสดงรายการได้ - การโหลดปลั๊กอินขณะรันไทม์ (
getEnabledPlugins) ข้ามแพ็กเกจที่ไม่มี manifestxcsh/pi manifest.versionถูกเขียนทับเสมอจากversionของแพ็กเกจ
JSON ของ package.json ที่มีรูปแบบผิดพลาดเป็นความล้มเหลวร้ายแรงในขณะอ่าน รูปร่าง manifest ที่มีรูปแบบผิดพลาดอาจล้มเหลวในภายหลังเมื่อมีการใช้งานฟิลด์เฉพาะ
กระบวนการติดตั้ง/อัปเดต (PluginManager.install)
หัวข้อที่มีชื่อว่า “กระบวนการติดตั้ง/อัปเดต (PluginManager.install)”- แยกวิเคราะห์ไวยากรณ์วงเล็บฟีเจอร์จากสเปคการติดตั้ง
- ตรวจสอบชื่อแพ็กเกจกับ regex + รายการที่ปฏิเสธอักขระพิเศษของ shell
- ตรวจสอบให้แน่ใจว่า
package.jsonของปลั๊กอินมีอยู่ (xcsh-plugins, แผนที่การพึ่งพาส่วนตัว) - รัน
bun install <packageSpec>ใน~/.xcsh/plugins - อ่าน
node_modules/<name>/package.jsonของแพ็กเกจที่ติดตั้ง - แก้ไข manifest และคำนวณ
enabledFeatures:[*]: ทุกฟีเจอร์ที่ประกาศ (หรือnullถ้าไม่มีแผนที่ฟีเจอร์)[a,b]: ตรวจสอบว่าแต่ละฟีเจอร์มีอยู่ในแผนที่ฟีเจอร์ manifest[]: รายการฟีเจอร์ว่าง- สเปคเปล่า:
null(ใช้นโยบายค่าเริ่มต้นในภายหลังใน loader)
- อัปเดต upsert สถานะขณะรันไทม์ใน lockfile:
{ version, enabledFeatures, enabled: true }
ความหมายของการอัปเดต
หัวข้อที่มีชื่อว่า “ความหมายของการอัปเดต”เนื่องจากการอัปเดตขับเคลื่อนโดย install:
xcsh plugin install pkg@newVersionอัปเดตการพึ่งพาและเวอร์ชันใน lockfile- การตั้งค่าที่มีอยู่ถูกเก็บรักษาไว้ รายการสถานะถูกเขียนทับสำหรับเวอร์ชัน/ฟีเจอร์/การเปิดใช้งาน
- ไม่มีตรรกะ “ตรวจสอบการอัปเดต” แยกต่างหากหรือการย้ายข้อมูลแบบทรานแซกชัน
กระบวนการลบ (PluginManager.uninstall)
หัวข้อที่มีชื่อว่า “กระบวนการลบ (PluginManager.uninstall)”- ตรวจสอบชื่อแพ็กเกจ
- รัน
bun uninstall <name>ในไดเรกทอรีปลั๊กอิน - ลบสถานะขณะรันไทม์ของปลั๊กอินออกจาก lockfile:
config.plugins[name]config.settings[name]
หากคำสั่ง uninstall ล้มเหลว สถานะขณะรันไทม์จะไม่เปลี่ยนแปลง
กระบวนการแสดงรายการ (PluginManager.list)
หัวข้อที่มีชื่อว่า “กระบวนการแสดงรายการ (PluginManager.list)”- อ่านแผนที่การพึ่งพาปลั๊กอินจาก
~/.xcsh/plugins/package.json - โหลดการกำหนดค่าขณะรันไทม์ใน lockfile (ไฟล์หายไป -> ค่าเริ่มต้นว่าง)
- โหลดการแทนที่ของโปรเจกต์ (
<cwd>/.xcsh/plugin-overrides.json, ข้อผิดพลาดในการแยกวิเคราะห์/อ่าน -> วัตถุว่างพร้อมคำเตือน) - สำหรับแต่ละการพึ่งพาที่มี package.json ที่แก้ไขได้:
- สร้างบันทึก
InstalledPlugin - รวมสถานะฟีเจอร์/การเปิดใช้งาน:
- ฐานจาก lockfile (หรือค่าเริ่มต้น)
- การแทนที่ของโปรเจกต์สามารถแทนที่การเลือกฟีเจอร์ได้
- รายการ
disabledของโปรเจกต์ทำให้ปลั๊กอินถูกมาสก์ว่าปิดใช้งาน
- สร้างบันทึก
นี่คือสถานะที่มีผลซึ่งใช้โดยเอาต์พุตสถานะ CLI และการทำงานของ settings/features
กระบวนการเชื่อมโยง (PluginManager.link)
หัวข้อที่มีชื่อว่า “กระบวนการเชื่อมโยง (PluginManager.link)”link รองรับการพัฒนาปลั๊กอินในเครื่องโดยการสร้าง symlink ของแพ็กเกจในเครื่องไปยัง ~/.xcsh/plugins/node_modules/<pkg.name>
พฤติกรรม:
- แก้ไข
localPathกับ cwd ของ manager - ต้องการ
package.jsonในเครื่องและฟิลด์name - ตรวจสอบให้แน่ใจว่าไดเรกทอรีปลั๊กอินมีอยู่
- สำหรับชื่อแบบมีขอบเขต สร้างไดเรกทอรีขอบเขต
- ลบเส้นทางที่มีอยู่ที่ตำแหน่ง link เป้าหมาย
- สร้าง symlink
- เพิ่มรายการใน lockfile ขณะรันไทม์โดยเปิดใช้งานพร้อมฟีเจอร์เริ่มต้น (
null)
ข้อควรระวัง: PluginManager.link ปัจจุบันไม่บังคับใช้การตรวจสอบขอบเขตเส้นทาง cwd ที่มีอยู่ใน installer.ts รุ่นเก่า (normalizedPath.startsWith(normalizedCwd)) ดังนั้นความน่าเชื่อถือจึงเป็นความรับผิดชอบของผู้เรียกใช้
การโหลดขณะรันไทม์: จากปลั๊กอินที่ติดตั้งแล้วไปสู่ความสามารถที่เรียกได้
หัวข้อที่มีชื่อว่า “การโหลดขณะรันไทม์: จากปลั๊กอินที่ติดตั้งแล้วไปสู่ความสามารถที่เรียกได้”ประตูการค้นพบ
หัวข้อที่มีชื่อว่า “ประตูการค้นพบ”getEnabledPlugins(cwd) (plugins/loader.ts) อ่าน:
- manifest การพึ่งพาปลั๊กอิน (
package.json) - สถานะขณะรันไทม์ใน lockfile
- การแทนที่ของโปรเจกต์ผ่าน
getConfigDirPaths("plugin-overrides.json", { user: false, cwd })
การกรอง:
- ข้ามถ้าไม่มี package.json ของปลั๊กอิน
- ข้ามถ้าไม่มี manifest (
xcsh/pi) - ข้ามถ้าปิดใช้งานส่วนกลางใน lockfile
- ข้ามถ้าโปรเจกต์ปิดใช้งาน
การแก้ไขเส้นทางความสามารถ
หัวข้อที่มีชื่อว่า “การแก้ไขเส้นทางความสามารถ”สำหรับแต่ละปลั๊กอินที่เปิดใช้งาน:
resolvePluginToolPaths(plugin)resolvePluginHookPaths(plugin)resolvePluginCommandPaths(plugin)
ตัวแก้ไขแต่ละตัวรวมรายการฐานบวกรายการฟีเจอร์:
- รายการฟีเจอร์ที่ชัดเจน -> เฉพาะฟีเจอร์ที่เลือก
enabledFeatures === null-> เปิดใช้งานฟีเจอร์ที่ทำเครื่องหมายdefault: true
ไฟล์ที่หายไปจะถูกข้ามอย่างเงียบๆ (การตรวจสอบด้วย existsSync)
ความแตกต่างในการเดินสายขณะรันไทม์ปัจจุบัน
หัวข้อที่มีชื่อว่า “ความแตกต่างในการเดินสายขณะรันไทม์ปัจจุบัน”- เครื่องมือถูกเดินสายเข้าสู่รันไทม์ในปัจจุบัน ผ่าน
discoverAndLoadCustomTools(custom-tools/loader.ts) ซึ่งเรียกgetAllPluginToolPaths(cwd) - เส้นทางถูกลบข้อมูลซ้ำโดยเส้นทางสัมบูรณ์ที่แก้ไขแล้วในการค้นพบเครื่องมือที่กำหนดเอง (ชุด
seen, เส้นทางแรกชนะ) - ตัวแก้ไข Hooks/commands มีอยู่ และถูก export แล้ว แต่เส้นทางโค้ดนี้ปัจจุบันยังไม่ได้เดินสายเข้าสู่ registry ขณะรันไทม์ในลักษณะเดียวกับที่เครื่องมือถูกเดินสาย
รายละเอียดการจัดการ Lock/สถานะ
หัวข้อที่มีชื่อว่า “รายละเอียดการจัดการ Lock/สถานะ”PluginManager แคชการกำหนดค่าขณะรันไทม์ในหน่วยความจำต่อ instance (#runtimeConfig) และโหลดแบบ lazy ครั้งเดียว
พฤติกรรมการโหลด:
- lockfile หายไป ->
{ plugins: {}, settings: {} } - ความล้มเหลวในการอ่าน/แยกวิเคราะห์ lockfile -> คำเตือน + ค่าเริ่มต้นว่างเช่นกัน
พฤติกรรมการบันทึก:
- เขียน JSON ของ lockfile แบบ pretty-printed เต็มรูปแบบในแต่ละการเปลี่ยนแปลง
ไม่มีการล็อคข้ามกระบวนการหรือกลยุทธ์การรวมที่มีอยู่ การเขียนพร้อมกันสามารถเขียนทับซึ่งกันและกันได้
การตรวจสอบความปลอดภัยและขอบเขตความน่าเชื่อถือ
หัวข้อที่มีชื่อว่า “การตรวจสอบความปลอดภัยและขอบเขตความน่าเชื่อถือ”การตรวจสอบ input/แพ็กเกจ
หัวข้อที่มีชื่อว่า “การตรวจสอบ input/แพ็กเกจ”เส้นทาง manager ที่ใช้งานบังคับใช้การตรวจสอบชื่อแพ็กเกจ:
- regex สำหรับสเปคแพ็กเกจแบบมีขอบเขต/ไม่มีขอบเขต (พร้อมเวอร์ชันตามต้องการ)
- รายการที่ปฏิเสธอักขระพิเศษ shell อย่างชัดเจน (
[;&|$(){}[]<>\]`)
สิ่งนี้จำกัดความเสี่ยงการ inject คำสั่งเมื่อเรียกใช้ bun install/uninstall
ขอบเขตความน่าเชื่อถือของระบบไฟล์
หัวข้อที่มีชื่อว่า “ขอบเขตความน่าเชื่อถือของระบบไฟล์”- โค้ดปลั๊กอินทำงานใน process เมื่อโมดูลเครื่องมือที่กำหนดเองถูก import ไม่มี sandboxing
- เส้นทางสัมพัทธ์ของ manifest ถูกรวมกับไดเรกทอรีแพ็กเกจปลั๊กอินและตรวจสอบเฉพาะการมีอยู่
- แพ็กเกจปลั๊กอินเองเป็นโค้ดที่น่าเชื่อถือเมื่อติดตั้งแล้ว
การตรวจสอบเฉพาะ installer รุ่นเก่า
หัวข้อที่มีชื่อว่า “การตรวจสอบเฉพาะ installer รุ่นเก่า”installer.ts รวมการตรวจสอบเพิ่มเติมในขณะ link ที่ไม่ได้สะท้อนใน PluginManager.link:
- เส้นทางในเครื่องต้องแก้ไขภายใน cwd ของโปรเจกต์
- การตรวจสอบชื่อแพ็กเกจ/การข้ามผ่านเส้นทางเพิ่มเติมสำหรับการตั้งชื่อ target ของ symlink
เนื่องจาก CLI ใช้ PluginManager การตรวจสอบ link ที่เข้มงวดกว่าเหล่านี้จึงไม่ได้อยู่บนเส้นทางหลักในปัจจุบัน
พฤติกรรมความล้มเหลว ความสำเร็จบางส่วน และการย้อนกลับ
หัวข้อที่มีชื่อว่า “พฤติกรรมความล้มเหลว ความสำเร็จบางส่วน และการย้อนกลับ”ตัวจัดการปลั๊กอินไม่ใช่แบบทรานแซกชัน
| ขั้นตอนการทำงาน | พฤติกรรมเมื่อล้มเหลว | การย้อนกลับ |
|---|---|---|
bun install ล้มเหลว | การติดตั้งยกเลิกพร้อม stderr | ไม่มี (ยังไม่มีการเขียนสถานะ) |
| ติดตั้งสำเร็จ จากนั้นการตรวจสอบ manifest/ฟีเจอร์ล้มเหลว | คำสั่งล้มเหลว | ไม่มีการย้อนกลับการ uninstall การพึ่งพาอาจยังคงอยู่ใน node_modules/package.json |
| ติดตั้งสำเร็จ จากนั้นการเขียน lockfile ล้มเหลว | คำสั่งล้มเหลว | ไม่มีการย้อนกลับของแพ็กเกจที่ติดตั้ง |
bun uninstall สำเร็จ การเขียน lockfile ล้มเหลว | คำสั่งล้มเหลว | แพ็กเกจถูกลบ สถานะขณะรันไทม์ที่ค้างอยู่อาจยังคงอยู่ |
link ลบ target เก่าแล้ว การสร้าง symlink ล้มเหลว | คำสั่งล้มเหลว | ไม่มีการกู้คืน link/ไดเรกทอรีก่อนหน้า |
ในทางปฏิบัติ doctor --fix สามารถซ่อมแซมความเบี่ยงเบนบางส่วนได้ (bun install, การล้างค่า config ที่ไม่มีเจ้าของ, การล้างฟีเจอร์ที่ไม่ถูกต้อง) แต่เป็นแบบ best-effort
สรุปพฤติกรรมเมื่อ manifest มีรูปแบบผิดพลาดหรือขาดหายไป
หัวข้อที่มีชื่อว่า “สรุปพฤติกรรมเมื่อ manifest มีรูปแบบผิดพลาดหรือขาดหายไป”- ฟิลด์
xcsh/piหายไป:- ติดตั้ง/แสดงรายการ: ยอมรับได้ (manifest ขั้นต่ำ)
- การค้นพบปลั๊กอินที่เปิดใช้งานขณะรันไทม์: ถูกข้ามในฐานะที่ไม่ใช่ปลั๊กอิน
- ฟีเจอร์ที่ขาดหายไปซึ่งอ้างถึงโดยสเปคการติดตั้งหรือ
features --set/--enable: ข้อผิดพลาดร้ายแรงพร้อมรายการฟีเจอร์ที่มีอยู่ plugin-overrides.jsonที่ไม่ถูกต้อง: ถูกละเว้นพร้อมการใช้{}สำรองในทั้ง manager และ loader paths- เส้นทางไฟล์ tool/hook/command ที่ขาดหายไปซึ่งอ้างถึงโดย manifest: ถูกละเว้นอย่างเงียบๆ ในระหว่างการขยาย resolver ถูกระบุเป็นข้อผิดพลาดเฉพาะโดย
doctor
ความแตกต่างของโหมดและลำดับความสำคัญ
หัวข้อที่มีชื่อว่า “ความแตกต่างของโหมดและลำดับความสำคัญ”--dry-run(install): ส่งคืนผลลัพธ์การติดตั้งสังเคราะห์ ไม่มีการเขียนระบบไฟล์/เครือข่าย/สถานะ--json: การจัดรูปแบบเอาต์พุตเท่านั้น ไม่มีการเปลี่ยนแปลงพฤติกรรม- การแทนที่ของโปรเจกต์มีลำดับความสำคัญเหนือ lockfile ส่วนกลางเสมอสำหรับมุมมอง feature/settings
- การเปิดใช้งานที่มีผลคือ
runtimeEnabled && !projectDisabled
ไฟล์การนำไปใช้งาน
หัวข้อที่มีชื่อว่า “ไฟล์การนำไปใช้งาน”src/commands/plugin.ts— การประกาศคำสั่ง CLI และการแมปแฟล็กsrc/cli/plugin-cli.ts— การส่งคำสั่ง, handler คำสั่งสำหรับผู้ใช้src/extensibility/plugins/manager.ts— การนำไปใช้งาน install/remove/list/link/state/doctor ที่ใช้งานsrc/extensibility/plugins/installer.ts— helper ของ installer รุ่นเก่าและการตรวจสอบความปลอดภัย link เพิ่มเติมsrc/extensibility/plugins/loader.ts— การค้นพบปลั๊กอินที่เปิดใช้งานและการแก้ไขเส้นทาง tool/hook/commandsrc/extensibility/plugins/parser.ts— helper การแยกวิเคราะห์สเปคการติดตั้งและชื่อแพ็กเกจsrc/extensibility/plugins/types.ts— สัญญาประเภท manifest/runtime/overridesrc/extensibility/custom-tools/loader.ts— การเดินสายขณะรันไทม์สำหรับโมดูลเครื่องมือที่จัดหาโดยปลั๊กอิน