Šķîþ ţö ḿàîñ çöñţéñţ

ŴÀŠḾ Éñĝîñé ÀƂÎ

Ţĥé ƃŕöŵšéŕ ƃüîļđ öƒ ķàþî (kapi/cmd/kapi-wasm-cli) ŕéĝîšţéŕš à šéţ öƒ ĝļöƃàļ ĴŠ ƒüñçţîöñš àţ ƃööţ. Ţĥàţ šéţ îš à ṽéŕšîöñéđ çöñţŕàçţ, ţĥé ÀƂÎ çöñšüḿéđ ƃý ţĥé @neokapi/engine ñþḿ þàçķàĝé (packages/engine), ŵĥîçĥ ŵŕàþš îţ îñ ţĥé ţýþéđ KapiRuntime ƒàçàđé.

Çöñţŕàçţ​

  • Šîñĝļé ŕéĝîšţŕàţîöñ þöîñţ. Éṽéŕý éñţŕý þöîñţ îš đéçļàŕéđ îñ ţĥé engineExports ţàƃļé îñ kapi/cmd/kapi-wasm-cli/main.go àñđ îñšţàļļéđ öñ globalThis ƒŕöḿ ţĥéŕé. Ñöţĥîñĝ éļšé ŕéĝîšţéŕš éñĝîñé ĝļöƃàļš.
  • Ƒéàţüŕé đéţéçţîöñ. kapiEngineABI() ŕéţüŕñš {abi, version, functions}: ţĥé ÀƂÎ ḿàĵöŕ ṽéŕšîöñ, ţĥé ķàþî ƃüîļđ ṽéŕšîöñ, àñđ ţĥé ļîšţ öƒ ŕéĝîšţéŕéđ ĝļöƃàļ ñàḿéš. À ƃüîļđ ŵîţĥöüţ kapiEngineABI þŕéđàţéš ţĥé đéšçŕîþţöŕ àñđ îš ţŕéàţéđ àš àƃî 0 (þŕöƃé îñđîṽîđüàļ ĝļöƃàļš).
  • Àđđîţîṽé ŵîţĥîñ à ṽéŕšîöñ. Ƒöŕ öñé abi ṽàļüé, çĥàñĝéš àŕé šţŕîçţļý àđđîţîṽé: ñéŵ ƒüñçţîöñš ḿàý àþþéàŕ îñ functions, ƃüţ éẋîšţîñĝ ñàḿéš, šîĝñàţüŕéš, àñđ þàýļöàđ šĥàþéš ñéṽéŕ çĥàñĝé öŕ đîšàþþéàŕ. Ŕéñàḿîñĝ öŕ ŕéḿöṽîñĝ àñ éñţŕý þöîñţ, öŕ çĥàñĝîñĝ à šîĝñàţüŕé îñçöḿþàţîƃļý, ƃüḿþš ţĥé ṽéŕšîöñ.
  • Ƃööţ ĥàñđšĥàķé. Ţĥé ĥöšţ îñšţàļļš îţš fs/process šĥîḿš (ţĥé wasm_exec.js éñṽîŕöñḿéñţ) àñđ ţĥé ŠǪĻîţé ƃŕîđĝé (__kapiSQL, šéé Šţöŕàĝé) ƃéƒöŕé îñšţàñţîàţîöñ; àƒţéŕ ŕéĝîšţéŕîñĝ ţĥé ĝļöƃàļš, ţĥé éñĝîñé îñṽöķéš ţĥé ĥöšţ'š __kapiCliReady() çàļļƃàçķ àñđ ţĥéñ ƃļöçķš ƒöŕéṽéŕ šö ţĥé ĝļöƃàļš šţàý çàļļàƃļé. Îñ à ƃŕöŵšéŕ ţĥé ĥöšţ îš ţĥé éñĝîñé'š Ŵöŕķéŕ (Ţĥé Ŵöŕķéŕ), šö ţĥé ĝļöƃàļš ļîṽé ţĥéŕé àñđ ţĥé ƒàçàđé ŕéàçĥéš ţĥéḿ ƃý ḿéššàĝé.
  • Ŕéṽéŕšé ƃŕîđĝéš. Šöḿé ƒéàţüŕéš çàļļ ƃàçķ îñţö öþţîöñàļ ĥöšţ-þŕöṽîđéđ ĝļöƃàļš: __kapiPdfium (ÞĐƑ ţéẋţ + ĝéöḿéţŕý), kapiLocalGenerate (öñ-đéṽîçé ĻĻḾ), kapiLocalNER (öñ-đéṽîçé ÑÉŔ), àñđ kapiBrowserTranslate (ŵîţĥ ţĥé þļàţƒöŕḿ Translator ÀÞÎ). Éàçĥ đéĝŕàđéš ŵîţĥ àñ àçţîöñàƃļé éŕŕöŕ ŵĥéñ îţš ƃŕîđĝé îš àƃšéñţ. Ţĥé ţýþéđ îñţéŕƒàçéš ļîṽé îñ packages/engine/src/capabilities.ts. À þàĝé îñšţàļļš ţĥéḿ öñ îţš öŵñ globalThis, àñđ ţĥé éñĝîñé ƒîñđš ţĥéḿ ţĥéŕé ƒŕöḿ ţĥé þàĝé öŕ ƒŕöḿ à Ŵöŕķéŕ.

Ţĥé Ŵöŕķéŕ​

bootKapiRuntime šţàŕţš ţĥé éñĝîñé îñ à đéđîçàţéđ Ŵöŕķéŕ (packages/engine/src/worker.ts) ŵĥéŕéṽéŕ Worker éẋîšţš: Ĝö, ŠǪĻîţé àñđ ţĥé éñĝîñé'š ƒîļé šýšţéḿ ŕüñ ţĥéŕé, öƒƒ ţĥé þàĝé'š ţĥŕéàđ. { worker: false }, öŕ àñ éñṽîŕöñḿéñţ ŵîţĥöüţ Worker (Ñöđé, à ţéšţ), ŕüñš îţ öñ ţĥé çàļļîñĝ ţĥŕéàđ àš ƃéƒöŕé, ŵîţĥ ţĥé ŵöŕķšþàçé îñ ḿéḿöŕý.

  • Çàļļš ƃý ḿéššàĝé. Ţĥé ƒàçàđé šéñđš éàçĥ çàļļ àš à ḿéššàĝé ñàḿîñĝ ţĥé éñĝîñé ĝļöƃàļ àñđ îţš àŕĝüḿéñţš (packages/engine/src/protocol.ts), àñđ ţĥé Ŵöŕķéŕ àñšŵéŕš ŵîţĥ ţĥé ṽàļüé. Çàļļš ţĥàţ àŕé ñöţ éñĝîñé ĝļöƃàļš (removeDatabase, reset, syncContext, àñđ ŕéàđîñĝ ƃàçķ à ţŕàçé) ŕüñ ƃéšîđé ţĥéḿ îñ ţĥé Ŵöŕķéŕ (packages/engine/src/local.ts). kbf, segment, segmentEngines àñđ removeDatabase àñšŵéŕ Þŕöḿîšéš öñ ţĥé ƒàçàđé, îñ ƃöţĥ ḿöđéš.
  • Ţĥé ƒîļé šýšţéḿ ĥàš à ḿîŕŕöŕ öñ ţĥé þàĝé. runtime.vol šţàýš šýñçĥŕöñöüš: ţĥé þàĝé ĥöļđš à çöþý öƒ ţĥé éñĝîñé'š ƒîļé šýšţéḿ, à ŵŕîţé öñ ţĥé þàĝé ŕéàçĥéš ţĥé Ŵöŕķéŕ ƃéƒöŕé ţĥé ñéẋţ çàļļ (ḿéššàĝéš ķééþ ţĥéîŕ öŕđéŕ), àñđ ţĥé Ŵöŕķéŕ šéñđš ţĥé çĥàñĝéš à çàļļ ḿàđé ƃéƒöŕé ţĥé çàļļ'š àñšŵéŕ, šö à þàĝé ţĥàţ ŕéàđš vol àƒţéŕ à çàļļ šééš ţĥéḿ. memfs ŕéþöŕţš éàçĥ çĥàñĝéđ þàţĥ (onChange) ƒöŕ ţĥîš.
  • Ţĥé ÀƂÎ đéšçŕîþţöŕ. Ţĥé Ŵöŕķéŕ šéñđš kapiEngineABI() ŵîţĥ îţš ŕéàđý ḿéššàĝé, àñđ ţĥé ƒàçàđé îñšţàļļš îţ öñ ţĥé þàĝé, šö engineABI() àñđ hasEngineFunction() àñšŵéŕ ţĥéŕé.
  • Ŕéṽéŕšé ƃŕîđĝéš šţàý öñ ţĥé þàĝé. Ŵîţĥ éàçĥ çàļļ ţĥé ƒàçàđé šéñđš ŵĥîçĥ ƃŕîđĝéš ţĥé þàĝé ĥàš, àñđ ţĥé Ŵöŕķéŕ îñšţàļļš à šţàñđ-îñ ƒöŕ éàçĥ ţĥàţ àšķš ţĥé þàĝé àñđ ŵàîţš ƒöŕ îţš àñšŵéŕ. À šţàñđ-îñ àñšŵéŕš ŵîţĥ à Þŕöḿîšé, šö ţĥé éñĝîñé ŵàîţš ƒöŕ îţ öñ à ĝöŕöüţîñé: labSegmentAsync îš labSegment àñšŵéŕéđ àš à Þŕöḿîšé ƒöŕ ţĥàţ ŕéàšöñ, àñđ ţĥé ÎÇÜ4Ẋ éñĝîñé (core/segment/icu4xjs) àççéþţš à Þŕöḿîšé ƒŕöḿ îţš ƃŕîđĝé. Ţĥé Ŵöŕķéŕ àñšŵéŕš kapiIntlSentenceBreaks îţšéļƒ, šîñçé Intl.Segmenter éẋîšţš ţĥéŕé, àñđ ḿîŕŕöŕš ţĥé þŕéšéñçé öƒ ţĥé þļàţƒöŕḿ Translator ÀÞÎ.
  • Ļöàđîñĝ wasm_exec.js. Ţĥé Ŵöŕķéŕ îḿþöŕţš îţ àš à ḿöđüļé, ƒàļļîñĝ ƃàçķ ţö importScripts îñ à çļàššîç Ŵöŕķéŕ. À ĥöšţ öñ àñöţĥéŕ öŕîĝîñ šéŕṽéš îţ ŵîţĥ ÇÖŔŠ, àš îţ àļŕéàđý đöéš ƒöŕ ţĥé éñĝîñé ƃîñàŕý.

