Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
77 commits
Select commit Hold shift + click to select a range
7c70cea
ci(release): deduplicate platform release gates
XingYu-Zhong Aug 4, 2026
479726b
fix(thread-actions): update message queuing logic for GUI plans
XingYu-Zhong Aug 4, 2026
8c35849
feat: implement OpenCode Go cookie resolution and subscription usage …
XingYu-Zhong Aug 4, 2026
0cfcc97
fix(ci): restore PR check baseline
luoye520ww Aug 4, 2026
4490f18
fix(ci): isolate packaged desktop smoke from updater
luoye520ww Aug 4, 2026
fe1835c
feat(preview): reveal files in system manager
luoye520ww Aug 4, 2026
5b9f00d
fix(settings): prevent provider changes from reverting
luoye520ww Aug 5, 2026
740ead1
feat(chat): redesign component prototype card with canvas import and …
XingYu-Zhong Aug 5, 2026
222d9a7
fix(workbench): restore page memory and align requirement sessions wi…
XingYu-Zhong Aug 5, 2026
cb0105f
feat(schedule): add session-level daemon threads with WeChat push
XingYu-Zhong Aug 5, 2026
a9c7c48
feat(schedule): add session-level daemon threads with WeChat push
XingYu-Zhong Aug 5, 2026
19cee57
fix(workbench): restore page memory and align requirement sessions wi…
XingYu-Zhong Aug 5, 2026
38716f7
fix(design): avoid macOS controls in prototype player
XingYu-Zhong Aug 5, 2026
a432015
feat(chat): redesign component prototype card with canvas import and …
XingYu-Zhong Aug 5, 2026
73f3e0e
feat(providers): fall back to kun-agent.com catalog when models.dev f…
XingYu-Zhong Aug 5, 2026
c210a65
Merge branch 'codex/models-dev-fallback' into develop
XingYu-Zhong Aug 5, 2026
6cd28c7
fix(cursor): forward Kun tool provider and toolKind into ToolHost exe…
XingYu-Zhong Aug 5, 2026
00b82f3
fix(kun): honor five-retry backoff budget for interrupted model streams
XingYu-Zhong Aug 5, 2026
9ac5264
fix(chat): make event replay and turn recovery monotonic
XingYu-Zhong Aug 5, 2026
2e79346
feat: add versioning support for HTML artifacts and enhance design pr…
XingYu-Zhong Aug 5, 2026
13e93f6
Merge branch 'codex/fix-llm-stream-retry-5' into develop
XingYu-Zhong Aug 5, 2026
663d289
Merge branch 'codex/session-daemon-wechat-push' into develop
XingYu-Zhong Aug 5, 2026
8be6c3f
fix(loop): align compaction budget with send-time guard
XingYu-Zhong Aug 5, 2026
b99f99e
fix(chat): repair aborted tool-call history atomically
XingYu-Zhong Aug 5, 2026
93a6f8f
Merge branch 'codex/fix-page-memory-and-requirement-session' into dev…
XingYu-Zhong Aug 5, 2026
2290a21
fix(cursor): enhance recovery run with custom tools in local context
XingYu-Zhong Aug 5, 2026
38af3f3
Merge branch 'codex/fix-llm-stream-retry-5' into develop
XingYu-Zhong Aug 5, 2026
8ef3964
fix(migration): recover blocked runtime data safely
XingYu-Zhong Aug 5, 2026
18bacd9
fix(runtime): serialize lifecycle and approval leases
XingYu-Zhong Aug 5, 2026
4654bb1
fix(loop): recover ordinary turns that stop with progress after tool …
XingYu-Zhong Aug 5, 2026
ff28d81
fix(migration): recover blocked runtime data safely
XingYu-Zhong Aug 5, 2026
7997c8d
fix(runtime): serialize lifecycle and approval leases
XingYu-Zhong Aug 5, 2026
d051896
feat(chat): show a durable compaction record in the session timeline
XingYu-Zhong Aug 5, 2026
c642f02
fix(kun): honor five-retry backoff budget for interrupted model streams
XingYu-Zhong Aug 5, 2026
a3d75c2
fix(loop): align compaction budget with send-time guard
XingYu-Zhong Aug 5, 2026
55054f0
fix(chat): make event replay and turn recovery monotonic
XingYu-Zhong Aug 5, 2026
4ce8f99
fix(sdd): add subagent return navigation
XingYu-Zhong Aug 5, 2026
05ac3b0
fix(settings): make provider mutations revision-safe
XingYu-Zhong Aug 5, 2026
2a06bc9
Merge branch 'codex/fix-page-memory-and-requirement-session' into dev…
XingYu-Zhong Aug 5, 2026
cfaaf78
fix(cursor): enhance recovery run with custom tools in local context
XingYu-Zhong Aug 5, 2026
aafaadf
feat(browser): enhance Browser Use action handling and validation
XingYu-Zhong Aug 5, 2026
ac8951a
ci(release): publish after successful builds
XingYu-Zhong Aug 5, 2026
a0eecfa
Merge branch 'codex/fix-canvas-layer-delete' into develop
XingYu-Zhong Aug 5, 2026
56e0536
fix(sdd): add subagent return navigation
XingYu-Zhong Aug 5, 2026
ef1f553
fix(settings): make provider mutations revision-safe
XingYu-Zhong Aug 5, 2026
0b7af99
fix(design): avoid macOS controls in prototype player
XingYu-Zhong Aug 5, 2026
01546ee
test(registry): make credential expiry coverage deterministic
XingYu-Zhong Aug 5, 2026
7a47b09
fix(graph): preserve control intent and bound supervision
XingYu-Zhong Aug 5, 2026
46d5d12
Merge branch 'codex/compact-timeline-record'
XingYu-Zhong Aug 5, 2026
d1bf34c
feat(providers): fall back to kun-agent.com catalog when models.dev f…
XingYu-Zhong Aug 5, 2026
6785357
Merge branch 'codex/models-dev-fallback' into develop
XingYu-Zhong Aug 5, 2026
eda29ef
fix(design): allow explicit canvas layer deletion and persist per-ver…
XingYu-Zhong Aug 5, 2026
0e97171
feat(browser): enhance Browser Use action handling and validation
XingYu-Zhong Aug 5, 2026
6c9c279
ci(release): publish after successful builds
XingYu-Zhong Aug 5, 2026
5dc0a6f
fix(chat): repair aborted tool-call history atomically
XingYu-Zhong Aug 5, 2026
d3e10b7
fix(design): allow explicit canvas layer deletion and persist per-ver…
XingYu-Zhong Aug 5, 2026
8d998e1
test(registry): make credential expiry coverage deterministic
XingYu-Zhong Aug 5, 2026
beee4fc
fix(graph): preserve control intent and bound supervision
XingYu-Zhong Aug 5, 2026
9486509
fix(cache): preserve goal and responses cache continuity
XingYu-Zhong Aug 5, 2026
1088f5b
fix(settings): make provider authority credential-aware
XingYu-Zhong Aug 5, 2026
4b4a83a
Merge branch 'codex/fix-canvas-layer-delete' into develop
XingYu-Zhong Aug 5, 2026
658d97a
fix(loop): recover ordinary turns that stop with progress after tool …
XingYu-Zhong Aug 5, 2026
f570766
fix(cache): preserve goal and responses cache continuity
XingYu-Zhong Aug 5, 2026
46db882
fix(settings): make provider authority credential-aware
XingYu-Zhong Aug 5, 2026
bd0f77b
Merge branch 'codex/session-daemon-wechat-push' into develop
XingYu-Zhong Aug 5, 2026
95f75f2
feat: add versioning support for HTML artifacts and enhance design pr…
XingYu-Zhong Aug 5, 2026
0cd58ce
fix(model): clamp effective output budget to remaining context
XingYu-Zhong Aug 6, 2026
49cc45c
fix(observability): record pre-model phases and harden runtime diagno…
XingYu-Zhong Aug 6, 2026
c7ceead
fix(runtime): restart Kun after Claude SDK provisioning (#1114)
XingYu-Zhong Aug 6, 2026
4d8ae31
feat(settings): add in-app uninstall with optional full data removal
XingYu-Zhong Aug 6, 2026
d9f3613
feat(kun): first-class explore_agent tool with lab settings and Codex…
XingYu-Zhong Aug 6, 2026
9db85db
feat:Refactor tool storm configuration and behavior
XingYu-Zhong Aug 6, 2026
3d3e6b6
fix(tests): improve cleanup logic in DaemonRuntime tests and enhance …
XingYu-Zhong Aug 7, 2026
bec4ece
feat(uninstall): include app installation path in uninstall status an…
XingYu-Zhong Aug 7, 2026
d819abd
feat(settings): update API key placeholder handling in ProvidersSetti…
XingYu-Zhong Aug 7, 2026
d5abd72
feat: enhance explore_agent tool context and improve error handling i…
XingYu-Zhong Aug 7, 2026
7e6b66a
docs(release): add v0.2.36 release notes
XingYu-Zhong Aug 7, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
320 changes: 2 additions & 318 deletions .github/workflows/daily-dev-prerelease.yml

Large diffs are not rendered by default.

309 changes: 6 additions & 303 deletions .github/workflows/pr-checks.yml

Large diffs are not rendered by default.

330 changes: 4 additions & 326 deletions .github/workflows/release.yml

Large diffs are not rendered by default.

5 changes: 4 additions & 1 deletion build/windows-installer-migration.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -388,7 +388,10 @@ function Convert-IdentityToSid([string]$Identity) {
}

function Get-FileSystemSecurity([string]$PathValue) {
$sections = [Security.AccessControl.AccessControlSections]::All
# Journal trust only depends on the owner and DACL. Requesting All would
# also read the SACL/Audit section, which ordinary user accounts cannot
# inspect without SeSecurityPrivilege.
$sections = [Security.AccessControl.AccessControlSections]::Owner -bor [Security.AccessControl.AccessControlSections]::Access
if ([IO.Directory]::Exists($PathValue)) {
return [IO.Directory]::GetAccessControl($PathValue, $sections)
}
Expand Down
2 changes: 1 addition & 1 deletion docs/KUN_CONFIG.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ GUI 启动 Kun 时会按下面的顺序合并配置。
},
"runtime": {
"streamIdleTimeoutMs": 450000,
"toolStorm": { "enabled": true, "windowSize": 8, "threshold": 3 },
"toolStorm": { "enabled": true },
"toolArgumentRepair": { "maxStringBytes": 524288 }
}
}
Expand Down
4 changes: 3 additions & 1 deletion docs/graph-mode.md
Original file line number Diff line number Diff line change
Expand Up @@ -477,7 +477,9 @@ Journal 是带 checksum 的 append-only JSONL;sequence 单调递增。snapshot
2. 过期 lease,标记缺失 worktree。
3. 对 queued/running/waiting attempt 与 child session 对账。
4. 缺失 child 变为 orphaned/interrupted,并按剩余 attempt 次数重试或升级。
5. `pausing` 收敛到 paused;缺 final summary 的 `completing` 回到 supervision。
5. `pausing` 按持久化的 `pendingControlIntent` 收敛:`pause` 进入 `paused`;
`cancel` 或旧 journal 的 `cancellation dispatch fence` 完成幂等 cleanup 后进入
`cancelled`。缺 final summary 的 `completing` 回到 supervision。
6. 写入 cleanup 和 recovery signal,再启动 scheduler。

