From 2ce3359acb2d97ed9979ae67a13325bb0eb9acb6 Mon Sep 17 00:00:00 2001 From: tiye Date: Wed, 11 Nov 2026 02:29:31 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E5=8D=87=E7=BA=A7=20Gen=20Code=20=E5=88=B0?= =?UTF-8?q?=20Calcit=200.41.0=20=E5=B9=B6=E6=94=B6=E7=B4=A7=E9=94=AE?= =?UTF-8?q?=E7=9B=98=E4=BA=8B=E4=BB=B6=E7=B1=BB=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/upload.yaml | 16 ++++- README.md | 11 ++-- calcit.cirru | 108 ++++++++++++++-------------------- config/calcit-quality.cirru | 95 ------------------------------ deps.cirru | 4 +- package.json | 4 +- tests/stream-contract.mjs | 27 ++++++--- yarn.lock | 10 ++-- 8 files changed, 95 insertions(+), 180 deletions(-) delete mode 100644 config/calcit-quality.cirru diff --git a/.github/workflows/upload.yaml b/.github/workflows/upload.yaml index cb19513..627de24 100644 --- a/.github/workflows/upload.yaml +++ b/.github/workflows/upload.yaml @@ -61,7 +61,21 @@ jobs: set -euo pipefail calcit calcit.cirru --check-only --all-defs calcit calcit.cirru fix --workflow strict --verify --format json | jq -e '.data.workflow.status == "passed" and .diagnostics == []' - calcit calcit.cirru analyze quality --baseline config/calcit-quality.cirru + calcit calcit.cirru analyze weak-types --only coverage --coverage-level none,partial --format json | + jq -e 'all(.data.definitions[]; + .coverage == "partial" and + (.id == "gen-code.schema/normalize-store-data" or .id == "gen-code.schema/read-open-field-or"))' + calcit calcit.cirru analyze weak-types --format json | + jq -e ' + .data.summary.kinds as $k | + .data.summary.intents.unresolved == 0 and + $k["code-nil"] == 0 and $k["code-dynamic"] == 0 and $k["unsafe-coerce"] <= 2 and + all(.data.definitions[]; + ([.occurrences[] | select(.kind == "unsafe-coerce")] | length) <= + (if .id == "gen-code.core/initialize-chat!" or .id == "gen-code.stream/read-genai-chunk" + then 1 else 0 end))' + calcit calcit.cirru analyze weak-types --only deprecated-call --summary-only --format json | + jq -e '.data.summary.calls == 0' - name: Test Reel state boundary run: calcit test --require-match diff --git a/README.md b/README.md index a5d591d..4ac72cc 100644 --- a/README.md +++ b/README.md @@ -2,15 +2,17 @@ Demo: https://repo.calcit-lang.org/gen-code/ -## 0.0.25 候选 +## 0.0.26 候选 -使用者需统一 Calcit CLI 和 `@calcit/procs` **0.40.0**,配对正式 +使用者需统一 Calcit CLI 和 `@calcit/procs` **0.41.0**,配对正式 UI **0.15.2**、Respo **0.19.5**、JS-FFI **0.2.13** 和传递依赖 Router **0.12.2**, 然后重新生成 JS。插件继续接收单事件派发,代码生成请求与存档行为沿用原合同。 Reel **0.11.0** 是 Demo 的开发依赖。Demo 将插件事件解码为具名 `GenCodeOp`,快捷键与面板通过独立回调接收 `Control`。流式补丁通过 `GenCodeFieldValue` union 约束为字符串或布尔值,Editor 等宿主的插件回调继续接收单个原格式操作。 内部 `call-genai-msg!` 只向回调交付补丁 Map。插件在派发边界补齐 cursor 和请求状态,生成原格式的 `:states-merge` 事件。 -验收覆盖原严格检查、质量基线、离线流式回归和构建。正式版本以通过验收后的 Git tag 为准。 +Meta+Enter 直接读取 Respo 提供的类型化键盘字段,快捷键条件与派发协议不变。 +质量检查使用 0.41.0 的 coverage、弱类型和弃用视图,继续限制两处既有 SDK 强转。 +验收覆盖完整 strict、原测试、离线快捷键与流式回归和构建。 ## 历史 0.0.22 配对 @@ -61,7 +63,8 @@ calcit edit format git diff --exit-code --quiet -- calcit.cirru calcit --check-only --all-defs calcit fix --workflow strict --verify --format json -calcit analyze quality --baseline config/calcit-quality.cirru +calcit analyze weak-types --only coverage --summary-only +calcit analyze weak-types --summary-only calcit test --require-match yarn build yarn test:stream diff --git a/calcit.cirru b/calcit.cirru index 774cde7..a548fb1 100644 --- a/calcit.cirru +++ b/calcit.cirru @@ -31,10 +31,10 @@ {} $ :style $ {} (:width 800) .render plugin-gen-code if dev? - Option :some $ comp-typed-reel (>> states :reel) reel ({}) on-control - Option :none + Some $ comp-typed-reel (>> states :reel) reel ({}) on-control + , None :examples $ [] - :schema $ quote $ Fn (reel.typed/State gen-code.schema/GenCodeOp gen-code.types/StoreData) + :schema $ quote $ Fn (reel.typed/State schema/GenCodeOp gen-code.types/StoreData) Fn reel.typed/Control $ -> Unit -> respo.schema/Component :ns $ %{} 'NsEntry (:doc |) @@ -80,13 +80,13 @@ :examples $ [] :schema $ quote Impl '*abort-control $ %{} 'CodeEntry (:doc |) - :code $ quote $ defref *abort-control (Option :none) + :code $ quote $ defref *abort-control None :examples $ [] - :schema $ quote $ Ref (calcit.core/Option gen-code.core/AbortControllerHost) + :schema $ quote $ Ref (Option AbortControllerHost) '*ai-chat $ %{} 'CodeEntry (:doc |) - :code $ quote $ defref *ai-chat (Option :none) + :code $ quote $ defref *ai-chat None :examples $ [] - :schema $ quote $ Ref (calcit.core/Option gen-code.core/GenAIChatHost) + :schema $ quote $ Ref (Option GenAIChatHost) 'AbortControllerHost $ %{} 'CodeEntry (:doc |) :code $ quote $ deftrait AbortControllerHost (:signal 'JsObject) .abort $ Fn $ -> Unit @@ -152,13 +152,6 @@ , gen-code.schema/GenCodeState :examples $ [] :schema $ quote EnumDef - 'KeyboardEventHost $ %{} 'CodeEntry (:doc |) - :code $ quote $ deftrait KeyboardEventHost - :metaKey $ JsNullish Bool - :keyCode $ JsNullish Number - :examples $ [] - :ffi $ {} (:backend :js) (:kind :external-object) (:target :browser) - :schema $ quote Trait 'call-genai-msg! $ %{} 'CodeEntry (:doc |) :code $ quote $ defn call-genai-msg! (variant prompt-text emit-patch! *text) hint-fn $ Fn Tag String @@ -215,7 +208,7 @@ , &unit :examples $ [] :schema $ quote $ Fn Tag String - Fn (Map Tag gen-code.schema/GenCodeFieldValue) (-> Unit) + Fn (Map Tag schema/GenCodeFieldValue) (-> Unit) Ref String -> Unit :features :js-ffi @@ -249,10 +242,10 @@ :code $ quote $ def initial-state schema/GenCodeState :answer | :loading? false :done? false :query | :code | :examples $ [] - :schema $ quote gen-code.schema/GenCodeState + :schema $ quote schema/GenCodeState 'initialize-chat! $ %{} 'CodeEntry (:doc |) :code $ quote $ defn initialize-chat! (variant) - reset! *ai-chat $ Option :some $ let + reset! *ai-chat $ Some $ let model $ pick-model variant doc-content $ str (include-file! |declare-task.md) sep (include-file! |format-guide.md) sep (include-file! |calcit-lang.md) sep $ include-file! |respo.md ai $ unsafe-coerce @@ -275,20 +268,12 @@ :code $ quote $ defn new-abort-controller! () js-cast (new js/AbortController) AbortControllerHost :examples $ [] - :schema $ quote $ Fn (-> gen-code.core/AbortControllerHost) (:features :js-ffi) + :schema $ quote $ Fn (-> AbortControllerHost) (:features :js-ffi) 'pick-model $ %{} 'CodeEntry (:doc |) :code $ quote $ defn pick-model (variant) match variant (:gemini |gemini-2.5-flash) (:gemini-pro |gemini-2.5-pro-preview-06-05) (:gemini-pro-1.5 |gemini-1.5-pro) (:gemini-flash-lite |gemini-2.0-flash-lite) (:gemma |gemma-3-27b-it) (_ |gemini-2.5-flash) :examples $ [] :schema $ quote $ Fn Tag (-> String) - 'read-keyboard-event $ %{} 'CodeEntry - :doc "|Check the native keyboard host members at the open Respo event boundary; this does not prove nullable field payloads." - :code $ quote $ defn read-keyboard-event (event-data) - js-cast - schema/read-open-field-or event-data :event $ {} - , 'gen-code.core/KeyboardEventHost - :examples $ [] - :schema $ quote $ Fn Dynamic (-> gen-code.core/KeyboardEventHost) (:features :js-ffi) 'send-genai-request! $ %{} 'CodeEntry :doc "|The raw Gemini SDK call is kept as a leaf FFI adapter so its capability is lexical." :code $ quote $ defn send-genai-request! (chat prompt-text abort) @@ -302,7 +287,7 @@ :abortSignal $ .-signal abort :responseMimeType |application/json :examples $ [] - :schema $ quote $ Fn gen-code.core/GenAIChatHost String gen-code.core/AbortControllerHost + :schema $ quote $ Fn GenAIChatHost String AbortControllerHost -> $ JsNullish JsObject :features :js-ffi 'send-genai-stream! $ %{} 'CodeEntry @@ -312,11 +297,11 @@ let abort $ new-abort-controller! pending $ send-genai-request! chat prompt-text abort - reset! *abort-control $ Option :some abort + reset! *abort-control $ Some abort if (js-nullish? pending) (raise "|GenAI stream response is nullish") js-cast (js-await pending) GenAIStreamHost :examples $ [] - :schema $ quote $ Fn gen-code.core/GenAIChatHost String (-> gen-code.stream/GenAIStreamHost) (:features :js-ffi) (:async) + :schema $ quote $ Fn GenAIChatHost String (-> GenAIStreamHost) (:features :js-ffi) (:async) 'sep $ %{} 'CodeEntry (:doc |) :code $ quote $ def sep (str &newline &newline |----------- &newline &newline) :examples $ [] @@ -389,12 +374,11 @@ -> Unit :async let - event $ read-keyboard-event e meta? $ .unwrap-or - js-nullish->option $ .-metaKey event + js-nullish->option $ :meta? e , false key-code $ .unwrap-or - js-nullish->option $ .-keyCode event + js-nullish->option $ :key-code e , -1 if and meta? $ = 13 key-code @@ -470,12 +454,12 @@ :inner-text $ :answer state if not $ blank? $ :code state - Option :some $ div + Some $ div {} $ :class-name css/column comp-cirru-snippet (:code state) - Option :some $ %{} respo-ui.schema/PresentationOptions - :class-name $ Option :some style-snippet - :style $ Option :none + Some $ %{} respo-ui.schema/PresentationOptions + :class-name $ Some style-snippet + :style None space-y 8 div {} $ :class-name css/row-parted @@ -487,7 +471,7 @@ -> Unit on-submit (:code state) d! , &unit - Option :none + , None assert-type (%:: GenCodePluginData :plugin render-node cursor state) 'GenCodePluginData :examples $ [] :schema $ quote $ Fn Dynamic @@ -495,7 +479,7 @@ Fn String Fn AnyEnum $ -> Unit -> Unit - -> gen-code.core/GenCodePluginData + -> GenCodePluginData :features :js-ffi :open :host :ns $ %{} 'NsEntry (:doc |) @@ -518,7 +502,7 @@ '*reel $ %{} 'CodeEntry (:doc |) :code $ quote $ defref *reel (typed/new-reel schema/store) :examples $ [] - :schema $ quote $ Ref (reel.typed/State gen-code.schema/GenCodeOp gen-code.types/StoreData) + :schema $ quote $ Ref (typed/State schema/GenCodeOp gen-code.types/StoreData) 'dispatch! $ %{} 'CodeEntry (:doc |) :code $ quote $ defn dispatch! (op) when @@ -530,7 +514,7 @@ :timestamp $ host/date-now-snapshot , &unit :examples $ [] - :schema $ quote $ Fn gen-code.schema/GenCodeOp (-> Unit) (:features :js-ffi) + :schema $ quote $ Fn schema/GenCodeOp (-> Unit) (:features :js-ffi) 'dispatch-render-event! $ %{} 'CodeEntry :doc "|Adapts the plugin's legacy event shape at the Demo render entry." :code $ quote $ defn dispatch-render-event! (op) @@ -577,7 +561,7 @@ reset! *reel $ typed/apply-control updater @*reel control , &unit :examples $ [] - :schema $ quote $ Fn reel.typed/Control (-> Unit) + :schema $ quote $ Fn typed/Control (-> Unit) 'persist-storage! $ %{} 'CodeEntry (:doc |) :code $ quote $ defn persist-storage! () println "|Saved at" $ :iso $ host/date-now-snapshot @@ -676,38 +660,38 @@ try match op (:states cursor state) - Option :some $ GenCodeOp :states + Some $ GenCodeOp :states decode-map-as cursor $ List respo.schema/CoordKey decode-map-as state 'gen-code.schema/GenCodeDraftValue (:states-merge cursor state changes) if and (struct? state) (&struct:matches? state GenCodeState) - Option :some $ GenCodeOp :states-merge + Some $ GenCodeOp :states-merge decode-map-as cursor $ List respo.schema/CoordKey assert-type state 'gen-code.schema/GenCodeState decode-map-as changes $ Map Tag gen-code.schema/GenCodeFieldValue - Option :none + , None (:hydrate-storage data) if and (struct? data) (&struct:matches? data gen-code.types/StoreData) - Option :some $ GenCodeOp :hydrate-storage $ assert-type data 'gen-code.types/StoreData - Option :none - _ $ Option :none - fn (_) (Option :none) + Some $ GenCodeOp :hydrate-storage $ assert-type data 'gen-code.types/StoreData + , None + _ None + fn (_) None :examples $ [] :schema $ quote $ Fn AnyEnum - -> $ Option gen-code.schema/GenCodeOp + -> $ Option GenCodeOp :open :decode :tests $ [] %{} 'TestEntry (:name |decodes-hydration) :code $ quote $ assert= - Option :some $ GenCodeOp :hydrate-storage store + Some $ GenCodeOp :hydrate-storage store decode-gen-code-op $ :: :hydrate-storage store %{} 'TestEntry (:name |rejects-reel-control) - :code $ quote $ assert= (Option :none) + :code $ quote $ assert= None decode-gen-code-op $ :: :reel/toggle %{} 'TestEntry (:name |rejects-invalid-hydration) - :code $ quote $ assert= (Option :none) + :code $ quote $ assert= None decode-gen-code-op $ :: :hydrate-storage $ {} 'normalize-store-data $ %{} 'CodeEntry (:doc |) :code $ quote $ defn normalize-store-data (data) @@ -740,7 +724,7 @@ :code $ quote $ defn plugin-op-to-wire (op) :: (&enum:nth op 0) & $ &enum:params op :examples $ [] - :schema $ quote $ Fn gen-code.schema/GenCodeOp (-> AnyEnum) (:open :reflect) + :schema $ quote $ Fn GenCodeOp (-> AnyEnum) (:open :reflect) 'read-open-field-or $ %{} 'CodeEntry :doc "|Read an open Map/Struct field; missing and nil values use the fallback, while false and Option payloads remain unchanged." :code $ quote $ defn read-open-field-or (value field fallback) @@ -771,14 +755,13 @@ assert= |fallback $ read-open-field-or {} $ :data nil , :data |fallback - assert= (Option :some false) + assert= (Some false) read-open-field-or - {} $ :data $ Option :some false - , :data |fallback - assert= (Option :none) - read-open-field-or - {} $ :data $ Option :none + {} $ :data $ Some false , :data |fallback + assert= None $ read-open-field-or + {} $ :data None + , :data |fallback , &unit 'store $ %{} 'CodeEntry (:doc |) :code $ quote $ def store @@ -813,12 +796,11 @@ hint-fn $ Fn (JsNullish JsObject) (-> Unit) (:features :js-ffi) match (js-nullish->option chunk) (:some value) - on-chunk! $ Option :some value - (:none) - on-chunk! $ Option :none + on-chunk! $ Some value + (:none) (on-chunk! None) , &unit :examples $ [] - :schema $ quote $ Fn gen-code.stream/GenAIStreamHost + :schema $ quote $ Fn GenAIStreamHost Fn (Option JsObject) (-> Unit) -> Unit :features :js-ffi diff --git a/config/calcit-quality.cirru b/config/calcit-quality.cirru deleted file mode 100644 index 3aba903..0000000 --- a/config/calcit-quality.cirru +++ /dev/null @@ -1,95 +0,0 @@ -{} (:schemaVersion 2) - :definitions $ {} - |gen-code.core/call-genai-msg! $ {} (:codeDynamic 0) - :codeNil 0 - :declaredOptional 0 - :deprecatedCalls 0 - :schemaDynamic 0 - :typeNone 0 - :typeNotFull 1 - :unresolved 0 - :unsafeCoerce 0 - |gen-code.core/get-gemini-key! $ {} (:codeDynamic 0) - :codeNil 0 - :declaredOptional 0 - :deprecatedCalls 0 - :schemaDynamic 0 - :typeNone 0 - :typeNotFull 0 - :unresolved 0 - :unsafeCoerce 0 - |gen-code.core/initialize-chat! $ {} (:codeDynamic 0) - :codeNil 0 - :declaredOptional 0 - :deprecatedCalls 0 - :schemaDynamic 0 - :typeNone 0 - :typeNotFull 1 - :unresolved 0 - :unsafeCoerce 1 - |gen-code.core/new-abort-controller! $ {} (:codeDynamic 0) - :codeNil 0 - :declaredOptional 0 - :deprecatedCalls 0 - :schemaDynamic 0 - :typeNone 0 - :typeNotFull 0 - :unresolved 0 - :unsafeCoerce 0 - |gen-code.core/read-keyboard-event $ {} (:codeDynamic 0) - :codeNil 0 - :declaredOptional 0 - :deprecatedCalls 0 - :schemaDynamic 0 - :typeNone 0 - :typeNotFull 1 - :unresolved 0 - :unsafeCoerce 0 - |gen-code.core/use-gen-code $ {} (:codeDynamic 0) - :codeNil 0 - :declaredOptional 0 - :deprecatedCalls 0 - :schemaDynamic 0 - :typeNone 0 - :typeNotFull 1 - :unresolved 0 - :unsafeCoerce 0 - |gen-code.schema/normalize-store-data $ {} (:codeDynamic 0) - :codeNil 0 - :declaredOptional 0 - :deprecatedCalls 0 - :schemaDynamic 0 - :typeNone 0 - :typeNotFull 1 - :unresolved 0 - :unsafeCoerce 0 - |gen-code.schema/read-open-field-or $ {} (:codeDynamic 0) - :codeNil 0 - :declaredOptional 0 - :deprecatedCalls 0 - :schemaDynamic 0 - :typeNone 0 - :typeNotFull 1 - :unresolved 0 - :unsafeCoerce 0 - |gen-code.stream/read-genai-chunk $ {} (:codeDynamic 0) - :codeNil 0 - :declaredOptional 0 - :deprecatedCalls 0 - :schemaDynamic 0 - :typeNone 0 - :typeNotFull 0 - :unresolved 0 - :unsafeCoerce 1 - :metrics $ {} (:codeDynamic 0) - :codeNil 0 - :declaredOptional 0 - :deprecatedCalls 0 - :schemaDynamic 0 - :typeNone 0 - :typeNotFull 6 - :unresolved 0 - :unsafeCoerce 2 - :scope $ {} (:includeDependencies false) - :namespace nil - :namespacePrefix nil diff --git a/deps.cirru b/deps.cirru index 97590c7..aaa380c 100644 --- a/deps.cirru +++ b/deps.cirru @@ -1,6 +1,6 @@ -{} (:calcit-version |0.40.0) - :version |0.0.25 +{} (:calcit-version |0.41.0) + :version |0.0.26 :dependencies $ {} |Respo/respo-ui.calcit |0.15.2 |Respo/respo.calcit |0.19.5 diff --git a/package.json b/package.json index bf3e482..035b980 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "dependencies": { - "@calcit/procs": "0.40.0", + "@calcit/procs": "0.41.0", "@cirru/writer.ts": "^0.1.7", "@google/genai": "^1.4.0", "cirru-color": "^0.2.4", @@ -18,6 +18,6 @@ "watch": "calcit -w calcit.cirru", "test:stream": "node tests/stream-contract.mjs" }, - "version": "0.0.25", + "version": "0.0.26", "packageManager": "yarn@4.18.0" } diff --git a/tests/stream-contract.mjs b/tests/stream-contract.mjs index 7c90b49..51c56de 100644 --- a/tests/stream-contract.mjs +++ b/tests/stream-contract.mjs @@ -4,6 +4,7 @@ import { registerHooks } from "node:module"; import { invoke_method } from "@calcit/procs"; import { consume_genai_stream_$x_ } from "../js-out/gen-code.stream.mjs"; import * as c from "../js-out/calcit.core.mjs"; +import { event__GT_edn } from "../js-out/respo.util.format.mjs"; import { _$s_abort_control, _$s_ai_chat, initial_state, new_abort_controller_$x_, use_gen_code } from "../js-out/gen-code.core.mjs"; const unwrapChunk = (chunkOption) => @@ -107,17 +108,15 @@ const fakeChat = { yield { text: '["println","|offline"]' }; }, }; -function findRunButton(element) { - if (field(element, "attrs").toArray().some( - attr => attr.get(0) === c.to_tag("inner-text") && attr.get(1) === "Run", - )) return element; +function findElement(element, matches) { + if (matches(element)) return element; for (const pair of field(element, "children").toArray()) { const node = field(pair, "node"); if (invoke_method("none?", node)) continue; const child = invoke_method("unwrap", node); if (child.tag === c.to_tag("element")) { - const button = findRunButton(child.extra[0]); - if (button) return button; + const found = findElement(child.extra[0], matches); + if (found) return found; } } } @@ -126,12 +125,24 @@ const plugin = use_gen_code( () => "", () => {}, ); -const run = findRunButton(invoke_method("render", plugin)); -assert.ok(run); +const rendered = invoke_method("render", plugin); +const run = findElement(rendered, element => field(element, "attrs").toArray().some( + attr => attr.get(0) === c.to_tag("inner-text") && attr.get(1) === "Run", +)); +const textarea = findElement(rendered, element => field(element, "name") === c.to_tag("textarea")); +assert.ok(run && textarea); +const keydown = field(field(textarea, "event"), "keydown"); +const enter = { type: "keydown", key: "Enter", code: "Enter", keyCode: 13 }; try { c.reset_$x_(_$s_ai_chat, c._PCT__$o__$o_(c.Option, c.to_tag("some"), fakeChat)); await field(field(run, "event"), "click")(null, op => { patches.push(op); }); + const keyboardPatches = []; + const emit = op => { keyboardPatches.push(op); }; + await keydown(event__GT_edn({ ...enter, metaKey: false }), emit); + assert.deepEqual(keyboardPatches, []); + await keydown(event__GT_edn({ ...enter, metaKey: true }), emit); await new Promise(resolve => setTimeout(resolve, 0)); + assert.match(field(keyboardPatches.at(-1).extra[2], "code"), /println.*offline/); } finally { c.reset_$x_(_$s_ai_chat, originalChat); c.reset_$x_(_$s_abort_control, originalAbort); diff --git a/yarn.lock b/yarn.lock index 522e8c2..19cde4a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -12,15 +12,15 @@ __metadata: languageName: node linkType: hard -"@calcit/procs@npm:0.40.0": - version: 0.40.0 - resolution: "@calcit/procs@npm:0.40.0" +"@calcit/procs@npm:0.41.0": + version: 0.41.0 + resolution: "@calcit/procs@npm:0.41.0" dependencies: "@calcit/finger-vec": "npm:0.1.1" "@calcit/ternary-tree": "npm:0.0.26" "@cirru/parser.ts": "npm:0.0.10" "@cirru/writer.ts": "npm:^0.1.9" - checksum: 10c0/4122eaa8d63fd57826d24c6c072dbd1cb6cdd2934dbfdb4fd0afc03f4aec73f07d71ccba246120c15e198134b7e92a324f1f1900b43c458b02e871354739cf84 + checksum: 10c0/5de94b39e435363d0f80611b63914c9abd6b0afac3c77adf9b9846ac439fce319ac0780697364cabf67b2997d39495a1e72086e1496ac560c51bb57462f37628 languageName: node linkType: hard @@ -1146,7 +1146,7 @@ __metadata: version: 0.0.0-use.local resolution: "root-workspace-0b6124@workspace:." dependencies: - "@calcit/procs": "npm:0.40.0" + "@calcit/procs": "npm:0.41.0" "@cirru/writer.ts": "npm:^0.1.7" "@google/genai": "npm:^1.4.0" bottom-tip: "npm:^0.1.5" From d72f7a510c6c7ef0701fc1e4f0c6d25400a92ea6 Mon Sep 17 00:00:00 2001 From: tiye Date: Wed, 11 Nov 2026 02:42:11 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E5=A4=8D=E7=94=A8=E6=B5=81=E5=BC=8F?= =?UTF-8?q?=E8=A1=A5=E4=B8=81=E6=A3=80=E6=9F=A5=E8=A6=86=E7=9B=96=20Meta+E?= =?UTF-8?q?nter=20=E6=B4=BE=E5=8F=91=E6=A0=BC=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/stream-contract.mjs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/stream-contract.mjs b/tests/stream-contract.mjs index 51c56de..1650ff4 100644 --- a/tests/stream-contract.mjs +++ b/tests/stream-contract.mjs @@ -103,6 +103,7 @@ const cursor = c._$L_(...cursorKeys); const originalChat = c.deref(_$s_ai_chat); const originalAbort = c.deref(_$s_abort_control); const patches = []; +const keyboardPatches = []; const fakeChat = { async *sendMessageStream() { yield { text: '["println","|offline"]' }; @@ -136,7 +137,6 @@ const enter = { type: "keydown", key: "Enter", code: "Enter", keyCode: 13 }; try { c.reset_$x_(_$s_ai_chat, c._PCT__$o__$o_(c.Option, c.to_tag("some"), fakeChat)); await field(field(run, "event"), "click")(null, op => { patches.push(op); }); - const keyboardPatches = []; const emit = op => { keyboardPatches.push(op); }; await keydown(event__GT_edn({ ...enter, metaKey: false }), emit); assert.deepEqual(keyboardPatches, []); @@ -148,7 +148,7 @@ try { c.reset_$x_(_$s_abort_control, originalAbort); } assert.ok(patches.length > 0); -for (const op of patches) { +for (const op of [...patches, ...keyboardPatches]) { assert.ok(invoke_method("none?", c.enum_definition(op))); assert.equal(op.tag, c.to_tag("states-merge")); assert.ok(c._$n__$e_(op.extra[0], cursor));