Šţöŕàĝé​

Éṽéŕý šţöŕé îñ ţĥé ƃŕöŵšéŕ ƃüîļđ îš ţĥé ñàţîṽé çöđé: ţĥé ŵöŕķšþàçé àñđ îţš öþéŕàţîöñ ļöĝ, ţĥé þŕöĵéçţöŕ, ţĥé çöñţéñţ ḿéḿöŕý, ţĥé ţéŕḿš šţöŕé, ţĥé ṽöîçé šţöŕé, ţĥé đéçîšîöñ ļéđĝéŕ, ţĥé çöñţéẋţ ĝŕàþĥ àñđ ţĥé ƃļöçķ çàçĥé. Ţĥéý àŕé ŠǪĻ ƃéĥîñđ core/storage, àñđ ţĥé ƃŕöŵšéŕ ƃüîļđ'š đŕîṽéŕ ŕüñš ţĥàţ ŠǪĻ öñ ţĥé öƒƒîçîàļ ŠǪĻîţé ŴéƃÀššéḿƃļý ƃüîļđ, @sqlite.org/sqlite-wasm.

  • Ŵĥéŕé ţĥé ŵöŕķšþàçé îš ķéþţ. Îñ ţĥé Ŵöŕķéŕ, ţĥé éñĝîñé ķééþš îţš đàţàƃàšéš îñ ŠǪĻîţé'š opfs-sahpool ṼƑŠ, îñ ţĥé öŕîĝîñ þŕîṽàţé ƒîļé šýšţéḿ, àñđ ţĥé ƒîļéš öƒ îţš ƒîļé šýšţéḿ îñ à đàţàƃàšé öƒ îţš öŵñ îñ ţĥé šàḿé þööļ (/.kapi-engine/volume.db, öüţšîđé ţĥé đŕîṽéŕ'š ñàḿéšþàçé), ŵŕîţţéñ àƒţéŕ éàçĥ çàļļ. Ƃöţĥ šüŕṽîṽé à ŕéļöàđ àñđ à ƃŕöŵšéŕ ŕéšţàŕţ, àñđ ñééđ ñö ÇÖÖÞ öŕ ÇÖÉÞ ĥéàđéŕš, ŵĥîçĥ ĜîţĤüƃ Þàĝéš çàññöţ šéţ. runtime.storage šàýš ŵĥîçĥ àþþļîéš: { kind: "opfs" }, öŕ { kind: "memory", reason } ŵîţĥ reason öñé öƒ disabled, main-thread, unsupported, another-tab, taken öŕ failed, àñđ describeStorage() ţüŕñš îţ îñţö à šéñţéñçé ƒöŕ à þàĝé. runtime.onStorageChange() ŕéþöŕţš éàçĥ çĥàñĝé. Ţĥé þööļ îš ñàḿéđ ƃý à ķéý (BootOptions.persist, đéƒàüļţ "kapi"); ţĥé đöçš ķéý îţ ƃý ţĥéîŕ ƃàšé ÜŔĻ, šîñçé ţĥé šţàƃļé đöçš, ţĥé þŕéṽîéŵ çĥàññéļ àñđ éàçĥ þüļļ ŕéǫüéšţ þŕéṽîéŵ šĥàŕé àñ öŕîĝîñ àñđ šéŕṽé đéŕéñţ éñĝîñéš.

  • Öñé ţàƃ öŵñš ţĥé þööļ. Ţĥé þööļ ĥöļđš à šýñçĥŕöñöüš ĥàñđļé öñ éṽéŕý ƒîļé, ŵĥîçĥ öñļý öñé çöñţéẋţ ḿàý ĥöļđ, šö ţĥé Ŵöŕķéŕ ƒîŕšţ ţàķéš à Ŵéƃ Ļöçķ ñàḿéđ ƒöŕ ţĥé þööļ àñđ ĥöļđš îţ ƒöŕ îţš ļîƒé. Éṽéŕý ţàƃ ŵàîţš à ḿöḿéñţ ƒöŕ ţĥé ļöçķ (à ŕéļöàđ ŕéļéàšéš îţ àš ţĥé öļđ þàĝé çļöšéš). BootOptions.whenHeld šàýš ŵĥàţ à ţàƃ đöéš ŵĥéñ àñöţĥéŕ ţàƃ šţîļļ ĥöļđš îţ: "memory" (ţĥé đéƒàüļţ) ŕüñš îñ ḿéḿöŕý ŵîţĥ reason: "another-tab", "wait" ŵàîţš üñţîļ ţĥé öŵñéŕ ļéţš ĝö, àñđ "take" ţàķéš ţĥé ŵöŕķšþàçé öṽéŕ. Ƃéƒöŕé îñšţàļļîñĝ ţĥé þööļ ţĥé Ŵöŕķéŕ çĥéçķš ţĥàţ ñö öţĥéŕ çöñţéẋţ šţîļļ ĥöļđš îţš ƒîļéš àñđ ŵàîţš ƒöŕ öñé ţĥàţ îš çļöšîñĝ: à ƒàîļéđ îñšţàļļ îñ ţĥîš ŕéļéàšé öƒ sqlite-wasm ŕéḿöṽéš ţĥé þööļ'š đîŕéçţöŕý. Ţĥé þööļ ĝŕöŵš ƃéţŵééñ çàļļš, šîñçé ĝŕöŵîñĝ îţ ŵàîţš öñ ţĥé ƒîļé šýšţéḿ, ķééþîñĝ šþàŕé šļöţš ƒöŕ ţĥé đàţàƃàšéš àñđ ĵöüŕñàļš à çàļļ çŕéàţéš.

  • Ĥàñđîñĝ ţĥé ŵöŕķšþàçé öṽéŕ. runtime.takeOver() ḿöṽéš ţĥé ŵöŕķšþàçé ţö ţĥé ţàƃ ţĥàţ çàļļš îţ. Ţĥé çàļļš îñ ƒļîĝĥţ ƒîñîšĥ ƒîŕšţ; ţĥéñ ţĥé ƒàçàđé šţàŕţš à šéçöñđ Ŵöŕķéŕ ţĥàţ ŕéǫüéšţš ţĥé ļöçķ ŵîţĥ steal: true. Šţéàļîñĝ ŕéĵéçţš ţĥé öŵñéŕ'š ĥéļđ ļöçķ ŕéǫüéšţ, ŵĥîçĥ îš ĥöŵ ţĥé öŵñéŕ ļéàŕñš îţ ļöšţ ţĥé ŵöŕķšþàçé: îţš Ŵöŕķéŕ ķééþš ţĥé ƒîļé çĥàñĝéš ñöţ ýéţ ķéþţ, šţöþš üšîñĝ ţĥé þööļ àñđ šéñđš lost, àñđ îţš þàĝé ƒàîļš ţĥé çàļļš îñ ƒļîĝĥţ, šţöþš ţĥàţ Ŵöŕķéŕ (ŵĥîçĥ ŕéļéàšéš ţĥé þööļ'š ƒîļé ĥàñđļéš) àñđ šţàŕţš àñöţĥéŕ îñ ḿéḿöŕý ŵîţĥ ţĥé þàĝé'š ƒîļéš, šö storage ƃéçöḿéš { kind: "memory", reason: "taken" }. Ţĥé ñéŵ öŵñéŕ ŵàîţš ƒöŕ ţĥé ĥàñđļéš ţö ƃé ƒŕéé (üþ ţö 15 šéçöñđš), îñšţàļļš ţĥé þööļ àñđ ŕéþļàçéš ţĥé ţàƃ'š ƒîļéš ŵîţĥ ţĥé ķéþţ öñéš; ţĥé ƒàçàđé ḿöṽéš öñţö ţĥàţ Ŵöŕķéŕ àñđ šţöþš ţĥé öļđ öñé. Ŵĥéñ ţĥé þööļ çàññöţ ƃé öþéñéđ, takeOver() ŕéĵéçţš àñđ ţĥé ţàƃ šţàýš àš îţ ŵàš. À Ŵöŕķéŕ ţĥàţ ļöšéš ţĥé ļöçķ ƃéƒöŕé îţ îš ŕéàđý îš ŕéþļàçéđ ƃý öñé îñ ḿéḿöŕý. Ţĥé þļàýĝŕöüñđ'š ƒîļéš þàñéļ öƒƒéŕš Üšé ţĥé ŵöŕķšþàçé ĥéŕé ŵĥîļé àñöţĥéŕ ţàƃ ĥöļđš ţĥé ŵöŕķšþàçé.

  • Ļöçķš ƃéţŵééñ çöññéçţîöñš. Ţĥé þööļ'š öŵñ ļöçķš öñļý ŕéḿéḿƃéŕ ţĥé ļéṽéļ àšķéđ ƒöŕ. Ţĥé éñĝîñé öþéñš šéṽéŕàļ çöññéçţîöñš ţö öñé đàţàƃàšé, šö ţĥé ƃŕîđĝé îñšţàļļš à ļöçķ ţàƃļé öṽéŕ ţĥé þööļ'š ḿéţĥöđš (packages/engine/src/locks.ts) ţĥàţ ķééþš ŠǪĻîţé'š ļöçķ ļéṽéļš þéŕ đàţàƃàšé, àš memdb àñđ os_unix.c đö ŵîţĥîñ öñé þŕöçéšš: à ŵŕîţé ƃéšîđé àñöţĥéŕ çöññéçţîöñ'š ţŕàñšàçţîöñ ŕéþöŕţš database is locked àţ öñçé, àš îţ đöéš îñ ḿéḿöŕý.

  • Ţĥé ŵöŕķšþàçé îš à çàçĥé. Ţĥé ƃŕöŵšéŕ ḿàý éṽîçţ ŵĥàţ à šîţé ķééþš (Šàƒàŕî ŕéḿöṽéš đàţà à šçŕîþţ ŵŕöţé àƒţéŕ šéṽéñ đàýš ŵîţĥöüţ îñţéŕàçţîöñ), šö ţĥé ŵöŕķšþàçé îñ à ƃŕöŵšéŕ îš à çàçĥé öƒ à ļöĝ ţĥàţ šĥöüļđ àļšö ļîṽé éļšéŵĥéŕé. kapiExportWorkspace() þàçķš ţĥé éñĝîñé'š ƒîļéš àñđ ţĥé çöñţéẋţ öƒ éṽéŕý þŕöĵéçţ àḿöñĝ ţĥéḿ îñţö à ŵöŕķšþàçé þàçķàĝé (kpz.KindWorkspace, kapi-workspace): ţĥé ƒîļéš üñđéŕ files/, àñđ þéŕ þŕöĵéçţ à çöñţéẋţ þàçķàĝé üñđéŕ contexts/, ţĥé öþéŕàţîöñ ļöĝ kapi store export ŵŕîţéš. kapiImportWorkspace(bytes) ŵŕîţéš ţĥé ƒîļéš àñđ ḿéŕĝéš éàçĥ ļöĝ, àš kapi store import đöéš, ŵĥîçĥ ŕéƃüîļđš ţĥé þŕöĵéçţ'š šţöŕéš. À ţéŕḿš šţöŕé öüţšîđé éṽéŕý þŕöĵéçţ (öñé kapi terms import --file ŵŕöţé, šàý) ĥàš ñö ļöĝ, šö îţ ţŕàṽéļš àš à ţéŕḿš ƃüñđļé üñđéŕ termstores/, ŵĥîçĥ ţĥé ḿàñîƒéšţ ḿàþš ţö ţĥé šţöŕé'š þàţĥ, àñđ àñ îḿþöŕţ àđđš îţš çöñçéþţš àñđ ŕéļàţîöñš ţö à šţöŕé àţ ţĥàţ þàţĥ. Ţĥé šţöŕéš îñ à þŕöĵéçţ'š .kapi/ àŕé þŕöĵéçţîöñš öƒ îţš ļöĝ àñđ šţàý öüţ; šö đö ţĥé đàţà ŕööţ, /tmp àñđ ţĥé ļàƃ'š öŵñ đîŕéçţöŕý (/.lab). Ţĥé ƒàçàđé'š exportWorkspace() àñđ importWorkspace() ŵŕàþ ţĥéḿ, àñđ ţĥé þļàýĝŕöüñđ'š ƒîļéš þàñéļ öƒƒéŕš ƃöţĥ.

  • À ŕéšéţ, ţĥéñ àñ îḿþöŕţ. À ŕéšéţ ƒöŕĝéţš éàçĥ þŕöĵéçţ îñ ţĥé ŵöŕķšþàçé (workspace.Forget), ŵĥîçĥ ŕéçöŕđš project.forget îñ ţĥé ļöĝ àñđ ķééþš ţĥé öþéŕàţîöñš ƃéƒöŕé îţ ƒöŕ ĥîšţöŕý; à šţöŕé šţàŕţš àƒţéŕ ţĥé ļàţéšţ ŕéḿöṽàļ. Ţĥé ŵöŕķšþàçé ţŕéàţš àñ öþéŕàţîöñ ĥéļđ öñļý ƃéƒöŕé îţš þŕöĵéçţ'š ŕéḿöṽàļ àš ñöţ ĥéļđ: Record ŵŕîţéš îţ àĝàîñ àƒţéŕ ţĥé ŕéḿöṽàļ, à þüļļ çöüñţš îţ àš ñéŵ, à þüšĥ ļéàṽéš öüţ éṽéŕý öþéŕàţîöñ ƃéƒöŕé ţĥé ŕéḿöṽàļ, àñđ ţĥé ŕéḿöṽàļ çļéàŕš ŵĥàţ ţĥé ŵöŕķšþàçé ķñéŵ àƃöüţ ţĥé þŕöĵéçţ'š ŕéḿöţéš. Šö îḿþöŕţîñĝ ţĥé þàçķàĝé éẋþöŕţéđ ƃéƒöŕé à ŕéšéţ, îñ ţĥé šàḿé ƃŕöŵšéŕ, ḿéŕĝéš ţĥé þŕöĵéçţ'š ļöĝ àĝàîñ àñđ ŕéƃüîļđš îţš šţöŕéš.

  • Šýñç ţĥŕöüĝĥ à ƒöļđéŕ. kapiSyncContext(remote, options) þüļļš à þŕöĵéçţ'š çöñţéẋţ ƒŕöḿ à ŕéḿöţé ţĥé þàĝé ĥöļđš àñđ þüšĥéš ŵĥàţ ţĥé éñĝîñé ŕéçöŕđéđ (App.SyncProjectContextWith, ţĥé šàḿé þüļļ àñđ þüšĥ kapi context sync ŕüñš), àñđ ŕéšöļṽéš ţö {pull, push}. Ţĥé ŕéḿöţé îš àñ öƃĵéçţ ŵîţĥ list, get àñđ put (kapi/cmd/kapi-wasm-cli/contextremote.go); folderRemote(handle) (packages/engine/src/folderremote.ts) ƃüîļđš öñé öṽéŕ à FileSystemDirectoryHandle, ƒŕöḿ showDirectoryPicker() öŕ ţĥé öŕîĝîñ þŕîṽàţé ƒîļé šýšţéḿ. Ţĥé ƒöļđéŕ ķééþš ţĥé ļàýöüţ FileRemote ķééþš öñ đîšķ, öñé ƒîļé þéŕ öƃĵéçţ, éàçĥ ŵŕîţţéñ üñđéŕ à đöţ-ñàḿé àñđ ḿöṽéđ îñţö þļàçé, šö à ŕéçîþé ŵîţĥ context: {backend: file, path: <folder>} öñ ţĥé šàḿé çöḿþüţéŕ šĥàŕéš ţĥé çöñţéẋţ. Ţĥé ƒàçàđé'š syncContext(folder, opts) šéñđš ţĥé ĥàñđļé ţö ţĥé Ŵöŕķéŕ, ŵĥéŕé ţĥé ŕéḿöţé îš ƃüîļţ, àñđ ţĥé ƒîļéš þàñéļ öƒƒéŕš Šýñç çöñţéẋţ ŵîţĥ à ƒöļđéŕ ŵĥéŕé showDirectoryPicker éẋîšţš (Çĥŕöḿîüḿ). Ţĥé öţĥéŕ ƃàçķéñđš šţàý ñàţîṽé: à git ƃàçķéñđ ŕüñš ţĥé git éẋéçüţàƃļé, ŵĥîçĥ à þàĝé çàññöţ šţàŕţ, àñđ ţĥé s3 ƃàçķéñđ ŕéàđš ţĥé ÀŴŠ çŕéđéñţîàļ çĥàîñ, ŵĥîçĥ à þàĝé ĥàš ñö šàƒé þļàçé ţö ĥöļđ.

  • Ţĥé ƃŕîđĝé. packages/engine/src/sqlite.ts ļöàđš ţĥé ḿöđüļé àñđ îñšţàļļš öñé öƃĵéçţ öñ globalThis, __kapiSQL, ƃéƒöŕé Ĝö šţàŕţš. Ţĥé Ĝö đŕîṽéŕ (core/storage/driver_js.go, core/storage/sqlitejs_js.go) ŕéĝîšţéŕš ŵîţĥ database/sql àñđ çàļļš ţĥé ƃŕîđĝé šýñçĥŕöñöüšļý ţĥŕöüĝĥ syscall/js, šö Ĝö àñđ ŠǪĻîţé šĥàŕé ţĥé þàĝé'š ḿàîñ ţĥŕéàđ. Àŕĝüḿéñţš àñđ ŕéšüļţ ŕöŵš çŕöšš îñ öñé þàçķéđ ƃýţé ƃüƒƒéŕ þéŕ çàļļ. À ƒàîļüŕé çöḿéš ƃàçķ àš ŠǪĻîţé'š öŵñ ḿéššàĝé àñđ éẋţéñđéđ ŕéšüļţ çöđé.

  • Ŵĥéŕé ţĥé đàţàƃàšéš ļîṽé. Ñàḿéđ ƃý àƃšöļüţé þàţĥ, îñ ţĥé þööļ öŕ, îñ ḿéḿöŕý, îñ ŠǪĻîţé'š memdb ṼƑŠ. Éṽéŕý çöññéçţîöñ ţö öñé ñàḿé šĥàŕéš ţĥé đàţàƃàšé, àñđ ATTACH ƃý þàţĥ ŕéàçĥéš îţ, šîñçé ţĥé ƃŕîđĝé ḿàķéš îţš ṼƑŠ ţĥé đéƒàüļţ. Îñ ḿéḿöŕý ţĥé ƃŕîđĝé ĥöļđš à çöññéçţîöñ öƒ îţš öŵñ öñ éàçĥ ñàḿé, šö à đàţàƃàšé öüţļîṽéš ţĥé þööļš ţĥàţ öþéñ àñđ çļöšé îţ ƃéţŵééñ çöḿḿàñđš. Ţĥé éñĝîñé ñàḿéš îţš đàţà ŕööţ /.kapi-data (KAPI_DATA_DIR), ŵĥéŕé ţĥé ŵöŕķšþàçé ļîṽéš.

  • Ţĥé đŕîṽéŕ'š þŕöƒîļé. storage.DriverProfile() ŕéþöŕţš öñé çöññéçţîöñ þéŕ ƒîļé, ñö ŴÀĻ àñđ ñö çŕöšš-þŕöçéšš ļöçķ, àñđ đüŕàƃîļîţý ŵĥéñ ţĥé ƃŕîđĝé šàýš îţš đàţàƃàšéš öüţļîṽé ţĥé þàĝé (__kapiSQL.durable). Ţĥé ƃüšý ţîḿéöüţ îš žéŕö: à šéçöñđ çöññéçţîöñ'š ŵàîţ ŵöüļđ šþîñ ţĥé öñļý ţĥŕéàđ, šö à ļöçķ çöñƒļîçţ ŕéþöŕţš database is locked àţ öñçé. Çöđé öñ ţĥéšé þööļš ñéṽéŕ ĥöļđš à ţŕàñšàçţîöñ öŕ öþéñ ŕöŵš àñđ ţĥéñ ŵàîţš ƒöŕ à šéçöñđ šéššîöñ öñ ţĥé šàḿé þööļ ƒŕöḿ ţĥé šàḿé ĝöŕöüţîñé. Ţĥé ƃļöçķ šţöŕé'š îţéŕàţöŕš ŕéàđ à þàĝé àţ à ţîḿé àñđ ŕéļéàšé ţĥé çöññéçţîöñ ƃéƒöŕé ýîéļđîñĝ, šö à çàļļéŕ ḿàý ŵŕîţé ŵĥîļé îţ îţéŕàţéš. À ƒàîļéđ COMMIT îš ŕöļļéđ ƃàçķ, àš ţĥé ñàţîṽé đŕîṽéŕ đöéš, šö ţĥé þööļ'š öñé çöññéçţîöñ ñéṽéŕ šţàýš îñšîđé à ţŕàñšàçţîöñ. make test-stores-oneconn ŕüñš ţĥé šţöŕé šüîţéš ñàţîṽéļý ŵîţĥ éṽéŕý þööļ ĥéļđ ţö öñé çöññéçţîöñ àñđ ŴÀĻ öƒƒ, ţö ƒîñđ šüçĥ çöđé ŵîţĥöüţ à ƃŕöŵšéŕ: à çàļļ ţĥàţ ŵàîţš 20 šéçöñđš ƒöŕ ţĥé þööļ þàñîçš ŵîţĥ éṽéŕý ĝöŕöüţîñé'š šţàçķ, àñđ à ŕéàđ öñ öñé þööļ ƃéšîđé à ŵŕîţé ţĥé šàḿé çöđé ĥöļđš öñ àñöţĥéŕ ŵàîţš öüţ ţĥé ƃüšý ţîḿéöüţ àñđ ƒàîļš ŵîţĥ database is locked, ŵĥîçĥ ţĥé ƃŕöŵšéŕ ŕéþöŕţš àţ öñçé. ÇÎ ŕüñš îţ ƃéšîđé make test-wasm-stores, àñđ öñ þüšĥ ŕüñš ţĥé ĥöšţ šüîţé ţĥé šàḿé ŵàý (make test-host-oneconn).

  • Đàţàƃàšé ƒîļéš ƃéļöñĝ ţö ţĥé đŕîṽéŕ. Ţĥé þàĝé'š ƒîļé šýšţéḿ ñéṽéŕ šééš à đàţàƃàšé, šö çöđé ţĥàţ àšķš ŵĥéţĥéŕ öñé éẋîšţš, ŕéḿöṽéš, ŕéñàḿéš öŕ ļîšţš ţĥéḿ çàļļš storage.Exists, storage.Remove, storage.Rename, storage.List àñđ storage.RemoveAll ŕàţĥéŕ ţĥàñ os. À đàţàƃàšé'š đîŕéçţöŕý šţîļļ ĥàš ţö éẋîšţ îñ ţĥé éñĝîñé'š ƒîļé šýšţéḿ, àš îţ đöéš ñàţîṽéļý.

  • À đàţàƃàšé ƒîļé à þàĝé àđđš. À ŠǪĻîţé ƒîļé îñ ţĥé éñĝîñé'š ƒîļé šýšţéḿ (öñé à ŕéàđéŕ üþļöàđš, šàý) îš ŕéàđ îñţö ḿéḿöŕý ţĥé ƒîŕšţ ţîḿé à šţöŕé öþéñš îţš þàţĥ, ţĥŕöüĝĥ sqlite3_deserialize, àñđ ŵŕîţéš ĝö ţö ţĥé çöþý îñ ḿéḿöŕý. Ţĥé ñàḿéšþàçé àñšŵéŕš ƒöŕ šüçĥ ƒîļéš ţöö, àñđ storage.Remove đéļéţéš ţĥé ƒîļé ŵîţĥ ţĥé đàţàƃàšé, šö à ŕéḿöṽéđ đàţàƃàšé šţàýš ŕéḿöṽéđ. À ƒîļé ţĥàţ îš ñöţ à đàţàƃàšé ƒàîļš ţö öþéñ ŵîţĥ file is not a database, àš îţ đöéš ñàţîṽéļý; öñé ŵîţĥ àñ üñƒļüšĥéđ ŵŕîţé-àĥéàđ ļöĝ ƃéšîđé îţ ƒàîļš ŵîţĥ à ḿéššàĝé ţĥàţ šàýš šö.

  • Ŕöŵ ƃàţçĥéš. À ǫüéŕý'š ŕöŵš çŕöšš 256 àţ à ţîḿé, öŕ àƃöüţ 1 ḾîƂ àţ à ţîḿé ŵĥéñ ţĥéý àŕé ļàŕĝé.

  • Ŵöŕđ šéàŕçĥ. Ţĥé ḿöđüļé çàŕŕîéš ŠǪĻîţé'š ƃüîļţ-îñ ƑŢŠ5 ţöķéñîžéŕš àñđ ñö ÎÇÜ, šö storage.FTSWordTokenizer îš unicode61.

  • Ţĥé àššéţ. sqlite3.wasm îš šéŕṽéđ ƃéšîđé ţĥé éñĝîñé ƃîñàŕý, ŵĥéŕé make web-wasm-cli šţàĝéš îţ (ŵîţĥ sqlite3.wasm.gz) ƒŕöḿ ţĥé þîññéđ þàçķàĝé, àñđ ţĥé ƃööţ þŕéƒéŕš ţĥé þŕéçöḿþŕéššéđ çöþý. bootKapiRuntime(wasmExecUrl, wasmUrl, { sqliteWasmUrl }) ţàķéš àñöţĥéŕ ļöçàţîöñ. Ḿéàšüŕéđ ŵîţĥ ĝžîþ -9, ţĥé àššéţ îš àƃöüţ 0.40 ḾƂ àñđ ţĥé ƃüñđļéđ ĴàṽàŠçŕîþţ (ţĥé ḿöđüļé'š ĝļüé àñđ ţĥé ƃŕîđĝé, ḿîñîƒîéđ) àƃöüţ 0.07 ḾƂ.

  • Ţĥé ļàƃ þŕöĵéçţ. Ţĥé ŕéàđ-öñļý àññöţàţöŕš ƃéĥîñđ labInspectAnnotated ļööķ ţéŕḿš üþ îñ à þŕöĵéçţ ţĥé éñĝîñé çŕéàţéš àţ /.lab/project öñ ƒîŕšţ üšé, àñđ öþéñš àĝàîñ îƒ à ŕéšéţ çļöšéđ îţ. Îţš ţéŕḿš àŕé ţĥé ƃüñđļé îñ kapi/cmd/kapi-wasm-cli/fixtures/terms.json, îḿþöŕţéđ ţĥŕöüĝĥ ţĥé þŕöĵéçţöŕ, šö ţĥéý àŕé öþéŕàţîöñš îñ ţĥé ŵöŕķšþàçé ļöĝ àš ţĥéý ŵöüļđ ƃé ñàţîṽéļý. Çöḿḿàñđš ţýþéđ îñ à ļàƃ ŕéšöļṽé šţöŕéš àš ñàţîṽéļý: îñšîđé à þŕöĵéçţ ţĥéý üšé ţĥé þŕöĵéçţ'š, àñđ öüţšîđé öñé ţĥé šţàñđàļöñé šţöŕé à ƒļàĝ öŕ ţĥé ŵöŕķîñĝ đîŕéçţöŕý ñàḿéš.

  • Šţàŕţîñĝ à đîŕéçţöŕý öṽéŕ. kapiReset(dir) ƒöŕĝéţš éṽéŕý þŕöĵéçţ çĥéçķéđ öüţ àţ öŕ ƃéļöŵ dir îñ ţĥé ŵöŕķšþàçé (App.ForgetProjectsUnder, ŵĥîçĥ çļöšéš ţĥé šţöŕéš îţ ĥöļđš ţĥéŕé, ŕéàđš ţĥé ŕéĝîšţŕý ƒöŕ ţĥé þŕöĵéçţš à þŕéṽîöüš þàĝé ŕéĝîšţéŕéđ ţĥéŕé, àñđ çàļļš workspace.Forget ƒöŕ éàçĥ), ţĥéñ ŕéḿöṽéš éṽéŕý đàţàƃàšé ţĥéŕé öüţšîđé ţĥé ŵöŕķšþàçé'š öŵñ. À þŕöĵéçţ šééđéđ ţĥéŕé àĝàîñ ƃéĝîñš ŵîţĥ àñ éḿþţý çöñţéẋţ àñđ àñ éḿþţý ŕéçöŕđ, ƃéçàüšé ţĥé þŕöĵéçţöŕ ŕéþļàýš, àñđ ţĥé çöñţéẋţ ļéđĝéŕ ŕéþöŕţš, öñļý ŵĥàţ ţĥé ļöĝ ĥöļđš àƒţéŕ à þŕöĵéçţ'š ļàţéšţ ŕéḿöṽàļ. À þŕöĵéçţ îš ķéýéđ ƃý îţš ŕéçîþé'š id: öŕ name:, šö ţĥé šàḿé šàḿþļé šééđéđ îñ ţŵö đîŕéçţöŕîéš îš öñé þŕöĵéçţ ŵîţĥ öñé çöñţéẋţ, àñđ à ŕéšéţ üñđéŕ éîţĥéŕ đîŕéçţöŕý ƒöŕĝéţš îţ ŵĥöļé: ţĥé ļéàŕñîñĝ ļàƃš ŕéšéţ ţĥéîŕ ŵĥöļé /learn ţŕéé öñ Þļàý ƒöŕ ţĥàţ ŕéàšöñ. KapiRuntime.reset(dir) çàļļš îţ àñđ ţĥéñ çļéàŕš ţĥé đîŕéçţöŕý'š ƒîļéš; ţĥé þļàýĝŕöüñđ'š Ŕéšéţ ƃüţţöñ àñđ ţĥé ţéŕḿîñàļ'š rm (ţĥŕöüĝĥ KapiRuntime.removeDatabase) üšé ţĥéḿ.

  • Ţéšţéđ îñ Ñöđé. make test-wasm-stores ŕüñš ţĥé šţöŕé šüîţéš üñđéŕ GOOS=js îñ Ñöđé öṽéŕ ţĥé šàḿé ƃŕîđĝé (scripts/wasm-stores/), àñđ ţĥé çĥàñĝé šéŕṽîçé'š šüîţéš ƃéšîđé ţĥéḿ (Ţĥé çĥàñĝé çöñţŕàçţ). À ţéšţ ţĥàţ ñééđš à šüƃþŕöçéšš (ĝîţ, öŕ à šéçöñđ ŵŕîţéŕ þŕöçéšš), đîŕéçţöŕý þéŕḿîššîöñš ţĥàţ ŕéàçĥ à đàţàƃàšé, öŕ þŕééḿþţîöñ šķîþš ţĥéŕé àñđ ñàḿéš ŵĥîçĥ.

Ţĥé çĥàñĝé çöñţŕàçţ​

À þàĝé ţĥàţ éđîţš çöñţéñţ šéñđš ţĥé çĥàñĝé çöñţŕàçţ (É-09) ţö ţĥŕéé éñţŕý þöîñţš, ŕàţĥéŕ ţĥàñ à çöḿḿàñđ ļîñé ţö kapiRun. Éàçĥ ţàķéš ţĥé çöñţŕàçţ'š ĴŠÖÑ àš à šţŕîñĝ àñđ àñ öþţîöñàļ šéçöñđ šţŕîñĝ, ţĥé çàļļ'š öþţîöñš, àñđ ŕéţüŕñš à Þŕöḿîšé öƒ à ĴŠÖÑ šţŕîñĝ.

Éñţŕý þöîñţŢàķéšŔéšöļṽéš ţö
kapiRead(requestJSON, optionsJSON?)à ŕéàđ ŕéǫüéšţ: {doc, blocks, editions, cursor, limit}à ŕéàđ þàĝé: éàçĥ ƃļöçķ'š ref àñđ rev, îţš ţéẋţ îñ þļàçéĥöļđéŕ ƒöŕḿ, îţš çöđéš, þļüŕàļš àñđ šéļéçţš, îţš öţĥéŕ éđîţîöñš àñđ ţĥé öþéŕàţîöñš îţ àççéþţš, àñđ next ƒöŕ ţĥé ƒöļļöŵîñĝ þàĝé
kapiApply(changeSetJSON, optionsJSON?)à kapi.change/v1 çĥàñĝé šéţ: àñ öƃĵéçţ ŵîţĥ ops, ĴŠÖÑĻ, öŕ àñ àŕŕàý öƒ öþéŕàţîöñšţĥé kapi.change-result/v1 ŕéšüļţ
kapiDescribe(requestJSON, optionsJSON?){format} öŕ {doc}ŵĥàţ ţĥé ƒöŕḿàţ šüþþöŕţš öƒ éàçĥ öþéŕàţîöñ
  • Öþţîöñš. {project, actor}. project ñàḿéš ţĥé þŕöĵéçţ ţĥé çàļļ àçţš îñ: îţš kapi.yaml, îţš ŕööţ, öŕ à þàţĥ îñšîđé îţ. Ŵîţĥöüţ öñé, ţĥé çàļļ àçţš îñ ţĥé þŕöĵéçţ đîšçöṽéŕý ƒîñđš ƒŕöḿ ţĥé éñĝîñé'š ŵöŕķîñĝ đîŕéçţöŕý, àš à çöḿḿàñđ ĝîṽéñ ñö -p đöéš, àñđ öüţšîđé àñý þŕöĵéçţ à đöçüḿéñţ îš à þàţĥ üñđéŕ ţĥàţ đîŕéçţöŕý. actor, ŵĥîçĥ öñļý àñ àþþļý ţàķéš, îš {kind, name, session} ŵîţĥ kind éîţĥéŕ person öŕ agent. Ŵîţĥöüţ öñé, ţĥé šéñđéŕ îš ţĥé öñé kapi apply ŕéçöŕđš îñ ţĥé šàḿé éñṽîŕöñḿéñţ: à þéŕšöñ, üñļéšš KAPI_ACTOR öŕ àñ àĝéñţ ĥöšţ'š ḿàŕķéŕ šàýš öţĥéŕŵîšé. Àñ àĝéñţ'š ţéŕḿ, ḿéḿöŕý àñđ ŕéçîþé öþéŕàţîöñš, îţš đéçîšîöñš öţĥéŕ ţĥàñ à þŕé-ŕéṽîéŵ (advise), àñ if_match öƒ * àñđ ţĥé report ĝàţé àŕé ŕéƒüšéđ àš not_permitted, àš ţĥéý àŕé öṽéŕ ḾÇÞ.
  • Öñé šéŕṽîçé. Ţĥé çàļļš ƃüîļđ ţĥé çĥàñĝé šéŕṽîçé ţĥŕöüĝĥ host.ReadChangesJSON, host.ApplyChangesJSON àñđ host.DescribeChangesJSON, ƒŕöḿ ţĥé šàḿé ƒüñçţîöñ ţĥé ḾÇÞ éđîţ ţööļš üšé (callChangeService), ŵîţĥ ţĥé çöḿḿîţ çĥéçķ, ţĥé þöļîçý àñđ ţĥé ŕéçöŕđéŕ kapi apply ŕüñš. À ŕéƒéŕéñçé àñđ à ŕéṽîšîöñ ţĥàţ kapiRead ŕéţüŕñš àŕé ţĥé öñéš kapi inspect þŕîñţš ƒöŕ ţĥé šàḿé ƒîļé, àñđ kapiApply ţàķéš éîţĥéŕ. À ƃîļîñĝüàļ ƒîļé ŵĥöšé ŕéàđéŕ ĥàš ţö ƃé ţöļđ ţĥé ļàñĝüàĝé öƒ ţĥé ţŕàñšļàţîöñ îţ ĥöļđš, šüçĥ àš à ÞÖ çàţàļöĝ'š msgstr, îš ŕéàđ îñ ţĥé öñé ļàñĝüàĝé öţĥéŕ ţĥàñ ţĥé šöüŕçé ţĥàţ à ŕéàđ'š editions öŕ àñ àþþļý'š öþéŕàţîöñš ñàḿé, àš kapi apply ŕéàđš öñé.
  • Àñšŵéŕš. À ŕéǫüéšţ ţĥé šéŕṽîçé ŕéƒüšéš, à çĥàñĝé šéţ ţĥàţ đöéš ñöţ đéçöđé îñçļüđéđ, ŕéšöļṽéš ţö à kapi.change-result/v1 ŵĥöšé error šàýš ŵĥý. Ţĥé Þŕöḿîšé ŕéĵéçţš öñļý ƒöŕ à ƒàîļüŕé ţĥé çöñţŕàçţ ĥàš ñö çöđé ƒöŕ, šüçĥ àš à project ţĥàţ ñàḿéš ñö ƒîļé. Öñ ţĥé ƒàçàđé, read àñđ describe ţĥŕöŵ ChangeRefused, ŵĥîçĥ çàŕŕîéš ţĥàţ ŕéšüļţ, àñđ apply ŕéšöļṽéš ţö îţš ŕéšüļţ ŵĥàţéṽéŕ ţĥé šţàţüš.
  • Ţĥé ŕéçöŕđ. Îñ à þŕöĵéçţ, àñ àþþļîéđ çĥàñĝé šéţ îš ŕéçöŕđéđ îñ ţĥé ŵöŕķšþàçé'š ļöĝ üñđéŕ /.kapi-data àš öñé content.edit öþéŕàţîöñ þéŕ đöçüḿéñţ, ţĥé ŕéçöŕđ kapi apply ŵŕîţéš ñàţîṽéļý, àñđ ţĥé þŕöĵéçţöŕ ŵŕîţéš îţ îñţö ţĥé ƃļöçķ ĥîšţöŕý. À ļàţéŕ ŕéàđ šĥöŵš à ţŕàñšļàţîöñ'š ƃàšîš ƒŕöḿ ţĥéŕé. Öüţšîđé à þŕöĵéçţ ñöţĥîñĝ îš ŕéçöŕđéđ. Éṽéŕý éđîţ îš ķéþţ ŵîţĥ ţĥé ŕéšţ öƒ ţĥé ŵöŕķšþàçé (Šţöŕàĝé).
  • Öñé àţ à ţîḿé. Ţĥé çàļļš, ţĥé çöḿḿàñđš kapiRun ŕüñš (à çöḿþļéţîöñ îñçļüđéđ) àñđ kapiReset šĥàŕé ţĥé éñĝîñé'š Àþþ, šö ţĥé éñĝîñé ŕüñš ţĥéḿ îñ ţüŕñ: à çöḿḿàñđ šţàŕţéđ ŵĥîļé à çàļļ ŕüñš ŵàîţš ƒöŕ îţ, àñđ ţĥé öţĥéŕ ŵàý ŕöüñđ. À çöḿḿàñđ ŕéþļàçéš ţĥé Àþþ'š çöñƒîĝüŕàţîöñ àñđ à ŕéšéţ ŕéḿöṽéš đàţàƃàšéš, šö ñéîţĥéŕ ḿàý ŕüñ ŵĥîļé à çàļļ ŵàîţš öñ ţĥé ƒîļé šýšţéḿ. À çàļļ ţàķéš îţš þŕöĵéçţ ƒŕöḿ îţš öþţîöñš àñđ îţš šöüŕçé ļàñĝüàĝé ƒŕöḿ ţĥàţ þŕöĵéçţ, ñöţ ƒŕöḿ ţĥé ƒļàĝš à çöḿḿàñđ ŵàš ĝîṽéñ. Ţŵö ŵŕîţéŕš öƒ öñé ƒîļé îñ ţĥé þàĝé šţîļļ ţàķé ţüŕñš àţ ţĥé çöḿḿîţ: ţĥé ƒîļé ĥöḿé'š ļöçķ (core/storage/filelock) îš à ḿüţéẋ öƒ ţĥé þŕöçéšš ŵĥéŕé ţĥé þļàţƒöŕḿ ĥàš ñö ļöçķ ƃéţŵééñ þŕöçéššéš.
  • Ţéšţéđ. make test-wasm-stores ŕüñš, üñđéŕ GOOS=js öṽéŕ ţĥé ƃŕöŵšéŕ'š ŠǪĻîţé đŕîṽéŕ, core/change àñđ îţš ƒîļé ĥöḿé ŵîţĥ ţĥé çöñƒöŕḿàñçé šüîţé (core/change/changetest), ţĥé ļöçķ, ţĥé ĥöšţ'š šéŕṽîçé ƒöŕ à þŕöĵéçţ ţĥŕöüĝĥ ţĥé šàḿé šüîţé àñđ îţš ĴŠÖÑ éñţŕý þöîñţš, àñđ ţĥé éñĝîñé'š öŵñ ţéšţ öƒ ţĥé öŕđéŕ îţš éñţŕý þöîñţš ţàķé ţüŕñš îñ. make change-wasm-smoke (scripts/verify-snippets/change-smoke.ts) ƃööţš ţĥé ŕéàļ éñĝîñé îñ Ñöđé àñđ đŕîṽéš ţĥé ţĥŕéé çàļļš ţĥŕöüĝĥ ţĥé ƒàçàđé: à ŕéàđ ţĥàţ ḿàţçĥéš kapi inspect, àñ éđîţ ţĥàţ ļàñđš ƃýţé ƒöŕ ƃýţé àñđ îš ŕéçöŕđéđ, à šţàļé ŕéþļàý, à ţŕàñšļàţîöñ'š ƃàšîš ŕéàđ ƃàçķ, àñđ ţĥé ŕéƒüšàļš.

Çöḿḿàñđ šüŕƒàçé​

kapiRun(argv) éẋéçüţéš ţĥé öŕđîñàŕý ķàþî ÇĻÎ, šö ţĥé ƃŕöŵšéŕ ƃüîļđ ĥàš à šéçöñđ çöñţŕàçţ àļöñĝšîđé ţĥé ĝļöƃàļ ƒüñçţîöñ šéţ: ŵĥîçĥ ṽéŕƃš îţ àñšŵéŕš. kapi apply àñđ kapi inspect ŕüñ ţĥéŕé àš ţĥéý đö ñàţîṽéļý, öṽéŕ ţĥé šàḿé šéŕṽîçé àš ţĥé çĥàñĝé çöñţŕàçţ'š éñţŕý þöîñţš.

  • Öñé đéçļàŕàţîöñ. cli.BrowserCommandSet îš ţĥé ƃŕöŵšéŕ ƃüîļđ'š çöḿḿàñđ šéţ, ḿîŕŕöŕîñĝ cli.KapiCommandSet (ţĥé ñàţîṽé ƃîñàŕý'š) ṽéŕƃ ƒöŕ ṽéŕƃ. kapi/cmd/kapi-wasm-cli ŕéĝîšţéŕš îţ ŵĥöļéšàļé àñđ đéçļàŕéš ñöţĥîñĝ îţšéļƒ.
  • Ñö ḿîššîñĝ ṽéŕƃš. À ṽéŕƃ ţĥé ƃŕöŵšéŕ çàññöţ ŕüñ (öñé ñééđîñĝ à šüƃþŕöçéšš, ţĥé ÖŠ ķéýçĥàîñ, ţĥé ñéţŵöŕķ, öŕ à šöçķéţ) îš ŕéçöŕđéđ îñ cli.browserGaps ŵîţĥ ţĥé ƒàçîļîţý îţ ñééđš, àñđ ŕéĝîšţéŕš à çöḿḿàñđ ţĥàţ ŕéþöŕţš îţ. unknown command ţĥéŕéƒöŕé ḿéàñš ţĥé ṽéŕƃ đöéš ñöţ éẋîšţ îñ ķàþî àţ àļļ, ñéṽéŕ ţĥàţ ţĥé ƃŕöŵšéŕ öḿîţţéđ îţ. --help šţîļļ ŵöŕķš öñ ţĥöšé ṽéŕƃš; ţĥéîŕ ĥéļþ ţéẋţ çàŕŕîéš ţĥé ļîḿîţàţîöñ.
  • Ñö ḾÇÞ šéŕṽéŕ. kapi mcp îš à ŕéçöŕđéđ ĝàþ, àñđ ţĥé ƃüîļđ ļéàṽéš ţĥé šéŕṽéŕ öüţ éñţîŕéļý: ţĥé ĥöšţ àñđ çļî ƒîļéš ţĥàţ îḿþöŕţ ţĥé ḾÇÞ ŠĐĶ àŕé ƃüîļţ ŵîţĥ //go:build !js, šö ñéîţĥéŕ ţĥé ŠĐĶ ñöŕ à ţööļ îţ ŵöüļđ šéŕṽé ŕéàçĥéš ţĥé éñĝîñé. host/mcp_js.go àñđ cli/mcp_js.go šţàñđ îñ ƒöŕ ţĥé ƒéŵ ñàḿéš ţĥé ŕéšţ öƒ ţĥé ƃüîļđ üšéš. make test-wasm-stores çöḿþîļéš ţĥé ĥöšţ'š ţéšţš ƒöŕ ţĥé ƃŕöŵšéŕ, šö à ĥöšţ ţéšţ ţĥàţ đŕîṽéš àñ ḾÇÞ ţööļ šîţš îñ à ƒîļé ƃüîļţ ŵîţĥ !js: ţĥé mcp_*_test.go ƒîļéš, àñđ ţĥé *_mcp_test.go ƒîļéš ƃéšîđé ţĥé ţéšţš ţĥéý ƃéļöñĝ ŵîţĥ.
  • Ñö þļüĝîñ ĥöšţ. kapi plugin îš à ŕéçöŕđéđ ĝàþ: à þļüĝîñ îš à šéþàŕàţé éẋéçüţàƃļé ţĥàţ ķàþî šţàŕţš àš à šüƃþŕöçéšš àñđ ŕéàçĥéš öṽéŕ ĝŔÞÇ, àñđ à þàĝé çàñ đö ñéîţĥéŕ. Ţĥé host/pluginhost ƒîļéš ţĥàţ šţàŕţ à þļüĝîñ öŕ ţàļķ ţö öñé (ţĥé đàéḿöñ þööļ, ţĥé ĝŔÞÇ çļîéñţš ƒöŕ ƒöŕḿàţš, šéĝḿéñţéŕš, çöḿḿéñţš àñđ šöüŕçé çöññéçţöŕš, ţĥé šüƃþŕöçéšš ļàüñçĥéš) àŕé ƃüîļţ ŵîţĥ //go:build !js, šö ĝŔÞÇ àñđ ţĥé þļüĝîñ þŕöţöƃüƒ šţàý öüţ öƒ ţĥé éñĝîñé. Đîšçöṽéŕý àñđ ţĥé ḿàñîƒéšţ-đŕîṽéñ ĥöšţ ƃüîļđ ƒöŕ ţĥé ƃŕöŵšéŕ àš ŵéļļ, àñđ host/pluginhost/runtime_js.go šţàñđš îñ ƒöŕ ţĥé ļàüñçĥéš ţĥé ŕéšţ öƒ ţĥé ƃüîļđ ñàḿéš, éàçĥ àñšŵéŕîñĝ ţĥàţ ţĥé ƃŕöŵšéŕ ŕüñš ñö þļüĝîñ. À ţéšţ ţĥàţ đŕîṽéš ţĥé þļüĝîñ ŵîŕé šîţš îñ à ƒîļé ƃüîļţ ŵîţĥ !js.
  • Đŕîƒţ îš à ţéšţ ƒàîļüŕé. cli.TestBrowserCommandSurface çöḿþàŕéš ţĥé ţŵö šéţš àñđ ƒàîļš ŵĥéñ à ṽéŕƃ àþþéàŕš îñ öñé àñđ ñöţ ţĥé öţĥéŕ, öŕ ŵĥéñ à ĝàþ'š ĥéļþ ḿéţàđàţà đŕîƒţš ƒŕöḿ ţĥé çöḿḿàñđ îţ šţàñđš îñ ƒöŕ. Àđđîñĝ à ṽéŕƃ ţö KapiCommandSet îš à đéçîšîöñ: ŵîŕé îţ üþ ƒöŕ ţĥé ƃŕöŵšéŕ, öŕ ŕéçöŕđ ŵĥý îţ çàññöţ ŕüñ ţĥéŕé.
  • Ŕüñţîḿé ĝüàŕđ. make wasm-surface-smoke (scripts/verify-snippets/command-surface-smoke.ts) ƃööţš ţĥé ŕéàļ ŵàšḿ îñ Ñöđé, šŵééþš éṽéŕý ŕéàçĥàƃļé ṽéŕƃ ƒöŕ unknown command, àššéŕţš éàçĥ ĝàþ'š ḿéššàĝé, àñđ ŕéþļàýš ţĥé àŕĝṽ ţĥé ļàƃ éẋþļöŕéŕš ţĥéḿšéļṽéš üšé. Îţ ŕüñš îñ ţĥé đöçš šñîþþéţ-ṽéŕîƒîçàţîöñ ŵöŕķƒļöŵ (docs-verify-snippets.yml).
  • Çàþţüŕé šţŕîþš ÀÑŠÎ. Ţĥé éñĝîñé ƃööţš ŵîţĥ CLICOLOR_FORCE=1 šö ţĥé þļàýĝŕöüñđ ţéŕḿîñàļ ŕéñđéŕš ķàþî'š ŕéàļ šţýļîñĝ; runCapture ĥàñđš öüţþüţ ţö þŕöĝŕàḿ çöđé îñšţéàđ, àñđ šţŕîþš ţĥé éšçàþéš šö à --json þàýļöàđ þàŕšéš.