Retention 只删除超过期限、terminal 且未被 thread reference 引用的 GraphRun。
Expand Down
11 changes: 11 additions & 0 deletions docs/kun-architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,17 @@ Kun 的缓存命中率要按 provider 原生 usage 字段优先计算和优化
重启或 resume 后 runtime usage 面板不重新从 0 计算。
- 动态上下文必须追加在稳定前缀之后。compaction、resume、fork、plan context
也不得改写稳定系统前缀。
- 自动压缩同时考虑输入压力和请求总预算:压缩触发不仅比较历史/请求输入与
soft/hard 输入阈值,还会把为模型输出保留的预算(`maxOutputTokens`)计入
`input + output` 总预算,并与发送前硬上限(上下文窗口的 85% 或模型
profile 的 hard threshold)对齐。这样输入尚未达到软阈值、但加上输出预算
已经突破发送上限(例如 1M 窗口 + 131072 输出预算)时,会在发送前强制
压缩,而不是在发送校验处直接失败。
- 最终请求只允许一次启发式兜底压缩:重新构造(图片/浏览器转发、token
economy、history hygiene)后的精确请求若仍超出 `input + output` 上限,
会基于最新持久化历史再做一次确定性启发式压缩(不调用 summary 模型、不
重复预算 reservation)并重建请求;第二次仍超限才精确失败。任何路径都
不会无限循环压缩、递归重建或把超限请求发往供应商。

冷启动第一轮可能仍然低或为 0,因为服务端还没有同一前缀可读;热起来后应稳定
超过 90%。2026-06-02 的真实 Kun 临时线程验证:
Expand Down
11 changes: 4 additions & 7 deletions docs/kun-cache-optimization.md
Original file line number Diff line number Diff line change
Expand Up @@ -146,11 +146,8 @@ Kun 也会在模型请求边界做一层共享的 history hygiene:
- `kun/src/loop/request-history-hygiene.ts`
- `kun/src/loop/agent-loop.ts`

同一 turn 内还会启用 repeat-loop guard:

- 第三次完全相同的 `(toolName, arguments)` 会被抑制。
- Kun 会写入一个 error `tool_result`,让模型收敛到更窄的查询或解释原因。
- 文件变更类工具会清掉之前的只读调用记录,避免“编辑后复读”被误判。
同一 turn 内不再抑制重复的相同工具调用:模型可以按需重试同一参数的工具,
失败原因通过 error `tool_result` 返回给模型自行收敛。

连续的内置只读工具调用会做保守并发:

Expand All @@ -162,8 +159,8 @@ Kun 也会在模型请求边界做一层共享的 history hygiene:

实现位置:

- `kun/src/loop/tool-storm-breaker.ts`
- `kun/src/loop/agent-loop.ts`
- `kun/src/loop/tool-dispatch-policy.ts`
- `kun/src/loop/tool-call-dispatcher.ts`

