feat: publish Dever core with project scaffolding and versioned AI skills

This commit is contained in:
Antigravity committed 2026-10-04 13:37:30 +00:00
1 parent 70fa73cdc2
commit ac458ffa7f
960 files changed
+221319 -1163

No files matched your search

@@ -0,0 +1,10 @@
{
"database": {
"default": {
"type": "sqlite",
"path": "data/db/app.db",
"max_connections": 1,
"max_page_size": 100
}
}
}
+1
View File
@@ -0,0 +1 @@
@@ -0,0 +1,28 @@
# Task、Group 和 Channel 都有明确所有者;示例不启动服务或访问网络。
pause() () {
dever.time.sleep(1)
}
square(value: Int) (result: Int) pure {
result = value * value
}
send_after(channel: Channel<Int>, value: Int) () {
dever.task.sleep(1)
send(channel, value)
}
main() (task_value: Int?, grouped_value: Int?, computed: Int) {
messages = channel(Int, 1)
sender = run(send_after(messages, 7))
task_value = receive(messages)
wait(sender)
workers = group(1)
run(workers, send_after(messages, 21))
wait(workers)
grouped_value = receive(messages)
computed = parallel(square(12))
blocking(pause())
close(messages)
}
@@ -0,0 +1,10 @@
{
"database": {
"default": {
"type": "sqlite",
"path": "data/db/app.db",
"max_connections": 1,
"max_page_size": 100
}
}
}
@@ -0,0 +1 @@
@@ -0,0 +1,24 @@
connection(event: dever.net.ConnectResult.Connected(socket)) () recover("监听错误是流的最后一项,记录后结束服务") {
dever.net.timeout(socket, 5000)
dever.net.write(socket, dever.bytes.from_text("Hello from Dever\n"))
dever.net.close(socket)
}
connection(event: dever.net.ConnectResult.Failed(message)) () recover("监听错误是流的最后一项,记录后结束服务") {
blocking(dever.io.println(message))
}
serve() () {
listener = dever.net.listen("127.0.0.1", 0)
# 随机分配本机端口;最多同时处理 32 条连接。
port = dever.net.port(listener)
blocking(dever.io.println(int.to_text(port)))
stream = dever.net.connections(listener)
parallel_each(connection, stream, 32)
dever.net.close_listener(listener)
}
main() () {
serve()
}
@@ -0,0 +1,10 @@
{
"database": {
"default": {
"type": "sqlite",
"path": "data/db/app.db",
"max_connections": 1,
"max_page_size": 100
}
}
}
+1
View File
@@ -0,0 +1 @@
@@ -0,0 +1,69 @@
# 自包含后端示例:随机回环端口,只请求一次,然后排空并关闭。
type Context {
prefix: Text
requests: Channel<Int>
}
route(request: dever.http.Request, context: Context) (
response: dever.http.Response
) {
send(context.requests, 1)
response = dever.http.Response {
status = 200
headers = [dever.http.header("Content-Type", "text/plain; charset=utf-8")]
body = dever.bytes.from_text(context.prefix + request.target)
}
}
serve(listener: dever.system.Listener, context: Context) () {
dever.system.http_serve(route, listener, dever.http.default_limits(), context)
}
expired() () {
blocking(dever.io.println("服务排空超时,剩余任务已停止"))
}
count(value: Int) (text: Text) {
text = "requests = " + int.to_text(value)
}
count(value: null) (text: Text) {
text = "request channel ended"
}
main() () {
listener = dever.net.listen("127.0.0.1", 0)
port = dever.net.port(listener)
requests = channel(Int, 1)
server = run(
serve(
listener,
Context {
prefix = "Hello "
requests = requests
}
)
)
client = dever.http.client(
"http://127.0.0.1:" + int.to_text(port),
dever.tls.system(),
dever.http.default_limits(),
dever.http.default_pool_limits()
)
response = dever.http.request(
client,
dever.http.Request {
method = "GET"
target = "/Dever"
headers = []
body = dever.bytes.from_text("")
}
)
blocking(dever.io.println(dever.bytes.to_text(response.body)))
dever.net.close_listener(listener)
timeout(server, 2000, expired)
dever.http.close_client(client)
close(requests)
blocking(dever.io.println(count(receive(requests))))
}
@@ -0,0 +1,10 @@
{
"database": {
"default": {
"type": "sqlite",
"path": "data/db/app.db",
"max_connections": 1,
"max_page_size": 100
}
}
}
@@ -0,0 +1 @@
+4
View File
@@ -0,0 +1,4 @@
dever-api 4
function domain.port(Int) (port: domain.Port []) pure=true recover=None effects=[] errors=[domain.PortResult.Failed] recoveries={}
type domain.Port record construct=public {value: Int [1..65535]}
type domain.PortResult Ready(port: domain.Port []) | error Failed(message: Text [])
@@ -0,0 +1,19 @@
public type Port {
value: Int >= 1 and <= 65535
}
public type PortResult {
Ready(port: Port)
error Failed(message: Text)
}
public port(value: Int >= 1 and <= 65535) (port: Port) pure {
port = Port {
value = value
}
}
public port(value: other) (port: Port) pure {
fail(PortResult.Failed("port must be between 1 and 65535"))
}
@@ -0,0 +1,18 @@
main() (configured: domain.Port, invalid: domain.PortResult, fallback: domain.Port) pure {
configured = domain.Port {
value = 8080
}
invalid = result(domain.port(0))
fallback = configured_or_default(result(domain.port(-1)))
}
configured_or_default(result: domain.PortResult.Ready(port)) (value: domain.Port) pure recover("optional local configuration uses port 8080") {
value = port
}
configured_or_default(result: domain.PortResult.Failed(message)) (value: domain.Port) pure recover("optional local configuration uses port 8080") {
value = domain.Port {
value = 8080
}
}
@@ -0,0 +1,10 @@
{
"database": {
"default": {
"type": "sqlite",
"path": "data/db/app.db",
"max_connections": 1,
"max_page_size": 100
}
}
}
+1
View File
@@ -0,0 +1 @@
+134
View File
@@ -0,0 +1,134 @@
type Pair {
left: Int
right: Int
}
type Number {
Present(value: Int)
Missing
}
type Key {
First
Second
}
number(value: Number.Present(payload)) (answer: Int) {
answer = payload
}
number(value: other) (answer: Int) {
answer = 0
}
grade(value: Int < 0) (answer: Text) {
answer = "negative"
}
grade(value: Int >= 0 and < 10) (answer: Text) {
answer = "small"
}
grade(value: Int >= 10) (answer: Text) {
answer = "large"
}
scale(value: Int, factor: Int) (answer: Int) {
answer = value * factor
}
positive(value: Int) (answer: Bool) {
answer = value > 0
}
target(value: Int, expected: Int) (answer: Bool) {
answer = value == expected
}
parts(value: Text) (first: Text, last: Text) {
first = text.trim(value)
last = text.lower(first)
}
change(pair: Pair) (answer: Pair) {
pair.left = 99
answer = pair
}
map_key(entry: MapEntry<Text, Int>) (key: Text) {
key = entry.key
}
optional(value: Int?) (answer: Int?) {
answer = value
}
main() (
original: Int,
changed: Int,
choice: Int,
category: Text,
exact: Bool,
quotient: Decimal,
third: Decimal,
rounded: Decimal,
integer_division: Int,
remainder: Int,
selected: List<Int>,
found: Int?,
total: Int,
empty_total: Decimal,
names: Text,
ordered_keys: List<Text>,
maps_equal: Bool,
nan_equal: Bool,
finite: Bool,
optionals: List<Int?>,
key_value: Int?,
identity: Bool
) {
pair = Pair {
right = 2
left = 1
}
saved = pair
pair = change(pair)
original = saved.left
changed = pair.left
choice = number(Number.Present(7)) + number(Number.Missing)
category = grade(12)
exact = 0.1 + 0.2 == 0.3
quotient = 5 / 2
third = 1 / 3
rounded = decimal.round(2.345, 2)
integer_division = -5 // 2
remainder = -5 % 2
values = each(scale, [-1, 0, 1, 2], 3)
selected = filter(positive, values)
found = find(target, values, 3)
total = sum(scale, selected, 2)
empty_total = sum([])
split = parts(" ABC ")
names = split.first + split.last
labels = {
"first" = 1
"second" = 2
}
original_labels = labels
labels = put(labels, "first", 3)
labels = remove(labels, "first")
labels = put(labels, "first", 1)
ordered_keys = each(map_key, entries(labels))
maps_equal = labels == original_labels
nan = 0.0e0 / 0.0e0
nan_equal = [nan] == [nan]
finite = math.is_finite(float.from_int(4))
optionals = each(optional, [null, 1, null])
keys = {
Key.First = 1
Key.Second = 2
}
key_value = get(keys, Key.Second)
identity = dever.id.from_text("stable") == dever.id.from_text("stable")
}
@@ -0,0 +1,10 @@
{
"database": {
"default": {
"type": "sqlite",
"path": "data/db/app.db",
"max_connections": 1,
"max_page_size": 100
}
}
}
+1
View File
@@ -0,0 +1 @@
@@ -0,0 +1,3 @@
public greet() () {
dever.io.println("hello")
}
@@ -0,0 +1,3 @@
main() () {
app.user.greet()
}
@@ -0,0 +1,10 @@
{
"database": {
"default": {
"type": "sqlite",
"path": "data/db/app.db",
"max_connections": 1,
"max_page_size": 100
}
}
}
+1
View File
@@ -0,0 +1 @@
+19
View File
@@ -0,0 +1,19 @@
route(request: dever.http.Request) (response: dever.http.Response) {
response = dever.http.Response {
status = 200
headers = [dever.http.header("Content-Type", "text/plain; charset=utf-8")]
body = dever.bytes.from_text("Hello Dever: " + request.target)
}
}
serve() () {
listener = dever.net.listen("127.0.0.1", 0)
port = dever.net.port(listener)
blocking(dever.io.println("HTTP listening on 127.0.0.1:" + int.to_text(port)))
dever.http.serve(route, listener, dever.http.default_limits())
}
main() () {
serve()
}
@@ -0,0 +1,10 @@
{
"database": {
"default": {
"type": "sqlite",
"path": "data/db/app.db",
"max_connections": 1,
"max_page_size": 100
}
}
}
+1
View File
@@ -0,0 +1 @@
@@ -0,0 +1,11 @@
main() (json: Text) {
total = reduce(add, [1, 2, 3], 0)
json = dever.json.stringify(
dever.json.parse("{\"message\":\"你好 Dever\",\"total\":" + int.to_text(total) + "}")
)
}
add(value: Int, total: Int) (next: Int) {
next = total + value
}
@@ -0,0 +1,10 @@
{
"database": {
"default": {
"type": "sqlite",
"path": "data/db/app.db",
"max_connections": 1,
"max_page_size": 100
}
}
}
@@ -0,0 +1 @@
@@ -0,0 +1,107 @@
route(request: dever.http.Request, reply: dever.system.HttpReply) () {
path(request.target, reply)
}
path(target: "/events", reply: dever.system.HttpReply) () {
dever.sse.start(reply, [])
tick(1, reply)
tick(2, reply)
tick(3, reply)
}
path(target: "/stream", reply: dever.system.HttpReply) () {
dever.http.start(reply, 200, [dever.http.header("Content-Type", "text/plain")])
dever.http.write(reply, dever.bytes.from_text("first\n"))
dever.task.sleep(100)
dever.http.write(reply, dever.bytes.from_text("second\n"))
dever.http.finish(reply)
}
path(target: "/ws", reply: dever.system.HttpReply) () {
upgraded(result(dever.websocket.accept(reply, dever.websocket.default_limits())), reply)
}
path(target: other, reply: dever.system.HttpReply) () {
dever.http.respond(
reply,
dever.http.Response {
status = 200
headers = [dever.http.header("Content-Type", "text/plain; charset=utf-8")]
body = dever.bytes.from_text("Dever: /stream, /events, /ws")
}
)
}
tick(index: Int, reply: dever.system.HttpReply) () {
dever.task.sleep(100)
dever.sse.send(
reply,
dever.sse.Event {
event = "tick"
data = int.to_text(index)
id = int.to_text(index)
retry_ms = 1000
}
)
}
upgraded(
result: dever.websocket.ConnectResult.Connected(socket),
reply: dever.system.HttpReply
) () recover("WebSocket handshake errors are returned as HTTP 400") {
each(message, dever.websocket.messages(socket), socket)
}
upgraded(
result: dever.websocket.ConnectResult.Failed(message),
reply: dever.system.HttpReply
) () recover("WebSocket handshake errors are returned as HTTP 400") {
dever.http.respond(
reply,
dever.http.Response {
status = 400
headers = []
body = dever.bytes.from_text(message)
}
)
}
message(
event: dever.websocket.MessageEvent.Read(value),
socket: dever.system.WebSocket
) () {
echo(value, socket)
}
message(
event: dever.websocket.MessageEvent.Failed(message),
socket: dever.system.WebSocket
) () {
fail(dever.websocket.MessageEvent.Failed(message))
}
echo(value: dever.websocket.Message.Text(text), socket: dever.system.WebSocket) () {
dever.websocket.send(socket, dever.websocket.Message.Text(text))
}
echo(value: dever.websocket.Message.Binary(bytes), socket: dever.system.WebSocket) () {
dever.websocket.send(socket, dever.websocket.Message.Binary(bytes))
}
# Ping/Pong 已由协议引擎处理,应用只消费控制帧。
echo(value: other, socket: dever.system.WebSocket) () {}
main() () {
listener = dever.net.listen("127.0.0.1", 0)
port = dever.net.port(listener)
blocking(
dever.io.println("HTTP / SSE / WebSocket on 127.0.0.1:" + int.to_text(port))
)
dever.http.serve_live(
route,
listener,
dever.http.default_limits(),
dever.http.default_live_limits()
)
}
@@ -0,0 +1,10 @@
{
"database": {
"default": {
"type": "sqlite",
"path": "data/db/app.db",
"max_connections": 1,
"max_page_size": 100
}
}
}
@@ -0,0 +1 @@
@@ -0,0 +1,10 @@
# 最多两个工作线程;输出顺序不保证,parallel_each 返回时任务都已完成。
show(name: Text) () {
dever.io.println(name)
}
main() () {
parallel_each(show, ["alpha", "beta", "gamma"], 2)
dever.io.println("done")
}
@@ -0,0 +1,10 @@
{
"database": {
"default": {
"type": "sqlite",
"path": "data/db/app.db",
"max_connections": 1,
"max_page_size": 100
}
}
}
+1
View File
@@ -0,0 +1 @@
@@ -0,0 +1,20 @@
# private 隐藏表示,调用方通过操作使用 Counter;普通数据无需强行套这层封装。
public type Counter {
private value: Int
}
public start() (counter: Counter) pure {
counter = Counter {
value = 0
}
}
public increment(counter: Counter) (next: Counter) pure {
next = counter
next.value = counter.value + 1
}
public read(counter: Counter) (value: Int) pure {
value = counter.value
}
@@ -0,0 +1,7 @@
main() (before: Int, after: Int) pure {
original = counter.start()
changed = counter.increment(original)
before = counter.read(original)
after = counter.read(changed)
}
@@ -0,0 +1,9 @@
# 预期 C009:缺少 false 分句。补齐后才能覆盖全部 Bool 输入。
label(enabled: true) (text: Text) {
text = "enabled"
}
main() (text: Text) {
text = label(true)
}
@@ -0,0 +1,9 @@
# 预期 C012:赋值后丢弃失败。把失败作为命名输出返回可通过。
type Result {
error Failed(message: Text)
}
main(value: Result) () {
discarded = value
}
@@ -0,0 +1,5 @@
# 预期 C006:另一个 package 不能读取私有字段。
public read(box: secret.Box) (value: Int) {
value = box.value
}
@@ -0,0 +1,4 @@
public type Box {
private value: Int
}
@@ -0,0 +1,5 @@
# 预期 C013:输出属于副作用。需要输出时应移除 pure。
main() () pure {
dever.io.println("hello")
}
@@ -0,0 +1,11 @@
# 预期 C011:0 不能构造合法端口。改为 8080 可通过。
type Port {
value: Int >= 1 and <= 65535
}
main() (port: Port) {
port = Port {
value = 0
}
}
@@ -0,0 +1,10 @@
{
"database": {
"default": {
"type": "sqlite",
"path": "data/db/app.db",
"max_connections": 1,
"max_page_size": 100
}
}
}
@@ -0,0 +1 @@
@@ -0,0 +1,58 @@
# handler 是具名函数;reduce_until 处理当前元素后停止,不处理后面的 100。
type Summary {
total: Int
count: Int
}
double(value: Int) (result: Int) pure {
result = value * 2
}
map_values(transform: handler(value: Int) (result: Int), values: List<Int>) (
results: List<Int>
) {
results = each(transform, values)
}
add(value: Int, total: Int) (next: Int) pure {
next = total + value
}
collect(value: Int, summary: Summary) (next: Summary, stop: Bool) pure {
next = Summary {
total = summary.total + value
count = summary.count + 1
}
stop = next.total >= 6
}
main() (
mapped: List<Int>,
total: Int,
stopped: Summary,
empty_total: Int,
bytes_total: Int,
first_value: Int?,
missing: Int?
) pure {
mapped = map_values(double, [1, 2, 3])
total = reduce(add, [1, 2, 3], 0)
stopped = reduce_until(
collect,
[1, 2, 3, 100],
Summary {
total = 0
count = 0
}
)
empty_total = reduce(add, [], 0)
bytes_total = reduce(add, dever.bytes.from_text("AB"), 0)
first_value = first(mapped)
missing = get(
{
"count" = 3
},
"unknown"
)
}
@@ -0,0 +1,10 @@
{
"database": {
"default": {
"type": "sqlite",
"path": "data/db/app.db",
"max_connections": 1,
"max_page_size": 100
}
}
}
+1
View File
@@ -0,0 +1 @@
+1
View File
@@ -0,0 +1 @@
ABC
@@ -0,0 +1,21 @@
sum_byte(value: Int, total: Int) (next: Int) {
next = total + value
}
consume(event: dever.io.ReadEvent.Chunk(bytes), total: Int) (next: Int) {
next = total + reduce(sum_byte, bytes, 0)
}
consume(event: dever.io.ReadEvent.Failed(message), total: Int) (
next: Int
) {
fail(dever.io.ReadEvent.Failed(message))
}
main() (total: Int) {
file = dever.io.open("examples/old/dever/stream/input.txt")
stream = dever.io.chunks(file, 2)
total = reduce(consume, stream, 0)
close(stream)
}
@@ -0,0 +1,10 @@
{
"database": {
"default": {
"type": "sqlite",
"path": "data/db/app.db",
"max_connections": 1,
"max_page_size": 100
}
}
}
+1
View File
@@ -0,0 +1 @@
@@ -0,0 +1,11 @@
# 结果随启动参数及当前时间变化;失败以结果返回。
main() (
arguments: List<Text>,
clock: Int,
invalid_sleep: dever.time.SleepResult
) {
arguments = dever.process.arguments()
clock = dever.time.unix_millis()
invalid_sleep = result(dever.time.sleep(-1))
}
@@ -0,0 +1,10 @@
{
"database": {
"default": {
"type": "sqlite",
"path": "data/db/app.db",
"max_connections": 1,
"max_page_size": 100
}
}
}
+1
View File
@@ -0,0 +1 @@
+29
View File
@@ -0,0 +1,29 @@
# 文本下标按 Unicode 标量;解析失败和越界保留 null,不自动改成零或空字符串。
main() (
cleaned: Text,
character: Text?,
slice: Text?,
pieces: List<Text>,
joined: Text,
parsed: Int?,
invalid: Int?,
exact: Decimal?,
rounded: Decimal,
utf8: Text,
invalid_utf8: dever.bytes.DecodeResult,
invalid_byte: dever.bytes.BufferResult
) pure {
cleaned = text.lower(text.trim(" Dever "))
character = text.at("a中😀", 2)
slice = text.slice("a中😀", 1, 3)
pieces = text.split("a,,b", ",")
joined = text.join(pieces, "|")
parsed = int.parse("42")
invalid = int.parse("forty-two")
exact = decimal.parse("1.25")
rounded = decimal.round(2.345, 2)
utf8 = dever.bytes.to_text(dever.bytes.from_text("你好"))
invalid_utf8 = result(dever.bytes.to_text(dever.bytes.from_ints([255])))
invalid_byte = result(dever.bytes.from_ints([256]))
}
+10
View File
@@ -0,0 +1,10 @@
{
"database": {
"default": {
"type": "sqlite",
"path": "data/db/app.db",
"max_connections": 1,
"max_page_size": 100
}
}
}
+1
View File
@@ -0,0 +1 @@
+150
View File
@@ -0,0 +1,150 @@
# 购物车结算
计算购物车中所有商品的合计金额、优惠金额和最终应付金额。
- 包:`main`
- 公开类型:
- `Product`
- `OrderSummary`
- 公开方法:无
- 使用:无
## 商品
保存商品名称、单价和购买数量。
- 类型:`Product`
- 字段:
- `name: Text`:商品名称
- `price: Decimal`:商品单价
- `quantity: Int >= 1`:购买数量,最少为 1
```typescript dever
public type Product {
name: Text
price: Decimal
quantity: Int >= 1
}
```
## 订单结算结果
保存参与结算的商品以及各项金额。
- 类型:`OrderSummary`
- 字段:
- `items: List<Product>`:参与结算的商品
- `subtotal: Decimal`:优惠前的商品合计
- `discount: Decimal`:优惠金额
- `payable: Decimal`:最终应付金额
```typescript dever
public type OrderSummary {
items: List<Product>
subtotal: Decimal
discount: Decimal
payable: Decimal
}
```
## 计算单项商品金额
使用商品单价乘以购买数量。
- 函数:`line_total`
- 输入:
- `product: Product`:需要计算金额的商品
- 输出:
- `total: Decimal`:该商品的总金额
```typescript dever
line_total(product: Product) (total: Decimal) {
total = product.price * product.quantity
}
```
## 汇总商品金额
计算商品列表中所有商品的金额总和。
- 函数:`sum_products`
- 输入:
- `products: List<Product>`:需要汇总的商品列表
- 输出:
- `subtotal: Decimal`:所有商品的合计金额
```typescript dever
sum_products(products: List<Product>) (subtotal: Decimal) {
subtotal = sum(line_total, products)
}
```
## 结算订单
根据商品列表和会员应付比例计算订单结果。
- 函数:`checkout`
- 输入:
- `products: List<Product>`:需要结算的商品列表
- `member_rate: Decimal`:会员实际应付比例,例如 0.90
- 输出:
- `summary: OrderSummary`:订单结算结果
```typescript dever
checkout(products: List<Product>, member_rate: Decimal) (summary: OrderSummary) {
subtotal = sum_products(products)
payable = decimal.round(subtotal * member_rate, 2)
discount = subtotal - payable
summary = OrderSummary {
items = products
subtotal = subtotal
discount = discount
payable = payable
}
}
```
## 运行购物车示例
创建商品列表,并以九折会员价格完成结算。
- 函数:`main`
- 输入:无
- 输出:
- `customer: Text`:客户名称
- `summary: OrderSummary`:客户的订单结算结果
```typescript dever
main() (customer: Text, summary: OrderSummary) {
customer = "小明"
products = [
Product {
name = "笔记本"
price = 12.50
quantity = 3
},
Product {
name = "签字笔"
price = 5.00
quantity = 2
}
]
summary = checkout(products, 0.90)
}
```
### 执行
```bash
deverc check examples/old/markdown --entry app.main
deverc fmt examples/old/markdown --check
deverc run examples/old/markdown app.main
```
结算结果:
| 项目 | 金额 |
| --- | ---: |
| 商品合计 | 47.50 |
| 优惠金额 | 4.75 |
| 应付金额 | 42.75 |