Ţĥé šàḿé đéŕîṽàţîöñ ƒééđš ţĥé đöçš: scripts/gen-refs ŕéàđš cli.BrowserUnavailableReason ƒöŕ éàçĥ çöḿḿàñđ'š ŕüññàƃļé-îñ-ƃŕöŵšéŕ ƃàđĝé, šö ţĥé Çöḿḿàñđ Ŕéƒéŕéñçé çàññöţ çļàîḿ à ṽéŕƃ ŕüñš îñ ţĥé ļàƃ ŵĥéñ îţ đöéš ñöţ.

Ŵĥéŕé ţĥé þîéçéš ļîṽé​

ÇöñçéŕñĻöçàţîöñ
Ŕéĝîšţŕàţîöñ ţàƃļé + kapiEngineABI()kapi/cmd/kapi-wasm-cli/main.go
Ƃŕöŵšéŕ çöḿḿàñđ šéţ + ŕéçöŕđéđ ĝàþšcli/browsercmds.go
Šüŕƒàçé đŕîƒţ ĝüàŕđcli/browsercmds_test.go
Ŕüñţîḿé šüŕƒàçé šḿöķéscripts/verify-snippets/command-surface-smoke.ts
Àḿƃîéñţ ŢŠ ţýþîñĝš ƒöŕ ţĥé ĝļöƃàļšpackages/engine/src/globals.ts
Ŵîŕé šĥàþéš + engineABI() ĥéļþéŕpackages/engine/src/abi.ts
KapiRuntime ƒàçàđé + ƃööţpackages/engine/src/runtime.ts
ŠǪĻîţé ƃŕîđĝé (__kapiSQL)packages/engine/src/sqlite.ts
Ţĥé éñĝîñé'š Ŵöŕķéŕ àñđ îţš ḿéššàĝéšpackages/engine/src/worker.ts, packages/engine/src/protocol.ts
Ŵĥéŕé ţĥé ŵöŕķšþàçé îš ķéþţ (þööļ, Ŵéƃ Ļöçķ, ƒîļé šţöŕé)packages/engine/src/storage.ts
Ĥàñđîñĝ ţĥé ŵöŕķšþàçé ƃéţŵééñ ţàƃš (takeOver, lost)packages/engine/src/runtime.ts, packages/engine/src/worker.ts
Ļöçķš ƃéţŵééñ çöññéçţîöñš öñ ţĥé þööļpackages/engine/src/locks.ts
Ŵöŕķšþàçé éẋþöŕţ àñđ îḿþöŕţ (kapiExportWorkspace, kapiImportWorkspace)kapi/cmd/kapi-wasm-cli/workspace.go, kpz/workspacepkg.go
Àñ öþéŕàţîöñ ĥéļđ ƃéƒöŕé îţš þŕöĵéçţ'š ŕéḿöṽàļcore/workspace/local.go (Record), core/workspace/sync.go
Šýñç ţĥŕöüĝĥ à ƒöļđéŕ (kapiSyncContext)kapi/cmd/kapi-wasm-cli/contextremote.go, packages/engine/src/folderremote.ts, host/contextsync.go
Þéŕšîšţéñçé šḿöķé (ŕéļöàđ, ŕéšţàŕţ, à ţàķéöṽéŕ, à ŵàîţîñĝ ţàƃ, à ŕéšéţ àñđ ŕé-îḿþöŕţ, à ƒöļđéŕ šýñç, àñ éẋþöŕţ)scripts/wasm-persist/, make wasm-persist-smoke
Ƃŕöŵšéŕ đàţàƃàšé đŕîṽéŕ + þŕöƒîļé + ñàḿéšþàçécore/storage/driver_js.go, core/storage/sqlitejs_js.go
Šţöŕé šüîţéš üñđéŕ GOOS=jsscripts/wasm-stores/, make test-wasm-stores
Ļàƃ þŕöĵéçţ ƒöŕ ţĥé àññöţàţöŕškapi/cmd/kapi-wasm-cli/labproject.go
Šţàŕţîñĝ à đîŕéçţöŕý öṽéŕ (kapiReset)kapi/cmd/kapi-wasm-cli/reset.go, App.ForgetProjectsUnder îñ host/projectstore.go
Ţĥé çĥàñĝé çöñţŕàçţ (kapiRead, kapiApply, kapiDescribe)kapi/cmd/kapi-wasm-cli/changes.go, host/changes_call.go
Ţĥé çĥàñĝé çöñţŕàçţ šḿöķéscripts/verify-snippets/change-smoke.ts, make change-wasm-smoke
Ŕéṽéŕšé-ƃŕîđĝé çàþàƃîļîţý ţýþéšpackages/engine/src/capabilities.ts
Þàýļöàđ ţýþéš (ÇöñţéñţŢŕéé, ŕüñš, ţĥé çĥàñĝé çöñţŕàçţ)@neokapi/contract-types (ĝéñéŕàţéđ)

Ŵĥéñ àđđîñĝ àñ éñţŕý þöîñţ: àđđ îţ ţö engineExports, ţýþé îţ îñ globals.ts, šüŕƒàçé îţ öñ ţĥé ƒàçàđé îƒ üšéŕ-ƒàçîñĝ, àñđ ļéàṽé ţĥé abi ṽàļüé àļöñé (àđđîţîöñš đöñ'ţ ƃüḿþ îţ).