Fork / resume 创建新线程时也会修复克隆历史:

Expand Down
8 changes: 4 additions & 4 deletions kun/package-lock.json

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

5 changes: 4 additions & 1 deletion kun/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@
"semver": "^7.8.5",
"typescript": "5.9.3",
"typescript-language-server": "5.3.0",
"undici": "^7.28.0",
"undici": "^7.29.0",
"yauzl": "^3.4.0",
"yazl": "^3.3.1",
"zod": "^4.4.3"
Expand All @@ -112,6 +112,9 @@
},
"overrides": {
"@hono/node-server": "2.0.11",
"fast-uri": "3.1.5",
"hono": "4.13.0",
"ip-address": "10.4.0",
"@connectrpc/connect-node": {
"undici": "6.28.0"
}
Expand Down
26 changes: 25 additions & 1 deletion kun/src/adapters/file/atomic-write.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,35 @@ export async function atomicWriteFile(
}
} catch (error) {
await rm(tmp, { force: true }).catch(() => undefined)
throw error
throw describeAtomicWriteError(path, error)
}
await rm(tmp, { force: true }).catch(() => undefined)
}

/**
* Preserves Node fs error fields (`code`, `errno`, `syscall`, `path`) while
* prefixing a stable `atomic write failed (CODE) for <path>` message so
* manager/runtime logs clearly attribute disk exhaustion (ENOSPC) or
* permission failures to the exact lease/config file instead of a bare
* "Internal server error" / "fetch failed".
*/
function describeAtomicWriteError(path: string, error: unknown): unknown {
if (!(error instanceof Error)) return error
const source = error as NodeJS.ErrnoException
const code = String(source.code ?? '')
const prefixed = new Error(
`atomic write failed${code ? ` (${code})` : ''} for ${path}: ${error.message}`,
{ cause: error }
)
Object.assign(prefixed, {
...(source.code !== undefined ? { code: source.code } : {}),
...(source.errno !== undefined ? { errno: source.errno } : {}),
...(source.syscall !== undefined ? { syscall: source.syscall } : {}),
...(source.path !== undefined ? { path: source.path } : {})
})
return prefixed
}

async function renameWithRetry(
from: string,
to: string,
Expand Down
90 changes: 90 additions & 0 deletions kun/src/adapters/hybrid/hybrid-thread-projection.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import { describe, expect, it } from 'vitest'
import { makeGoalContextItem, makeUserItem } from '../../domain/item.js'
import { createThreadRecord } from '../../domain/thread.js'
import { createTurnRecord } from '../../domain/turn.js'
import { hydrateThreadItems } from './hybrid-thread-projection.js'

describe('hydrateThreadItems', () => {
it('does not rehydrate internal goal context into the public thread projection', () => {
const threadId = 'thread_goal_projection'
const turnId = 'turn_goal_projection'
const prompt = 'Continue the goal.'
const user = makeUserItem({
id: 'item_goal_user',
threadId,
turnId,
text: prompt
})
const goal = makeGoalContextItem({
id: 'item_goal_context',
threadId,
turnId,
text: 'Internal stable goal context.',
createdAt: '2026-08-06T00:00:00.000Z'
})
const thread = {
...createThreadRecord({
id: threadId,
title: 'Goal projection',
workspace: '/tmp/workspace',
model: 'test-model'
}),
turns: [createTurnRecord({
id: turnId,
threadId,
prompt,
status: 'completed'
})]
}

const hydrated = hydrateThreadItems(thread, [user, goal], {
preserveExistingItemsWhenNoFileItems: false
})

expect(hydrated.turns[0]?.items).toEqual([user])
expect(JSON.stringify(hydrated)).not.toContain('Internal stable goal context.')
})

it('filters an internal goal context from a preserved legacy item mirror', () => {
const threadId = 'thread_goal_legacy_projection'
const turnId = 'turn_goal_legacy_projection'
const prompt = 'Keep the public history.'
const user = makeUserItem({
id: 'item_goal_legacy_user',
threadId,
turnId,
text: prompt
})
const goal = makeGoalContextItem({
id: 'item_goal_legacy_context',
threadId,
turnId,
text: 'Do not expose this model-only goal context.',
createdAt: '2026-08-06T00:00:00.000Z'
})
const thread = {
...createThreadRecord({
id: threadId,
title: 'Legacy goal projection',
workspace: '/tmp/workspace',
model: 'test-model'
}),
turns: [{
...createTurnRecord({
id: turnId,
threadId,
prompt,
status: 'completed'
}),
items: [user, goal]
}]
}

const hydrated = hydrateThreadItems(thread, [], {
preserveExistingItemsWhenNoFileItems: true
})

expect(hydrated.turns[0]?.items).toEqual([user])
expect(JSON.stringify(hydrated)).not.toContain('Do not expose this model-only goal context.')
})
})
29 changes: 26 additions & 3 deletions kun/src/adapters/hybrid/hybrid-thread-projection.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { ThreadRecord } from '../../contracts/threads.js'
import { ThreadSchema } from '../../contracts/threads.js'
import type { TurnItem } from '../../contracts/items.js'
import { isPublicTurnItem, type TurnItem } from '../../contracts/items.js'
import type { Turn } from '../../contracts/turns.js'

export type ThreadMetadataLine = {
Expand All @@ -14,14 +14,37 @@ export function stripThreadItemBodies(thread: ThreadRecord): ThreadRecord {
return { ...thread, turns: thread.turns.map((turn) => ({ ...turn, prompt: '', items: [] })) }
}

function stripInternalThreadItems(thread: ThreadRecord): ThreadRecord {
let changed = false
const turns = thread.turns.map((turn) => {
const items = turn.items.filter(isPublicTurnItem)
if (items.length === turn.items.length) return turn
changed = true
return { ...turn, items }
})
return changed ? { ...thread, turns } : thread
}

export function hydrateThreadItems(
thread: ThreadRecord,
items: TurnItem[],
options: { preserveExistingItemsWhenNoFileItems: boolean }
): ThreadRecord {
if (items.length === 0) return options.preserveExistingItemsWhenNoFileItems ? thread : stripThreadItemBodies(thread)
// The session stream also contains model-only records (for example the
// stable active-goal context). A hybrid ThreadRecord is the renderer/API
// projection, so it must never rehydrate those records after a restart.
const publicItems = items.filter(isPublicTurnItem)
if (publicItems.length === 0) {
// Older hybrid snapshots can still carry their own item mirror while the
// canonical stream is absent. Preserve that public history when asked,
// but do not let a model-only item from a previous process escape through
// this fallback path.
return options.preserveExistingItemsWhenNoFileItems ? stripInternalThreadItems(thread) : stripThreadItemBodies(thread)
}
const itemsByTurn = new Map<string, TurnItem[]>()
for (const item of items) itemsByTurn.set(item.turnId, [...(itemsByTurn.get(item.turnId) ?? []), item])
for (const item of publicItems) {
itemsByTurn.set(item.turnId, [...(itemsByTurn.get(item.turnId) ?? []), item])
}
const knownTurnIds = new Set(thread.turns.map((turn) => turn.id))
const turns = thread.turns.map((turn): Turn => {
const turnItems = itemsByTurn.get(turn.id) ?? []
Expand Down
21 changes: 20 additions & 1 deletion kun/src/adapters/hybrid/hybrid-thread-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -895,7 +895,26 @@ async function yieldToEventLoop(): Promise<void> {
await new Promise<void>((resolve) => setTimeout(resolve, 0))
}

/**
* Classifies the common better-sqlite3 failure — a prebuilt `.node` binary
* compiled for a different Node/Electron ABI — so operators see the exact
* compiled vs current ABI instead of a generic "JSONL fallback" line.
*/
export function describeSqliteAbiMismatch(message: string): string | null {
const compiled = /NODE_MODULE_VERSION (\d+)/.exec(message)?.[1]
if (!compiled) return null
return `abi: compiled=${compiled} current=${process.versions.modules ?? 'unknown'} ` +
`(node ${process.version}, ${process.platform}/${process.arch})`
}

function warnSqlite(action: string, error: unknown): void {
const message = error instanceof Error ? error.message : String(error)
console.warn(`[kun] hybrid sqlite ${action} failed; using JSONL fallback: ${message}`)
const abi = describeSqliteAbiMismatch(message)
const hint = abi
? ' Run `npm rebuild better-sqlite3` (or `npm ci`) with the same Node/Electron runtime that launches Kun.'
: ' Run `npm rebuild better-sqlite3` if the module is missing or stale.'
console.warn(
`[kun] hybrid sqlite ${action} failed; using JSONL fallback: ${message}` +
`${abi ? ` [${abi}]` : ''}${hint}`
)
}
Loading
Loading