Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@ Demo: https://repo.calcit-lang.org/gen-code/

## 0.0.26 候选

使用者需统一 Calcit CLI 和 `@calcit/procs` **0.41.1**,配对正式
使用者需统一 Calcit CLI 和 `@calcit/procs` **0.42.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` 事件。
Meta+Enter 直接读取 Respo 提供的类型化键盘字段,快捷键条件与派发协议不变。
质量检查使用 0.41.1 的 coverage、弱类型和弃用视图,继续限制两处既有 SDK 强转。
质量检查使用 0.42.0 的 coverage、弱类型和弃用视图,继续限制两处既有 SDK 强转。
验收覆盖完整 strict、原测试、离线快捷键与流式回归和构建。

## 历史 0.0.22 配对
Expand Down Expand Up @@ -45,6 +45,8 @@ Respo **0.19.3**、JS-FFI **0.2.12** / Router **0.12.0**。消费者需统一精

`use-gen-code` 返回插件,`.render` 生成界面,`.reset-state` 向传入的 dispatch 发送一个 `:: :states cursor state` 事件。提交回调接收代码字符串和 dispatch,继续遵守单事件合同。

类型化宿主可用 `use-gen-code-with-dispatch` 并传入从 `GenCodeOp` 到宿主操作类型的转换函数。内置 Demo 直接派发具名事件。原 `use-gen-code` 仍为旧宿主发送匿名事件。

开放 Map/Struct 字段读取如实返回 Dynamic:缺失或显式 nil 使用 fallback,false 和 Option 载荷原样保留。不能直接换为会展开 Option 的 field-or。外部同名 StoreData 仅作为数据输入,转 Map、检查 states 和嵌套状态,再重建本地类型;名称不代表身份,见 [#41](https://github.com/calcit-lang/gen-code/issues/41)。

Demo 先恢复存档,再渲染和注册持久化。启动恢复清除中断请求的 loading?,保留 query、answer、code、done?,不恢复请求或 AbortController。可解析但结构不符的数据保留旧回退行为,不宣称全部坏存档都会被拒绝,见 [#38](https://github.com/calcit-lang/gen-code/issues/38)。
Expand Down
61 changes: 34 additions & 27 deletions calcit.cirru
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,18 @@
let
store $ :store reel
states $ :states store
plugin-gen-code $ use-gen-code (>> states :drafter)
plugin-gen-code $ use-gen-code-with-dispatch (>> states :drafter)
fn ()
hint-fn $ Fn $ -> String
, "|println |demo"
fn (code d!)
hint-fn $ Fn String
Fn AnyEnum $ -> Unit
Fn schema/GenCodeOp $ -> Unit
-> Unit
println "|submit code" code
fn (op)
hint-fn $ Fn schema/GenCodeOp $ -> schema/GenCodeOp
, op
assert-traits plugin-gen-code GenCodeActions
div
{} $ :class-name $ str-spaced css/preset css/global css/row
Expand All @@ -45,7 +48,7 @@
respo.comp.space :refer $ =<
reel.comp.reel :refer $ comp-typed-reel
gen-code.config :refer $ dev?
gen-code.core :refer $ use-gen-code GenCodeActions
gen-code.core :refer $ use-gen-code-with-dispatch GenCodeActions
gen-code.schema :as schema
'gen-code.config $ %{} 'FileEntry
:defs $ {}
Expand Down Expand Up @@ -322,7 +325,19 @@
:examples $ []
:schema $ quote String
'use-gen-code $ %{} 'CodeEntry (:doc "|this component can be used to integrate")
:code $ quote $ defn use-gen-code (states get-hint-code on-submit)
:code $ quote $ defn use-gen-code (states get-hint-code on-submit) (use-gen-code-with-dispatch states get-hint-code on-submit gen-code.schema/plugin-op-to-wire)
:examples $ []
:schema $ quote $ Fn StatesInput
Fn $ -> String
Fn String
Fn AnyEnum $ -> Unit
-> Unit
-> GenCodePluginData
:generics StatesInput
:features :js-ffi
:open :host
'use-gen-code-with-dispatch $ %{} 'CodeEntry (:doc |)
:code $ quote $ defn use-gen-code-with-dispatch (states get-hint-code on-submit encode-op)
let
cursor $ decode-map-as
schema/read-open-field-or states :cursor $ []
Expand All @@ -335,11 +350,11 @@
loading? $ :loading? state
wire-dispatch $ fn (dispatch!)
hint-fn $ Fn
Fn AnyEnum $ -> Unit
Fn HostOp $ -> Unit
-> $ Fn schema/GenCodeOp $ -> Unit
fn (op)
hint-fn $ Fn schema/GenCodeOp $ -> Unit
dispatch! $ gen-code.schema/plugin-op-to-wire op
dispatch! $ encode-op op
, &unit
patch-dispatch $ fn (request-state emit!)
hint-fn $ Fn schema/GenCodeState
Expand All @@ -363,14 +378,14 @@
:value $ :query state
:on-input $ fn (e d!)
hint-fn $ Fn respo.schema/RespoEvent
Fn AnyEnum $ -> Unit
Fn HostOp $ -> Unit
-> Unit
d! $ gen-code.schema/plugin-op-to-wire $ gen-code.schema/GenCodeOp :states cursor
d! $ encode-op $ gen-code.schema/GenCodeOp :states cursor
assoc state :query $ decode-map-as (schema/read-open-field-or e :value |) 'String
, &unit
:on-keydown $ fn (e d!)
hint-fn $ Fn respo.schema/RespoEvent
Fn AnyEnum $ -> Unit
Fn HostOp $ -> Unit
-> Unit
:async
let
Expand Down Expand Up @@ -398,17 +413,17 @@
a $ {} (:class-name css/link) (:inner-text |Take)
:on-click $ fn (e d!)
hint-fn $ Fn respo.schema/RespoEvent
Fn AnyEnum $ -> Unit
Fn HostOp $ -> Unit
-> Unit
d! $ gen-code.schema/plugin-op-to-wire $ gen-code.schema/GenCodeOp :states cursor
d! $ encode-op $ gen-code.schema/GenCodeOp :states cursor
assoc state :query $ str (:query state) &newline &newline $ trim (get-hint-code)
, &unit
div
{} $ :class-name $ str-spaced css/row-middle css/gap8
a $ {} (:class-name css/link) (:inner-text |Refresh)
:on-click $ fn (e d!)
hint-fn $ Fn respo.schema/RespoEvent
Fn AnyEnum $ -> Unit
Fn HostOp $ -> Unit
-> Unit
initialize-chat! :gemini
let
Expand All @@ -420,7 +435,7 @@
:style $ {} (:border-color :red) (:color :red)
:on-click $ fn (e d!)
hint-fn $ Fn respo.schema/RespoEvent
Fn AnyEnum $ -> Unit
Fn HostOp $ -> Unit
-> Unit
match (deref *abort-control)
(:some abort)
Expand All @@ -430,7 +445,7 @@
button $ {} (:class-name css/button) (:inner-text |Run)
:on-click $ fn (e d!)
hint-fn $ Fn respo.schema/RespoEvent
Fn AnyEnum $ -> Unit
Fn HostOp $ -> Unit
-> Unit
:async
let
Expand Down Expand Up @@ -467,7 +482,7 @@
button $ {} (:class-name css/button) (:inner-text |Accept)
:on-click $ fn (e d!)
hint-fn $ Fn respo.schema/RespoEvent
Fn AnyEnum $ -> Unit
Fn HostOp $ -> Unit
-> Unit
on-submit (:code state) d!
, &unit
Expand All @@ -477,10 +492,11 @@
:schema $ quote $ Fn StatesInput
Fn $ -> String
Fn String
Fn AnyEnum $ -> Unit
Fn HostOp $ -> Unit
-> Unit
Fn schema/GenCodeOp $ -> HostOp
-> GenCodePluginData
:generics StatesInput
:generics StatesInput HostOp
:features :js-ffi
:open :host
:ns $ %{} 'NsEntry (:doc |)
Expand Down Expand Up @@ -516,15 +532,6 @@
, &unit
:examples $ []
: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)
match (schema/decode-gen-code-op op)
(:some action) (dispatch! action)
(:none) (eprintln "|Unknown operation:" op)
, &unit
:examples $ []
:schema $ quote $ Fn AnyEnum (-> Unit) (:features :js-ffi) (:open :decode)
'main! $ %{} 'CodeEntry (:doc |)
:code $ quote $ defn main! ()
println "|Running mode:" $ if config/dev? |dev |release
Expand Down Expand Up @@ -589,7 +596,7 @@
:code $ quote $ defn render-app! ()
render-with! mount-target
fn () $ comp-container @*reel on-control!
, dispatch-render-event!
, dispatch!
:examples $ []
:schema $ quote $ Fn (-> Unit) (:features :js-ffi)
:ns $ %{} 'NsEntry (:doc |)
Expand Down
2 changes: 1 addition & 1 deletion deps.cirru
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

{} (:calcit-version |0.41.1)
{} (:calcit-version |0.42.0)
:version |0.0.26
:dependencies $ {}
|Respo/respo-ui.calcit |0.15.2
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"dependencies": {
"@calcit/procs": "0.41.1",
"@calcit/procs": "0.42.0",
"@cirru/writer.ts": "^0.1.7",
"@google/genai": "^1.4.0",
"cirru-color": "^0.2.4",
Expand Down
33 changes: 26 additions & 7 deletions tests/stream-contract.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ 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";
import { _$s_abort_control, _$s_ai_chat, initial_state, new_abort_controller_$x_, use_gen_code, use_gen_code_with_dispatch } from "../js-out/gen-code.core.mjs";

const unwrapChunk = (chunkOption) =>
invoke_method("none?", chunkOption) ? null : invoke_method("unwrap", chunkOption);
Expand Down Expand Up @@ -91,7 +91,7 @@ const uiImport = registerHooks({ resolve(specifier, context, nextResolve) {
return nextResolve(specifier === "virtual-dom/create-element"
? "virtual-dom/create-element.js" : specifier, context);
} });
const { dispatch_render_event_$x_, on_control_$x_, _$s_reel } = await import("../js-out/gen-code.main.mjs");
const { dispatch_$x_, on_control_$x_, _$s_reel } = await import("../js-out/gen-code.main.mjs");
const { GenCodeOp, decode_gen_code_op } = await import("../js-out/gen-code.schema.mjs");
const { Control } = await import("../js-out/reel.typed.mjs");
uiImport.deregister();
Expand Down Expand Up @@ -175,7 +175,30 @@ assert.ok(invoke_method("none?", decode_gen_code_op(
assert.ok(invoke_method("none?", decode_gen_code_op(
c._$o__$o_(c.to_tag("states-merge"), c._$L_(true), initial_state, changes),
)));
dispatch_render_event_$x_(c._$o__$o_(c.to_tag("states-merge"), cursor, initial_state, changes));
const typedPlugin = use_gen_code_with_dispatch(
c._$n__$M_(c.to_tag("cursor"), cursor, c.to_tag("data"), initial_state),
() => "typed host hint",
() => {},
op => op,
);
const take = findElement(invoke_method("render", typedPlugin), element =>
field(element, "attrs").toArray().some(
attr => attr.get(0) === c.to_tag("inner-text") && attr.get(1) === "Take",
),
);
assert.ok(take);
let takeOperation;
field(field(take, "event"), "click")(null, op => { takeOperation = op; });
assert.equal(invoke_method("unwrap", c.enum_definition(takeOperation)), GenCodeOp);
assert.equal(takeOperation.tag, c.to_tag("states"));
assert.ok(c._$n__$e_(takeOperation.extra[0], cursor));
assert.match(field(takeOperation.extra[1], "query"), /typed host hint/);

const expectedOp = c._PCT__$o__$o_(
GenCodeOp,
c.to_tag("states-merge"), cursor, initial_state, changes,
);
dispatch_$x_(expectedOp);
const recorded = c.deref(_$s_reel);
const records = field(recorded, "records");
assert.equal(invoke_method("len", records), invoke_method("len", field(before, "records")) + 1);
Expand All @@ -187,10 +210,6 @@ const state = field(nested, "data");
assert.equal(field(state, "query"), "dispatch 合成提示 🐈");
assert.equal(field(state, "loading?"), true);
const record = invoke_method("unwrap", c.nth(records, invoke_method("len", records) - 1));
const expectedOp = c._PCT__$o__$o_(
GenCodeOp,
c.to_tag("states-merge"), cursor, initial_state, changes,
);
assert.ok(c._$n__$e_(field(record, "op"), expectedOp));
on_control_$x_(c._PCT__$o__$o_(Control, c.to_tag("toggle")));
const controlled = c.deref(_$s_reel);
Expand Down
10 changes: 5 additions & 5 deletions yarn.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading