Commit Graph
495 Commits
Author SHA1 Message Date
Sycun b3d3f48c40 feat: add detailed token usage monitoring and cache write metrics 2026-10-11 22:30:30 +08:00
Ed1s0nZ 1ecbd4054c fix: reject stale concurrent interception rule saves 2026-10-10 17:18:13 +08:00
Ed1s0nZ a8321c4bff fix(vulnerability): allow standalone manual findings and validate links 2026-10-10 16:03:42 +08:00
Sycun 6a67364947 feat: add vulnerability retest branches with an isolated evidence log
Retesting a finding creates an independent conversation branch that
snapshots the source history and model trace, so verification can run
multi-turn without writing to the original session.

- POST /api/vulnerabilities/:id/retest creates the branch and persists the
  prompt, so a lost response, navigation or refresh can resume it
- new update_vulnerability_status tool closes the loop; a retest branch may
  only read and update its own finding
- {{vulnerability_id}}, {{conversation_id}} and {{source_conversation_id}}
  resolve on send, in the first turn and in follow-ups
- evidence appends to a read-only vulnerabilities.retest_log column instead
  of retest_notes: that field is operator-authored and the edit form
  rewrites it wholesale, so a routine edit used to erase the retest trail
- the retest prompt is prefilled with the operator's retest_notes, which
  already states how to verify the fix
- copied messages are re-bound as time.Time. Scanning a DATETIME column into
  a string yields RFC3339Nano while AddMessage writes the driver's
  space-separated format, and messages sort on the raw created_at text, so a
  branch rendered its new turn above the inherited history
2026-10-10 07:21:20 +08:00
Sycun e8a5392b37 fix: serialize installation updates and recover interrupted adoption and rollback 2026-10-09 10:58:12 +08:00
Sycun 54d8f1187d fix: preserve rollback binaries during ambiguous recovery and YAML settings 2026-10-09 10:27:17 +08:00
Sycun 9c6928074d fix: a rollback keeps the operator's edits, and a retry really compiles
The review found two failure paths that reported success for work the engine had
not done.

Rollback: it refused only when *non-protected* source files were modified, and
then ran `git reset --hard` to the previous commit - which discards every local
change to tracked files, not just the update's. Edits to roles/skills/tools (the
update itself keeps those via its own stash) and edits made after the update
were silently wiped, while Result said nothing: deployment.md's promise that
"work done afterwards is not swept away" did not hold. Rollback now copies every
protected file that differs right now into `.update-backup/rollback_<ts>/`
before the reset, sets the copies back after it, re-applies hand deletions, and
names what it kept in Result.KeptContent like an update does.

Retry: Apply merges and writes the state file before it builds, so a failed (or
toolchain-less) build leaves HEAD on the new commit with the old binary still in
place. The retry then took the `!snap.UpdateAvailable` no-op branch, aligned the
version and returned err=nil - the job was recorded as succeeded, the page said
"update finished", the CLI printed that source and binary were in place, and the
old executable kept running. The tree now carries a `.update-build-pending`
marker, written the moment the merge lands (and when an adoption commits to its
work tree) and cleared only after the new binary is in place. The no-op branch
reads it: with a toolchain it compiles and reports the build (commits=0,
binaryBuilt=true); without one it keeps refusing exactly like the first attempt,
so "install go and click again" is now a real instruction. The console stops
treating "nothing to pull" as "nothing to do" (the retry button stays live, the
confirm dialog and the done toast say the build is what will happen), and the
CLI's printResult no longer swallows the build-only result.

Both paths are covered by regression tests that fail on the pre-fix tree: two
rollback scenarios driven through real git (edit before and after the update, a
hand deletion), and four retry scenarios driven through a scripted go on PATH
(failed build, state-write failure, an adoption's failed build retried by the
next update, and no toolchain then toolchain).
2026-10-08 16:16:07 +08:00
Sycun 22a069849c fix: stop a finished check from freezing the update console's source form
Reported from the live installation: after opening 系统设置 → 一键更新 (the
automatic check runs) the 保存更新源 button silently stopped working — a click
produced no request at all and the server log never saw a POST.

Root cause: the busy flag is a render input — it stamps `disabled` +
`data-state-disabled` on the action buttons — but the console only ever
re-rendered *while* busy. checkForUpdates (including the automatic one) renders
on entry and again when the response lands, and withUpdateBusy never rendered
once the flag cleared, so the last render left the source-save button disabled
for good. The carrier makes it permanent: data-state-disabled tells the
platform's permission gate not to re-enable the element either. Measured in a
browser after the auto-check: the DOM carried `disabled
data-state-disabled="true"` while updateBusy was already false.

Fix: withUpdateBusy now renders symmetrically — once on entry (the form visibly
locks while an action is in flight) and once after the flag clears (usable
again, button re-enabled) — skipping the exit render only when the restart
watchdog owns the view. The transient error banner stops being an injected div
and becomes state (updateActionError) rendered by renderUpdateConsole, so the
exit render cannot wipe it; it clears when a new action starts or the console is
re-entered.

Tests: the regression follows the operator's exact chain — deferred automatic
check → the form must be enabled again → clear the address → save must reach the
server — plus a second-save check; the first fails on the old code on the
disabled markup. Verified end to end in a real browser against a scratch
installation: the render trace reads entry(busy)→response(busy)→exit(idle), and
both saves (set and clear) hit the API and land in config.yaml.
2026-10-08 15:03:44 +08:00
Sycun 069abc0a7c Merge remote-tracking branch 'origin/main' into feat/self-update
# Conflicts:
#	config.example.yaml
2026-10-08 13:59:27 +08:00
Sycun 94a18263b9 feat: make the update source one repository address, the official repo by default
The update source used to be three things - a remote name or an address, plus an
optional branch - and unset it followed whatever this directory's remotes and
upstream happened to say. That asked people to understand git topology before
they could update, and the person it was built for could not tell what "follow
the remote this tree tracks" meant. It is now one field: config.yaml update.repo,
an address, empty meaning the official repository
(https://github.com/AIPentest/CyberStrikeAI.git). Point it at a mirror (GitHub is
hard to reach in some places) or at your own fork and that is the whole
configuration.

The branch nothing is any more: an update follows the source repository's own
default branch, resolved from the source itself (ls-remote --symref HEAD), so a
fork whose default is not "main" still works and nobody has to name a branch.
Remote names, the mine/origin/upstream ranking, @{upstream} tracking and the
adopt flow's branch argument are all gone with it.

The console page loses two input fields: the source section is one address, a
hint that empty means the official repository, and a save button; clearing the
address is the way back to the default. The install facts drop the remote name,
the check section shows the source's default branch once the network answer
arrives, and the adopt entry no longer requires saving an address first - the
official default makes connecting a tarball install a zero-configuration action.

The CLI now reads the same update.repo field the page saves (LoadUpdateRepo reads
just that field, without validating the rest of the file - a broken unrelated
section must not block the path that fixes the tree), so the keyboard and the
button cannot update from different repositories. -check-update prints the source
it is about to use.

Tests: the source suite now pins the default (official), the single-address save
(including the empty-string reset), and that the followed branch comes from the
source's own default branch rather than a hardcoded "main"; the console suite
posts the one field and renders the default hint; docs, config.example.yaml and
upgrade.sh describe the one-field story.
2026-10-08 13:46:14 +08:00
Ed1s0nZ d590cdd714 fix: place accessible password visibility toggle inside login input 2026-10-08 11:52:44 +08:00
Zeyu Shao (邵泽宇) aadcdcbcfc fix(workflows): resume saving after metadata confirmation (#345) 2026-10-08 11:08:46 +08:00
Sycun 8e00147d06 增加手机端使用ui的体验和整体优化 (#344)
* feat: integrate the mobile UI runtime layer from the migration package

迁移包给出的移动端改造是「运行时注入」架构:mobile.css 只写 767.98px 以下的
规则,mobile-ui.js 在末位加载并包装 switchPage、注入抽屉/底部标签栏/更多面板。
模板侧只有 4 处接线(viewport-fit + interactive-widget、样式层链接、ELK/SheetJS
移动端延迟加载、交互层末位脚本),其余保持上游原样,桌面端零影响。

* feat: 移动端注入层接入 i18n,并把触控下限统一到 44px

迁移包的交互层把标签栏、抽屉、更多面板的文案全写死成中文,en-US/ru-RU 下会中英
混杂;现在所有注入节点统一挂 data-i18n,交给 i18n.js 的 applyTranslations 在语言
切换时自动重译,本层只保留中文兜底。语言项改为按桌面端下拉里真实存在的语言循环
(原来只在 zh/en 之间来回,俄语用户点不到),面板里的 API 文档/GitHub 不再抄一份
URL,改为触发桌面端既有控件;iOS 上没有全屏 API 时给出提示而不是静默无反应;
不在四个标签里的页面点亮"更多",否则三分之一的页面底部栏无任何高亮。

同时补齐 PWA manifest、api-docs 页移动端样式层,并把通知铃铛与头像按钮从 38px
提到本层自己的 --m-touch(44px) 口径。配 web/static/js/mobile-ui-i18n.test.cjs:
键集三方一致、引用键必须三语都有译文、helper 区之外不许出现裸写文案的 API。

* style: 移动端外壳改 iOS 观感,并修掉抽屉页脚错位

观感:顶栏/底栏改透出材质+发丝分隔线,图标按钮一律正圆去底框,文字按钮一律胶囊,
卡片 18、面板顶角 22,按压给 scale 反馈并在 prefers-reduced-motion 下关掉;焦点环
从 2px 硬描边换成 3px 柔光环(forced-colors 下把硬描边还回去)。材质一律用
color-mix 从主题自己的 --bg-primary/--border-color 派生,浅色暗色都跟随。

两处不是"不好看"而是真错:
- 抽屉页脚被 insertBefore 插到菜单上面,"返回顶部"出现在列表上方;
- 顶栏材质在暗色下被 style.css 的 html[data-theme="dark"] header 不透明渐变压住,
  只写 header 选择器不生效,改成同特异性后暗色才真正透出。
圆角与胶囊走 --m-r-icon/--m-r-btn 令牌(24 节那批 !important 规则读的就是它们),
不再往下补选择器与 !important 对轰。

配 scripts/mobile-shot.mjs:手机视口下抓外壳图,--why 用 CDP 匹配样式表回答
"规则写了没生效是没命中还是被谁压住",--eval 量真实计算值。

* fix: 抽屉页脚与底部固定件被 Safari 工具栏压在后面

iOS 的 100dvh 是「工具栏收起时」的最大视口高度,工具栏展开时可见高度只有
innerHeight。两个全屏抽屉写死 height:100dvh,于是页脚那一截正好落在 Safari
底栏后面;bottom:0 的底栏与贴底面板同理。现在抽屉改用 mobile-ui.js 每次 resize
重写的 --m-app-height,贴底固定件按 max(0px, 100dvh - 可见高度) 抬升;不支持 dvh
或桌面端抬升量恒为 0,实测默认态底栏/抽屉位置零位移。

* fix: 去掉底部标签栏里重复的「更多」入口

顶栏的 ··· 与标签栏的「更多」打开的是同一个面板。按一个入口一份实现收掉底部那枚,
标签栏只留四个页面跳转;随之清掉 more2 图标、mobile.tabMore 键与门禁里的点击断言。
落点在四个标签之外的页面不再高亮任何标签——没有「更多」可点了。

* fix: 清掉另外两处重复入口,并把同类视口缺陷扫干净

顺着「底部更多与顶栏 ··· 重复」这条线扫了一遍,还有两处同类:
- 面板里的「退出登录」与头像菜单里的退出是同一个动作两个入口,头像菜单是桌面端
  一贯的位置,去掉面板那枚;连带删掉只有它能触发的 m-danger 样式与 logout 图标。
- 抽屉页脚的「返回顶部」与面板里的返回顶部是同一个动作两个入口,且抽屉是导航容器,
  动作按钮不该住在里面;去掉整个页脚(那句"移动端导航"文案也没有信息量)。

同类视口缺陷两处:
- #m-toast 的 bottom 只算到 tabbar-h + safe,底栏按 --m-bar-bottom 抬升时提示条不抬,
  工具栏展开时会压在底栏上;实测补前后间距 16px -> 16px。
- api-docs 页容器写 min-height:100dvh,恒定比可见区高出一截,最后一行落在 Safari
  底栏后面;改成 100svh(最小视口)。

i18n 契约测试同步:header.logout / mobile.navFooter 不再被引用,mobile 命名空间 18 键。

* style: 手机端对齐 new-api 的卡片密度与 iOS 的填充式表单

仪表盘那排 KPI 在 ≤480px 被桌面样式拍成一列 116px 高的长条,手机上要滚两屏才看完
四个数字。收成两列紧凑网格(奇数张末卡通栏不留空洞),数字 26px/600 + tabular-nums
做主角,标签 12px 弱化,图标块 28px。卡片表面统一成发丝边 + 16 圆角 + 几乎看不见的
投影——桌面的双层阴影在小屏上一屏四张会散。表单改 iOS 填充式(靠底色区分字段),
聚焦只留一圈柔光环(登录框实测叠过两圈),登录卡 20 圆角 + 满宽胶囊主按钮。

KPI 按 nth-child 分的淡彩渐变是产品自己的身份,这一节不跟它抢。

* fix: 补生产侧俄语、修掉白底白字的提示条,并把逐按钮门禁跑到 PASS

用户报的两件事:
- 面板里「切换语言」只在中英之间跳 —— 不是逻辑问题,是 ~/csai-生产版 缺俄语资产
  (模板没有 ru-RU 选项、i18n/ 只有两个 json、i18n.js 是不认 ru 的旧版)。补齐后
  真手指连点验通 中→英→俄→中,且该行文字自身跟着换。
- 点面板按钮时屏幕中间冒出一块白的 —— 是我自己造成的:25.6 把提示条改成浅色材质,
  字色还是基底的 #fff,等于白底白字。回到深色 HUD 胶囊,只留一层投影。

逐按钮门禁(需要登录态,本轮首次跑通全量 34 个界面 = 31 页 + 抽屉/面板/会话抽屉展开态):
- 硬缺陷 covered/offscreen/zero/pointer-events 全 0;11 条外壳真手指点击全过;
- 小于 44px 从 79 降到 3,残留是桌面密集表格里的控件,钉进基线只降不升;
- 修掉的真缺陷:子菜单项 42px(本层自己漏的下限)、.ai-channel-manager 的
  overflow:hidden 把 4 个通道选择按钮裁到滚不进来、会话抽屉里搜索框 42/分组按钮 24 宽/
  项目行 38/折叠头 30、工具条里 <a onclick> 只有 21px 高(这些链接既没 href 也没
  onclick 属性可依赖,判据要放宽到 <a>);复选框口径统一到 24.11 一处并放大到 30px。
- 门禁自己的两个错也修了:scrollIntoView 在「外层 hidden + 内层 auto」的嵌套里根本不滚,
   造成 59 个 offscreen 假红,改成逐层滚可滚祖先模拟手指;touch+mouse 双发会让一次点击
   变成两次(抽屉开了又关),只发 touch。
- 退出码口径写死:够不到/遮挡/零尺寸/pointer-events 与自家外壳必须 0,桌面遗留小命中区
   走基线;基线被压低时注入探针验红(RATCHET FAIL ×2)后撤销复验绿。

* style: 手机端玻璃质感升级,并补上对话上传的安卓适配

观感目标从"iOS 化的平面灰底"升到玻璃质感。平底上做半透明无物可透,玻璃读不出来,
所以先造画布再上材质(mobile.css 第 28 节):
- .container 铺环境光(浅色=近白底+右上 accent/左下紫柔光,暗色=深底+更亮柔光),
  .content-area / .chat-messages 交出实心底色,半透明表面从此有色可透;
- 模糊只给小面积/瞬时件:顶栏、底栏、底部面板、抽屉、登录卡、弹窗;常驻卡片
  只做半透明+发丝边+顶缘高光,不挂模糊——固定在滚动内容上的大面积模糊是掉帧主因
  (25 节实测口径不变);浅深色全用 color-mix 从主题令牌派生,只有顶缘高光按主题
  换向;prefers-reduced-transparency 与不支持模糊的环境退回实心。
- index.html 的 mobile.css 版本号递增,防 iPhone Safari 吃旧缓存。

安卓适配:对话上传的 accept="*" 不是合法 MIME 通配(各浏览器/WebView 解析不一致),
改为 "*/*";mobile-tap-audit.mjs 新增 --ua=iphone|android,同一套门禁可换安卓 UA 复跑
(壳层按视口宽度判定、与 UA 无关,换 UA 是给"安卓浏览器下同样合格"留可复现证据)。

验证(都在生产版文件夹跑):iPhone/Android 双 UA 端到端上传(按钮 44px → 触达
选择器 → POST /api/chat-uploads 200 落盘 → 附件条渲染)PASS;双 UA 全量门禁各 34 页
PASS(硬缺陷 0、点击失败 0、44px 基线无回潮)。
2026-10-08 10:44:42 +08:00
Sycun e80668b2e9 feat: make a restart part of the one-click update, and recover the page by itself
The console now knows what it is running: the status endpoint compares the binary
identity captured at startup (size + nanosecond mtime) with the file on disk, so
an update, a rollback or a CLI run that swapped the binary without a restart is
reported as needsRestart (with the build time) - a state that used to live only in
one job's result and vanished with the process. That state grows a persistent
banner and POST /api/system/update/restart (409 when there is nothing to activate
or a job owns the tree, 400 without a hook), so a forgotten tick is one click
instead of a shell login.

The restart tick defaults to on exactly where it is safe: launchd/systemd leave
markers in the environment (XPC_SERVICE_NAME, INVOCATION_ID/JOURNAL_STREAM) and
the box follows them; an operator's own choice is never second-guessed afterwards.

While the process is down the console becomes a recovery view that probes the
status endpoint every 2 seconds: 200 means the old process still answers, a dead
socket means it is on its way out, and a 401 - only a new process can fail to know
the session - reloads the page back to #system-update. A job poll that dies during
a requested restart is the restart in flight, not a failure to toast.

Also fixed: updateT now asks i18next not to escape interpolated values, because
the console escapes at render time - the apply confirm dialog has been showing
branch names with &#x2F; ever since they contained a slash, and the new banner
showed dates the same way.

Tests: 7 new console contract tests (36 total: banner, tick default, restart
confirm/refusal, watchdog 200-vs-401, timeout copy, the in-flight poll death) plus
handler tests for the stamp and the endpoint, all mutation-probed; docs describe
the pending-restart state and the self-recovery.
2026-10-07 22:53:32 +08:00
Sycun cbd8073beb feat: move the one-click update into the system settings menu
The update console stops being a page of its own and becomes the last section
of 系统设置 (data-section="update", gated by update:read): the sidebar entry
and page-system-update are gone, the console markup lives in
settings-section-update, and the settings menu is where an operator now finds
it. #system-update keeps working as an alias - both hash parsers normalize it
to settings + the update section - so existing deep links and docs keep landing.

Polling follows the new home: leaving the settings page (router) or switching
to another section (settings.js) stops it, selecting the section loads the
console, and returning to the settings page with the section still selected
re-reads the install tree and re-arms the poller (a frozen progress read is
the "nothing is happening" picture an operator must never be shown).

The guard suite follows the move: the old nav/page assertions become "must not
exist", the new ones pin the section, the alias, the poller handoff and the
retired nav.systemUpdate key (settings.nav.update replaces it in zh/EN/RU).
README and both developer/deployment guides say 系统设置 → 一键更新.
2026-10-07 22:52:56 +08:00
Sycun 27c1ff6573 feat: give the update source a page, and the adopt flow its preview
The console page grows an update-source section: what is in effect and where it
comes from (config.yaml or the tree's own tracking), an edit form for the three
fields, and - for a directory that is not a git installation - the adopt entry.
Adopt is preview-first: the plan lists what would be replaced and what would be
kept, the confirm dialog carries the counts, and the restart tick is the same one
an update uses. A refused save shows the server's own sentence (a remote name and
an address together, an ext:: address) instead of a generic failure, and the typed
values survive the failed save and the polling redraws.

zh/EN/RU dictionaries carry the 27 new keys; the console page's contract tests
grow to 29 (source rendering and save body, the refusal path, adopt gating by
installation kind, preview-then-confirm); docs/README describe choosing a source
and connecting an unpacked installation.
2026-10-07 12:49:15 +08:00
Sycun cb8bc6b824 feat: update this installation's own source in one action
An operator running a fork has no honest way to upgrade: upgrade.sh downloads the
Release tarball of one hard-coded third-party repository and rsyncs it over the
tree, so "upgrade" means "overwrite yourself with somebody else's code", and the
safe alternative is to pull by hand and remember the build command.

internal/update drives the remote the directory already tracks: fetch, fast-forward,
go build into .update-staging, atomic rename of the binary (the previous one kept as
cyberstrike-ai.prev), and a .update-state.json so a rollback has a target that is
not guessed at. Refusals are the point - local source edits and a diverged branch
stop with the file names and commit counts in the error rather than being reset to
match, and operator-owned content (roles/skills/tools/agents/data/config.yaml) is put
aside before the merge and restored over it, with what was kept listed in keptContent
instead of quietly dropped.

Consumers: GET/POST /api/system/update* behind update:read / update:apply (mutations
are process-global, so they need a global-scope session); a console page at
#system-update with an apply button that names why it is blocked, a job polled from
the server and a rollback control; the same three actions as -check-update / -update
/ -update-rollback on the binary; OpenAPI entries for all five endpoints. Permission
gating no longer re-enables a control a page disabled for a reason of its own
(data-state-disabled), which every state-disabled, permission-gated button in the
console was subject to. upgrade.sh becomes a thin shell over the same implementation
and only falls back to the tarball path for installs that are not git work trees.

Docs and the zh/EN/RU dictionaries are updated. The package runs 13 tests against
real temporary git repositories; the HTTP layer, RBAC and the console page each
carry their own contract tests.
2026-10-07 12:07:26 +08:00
Ed1s0nZ 062fd30cd7 fix: respect limited scan goals and retain asset completion instructions 2026-10-06 03:26:31 +08:00
Ed1s0nZ 41365d4a4c fix: keep workflow labels inside node boundaries 2026-10-06 03:18:28 +08:00
Ed1s0nZ 38508e79a8 fix: keep list badges within table columns 2026-10-06 03:16:34 +08:00
Ed1s0nZ 9090e75a67 fix: retain cancellation labels after approval interruptions 2026-10-06 03:11:11 +08:00
Ed1s0nZ 054a77cdab fix: preserve task cancellation through final events 2026-10-06 03:09:04 +08:00
Ed1s0nZ 07066f9219 fix: show failed outcomes in finished batch queues 2026-10-06 03:05:25 +08:00
Ed1s0nZ 5dc9cb1541 fix: retain knowledge indexing errors and explain failure causes 2026-10-06 03:02:14 +08:00
Ed1s0nZ bb96a084e0 fix: keep related fact views in place and clarify import outcomes 2026-10-06 02:58:56 +08:00
Ed1s0nZ 7d6d3e77dc fix: restore listener edit actions and validate required fields 2026-10-06 02:54:27 +08:00
Ed1s0nZ ae395f5bf7 fix: localize asset exports and preserve import compatibility 2026-10-06 02:51:15 +08:00
Ed1s0nZ 05d7d9ec65 fix: explain password validation errors and support login preview 2026-10-06 02:49:17 +08:00
Ed1s0nZ 8550325dfe fix: validate workflows and preserve execution outcomes 2026-10-06 02:32:32 +08:00
Ed1s0nZ bdefa535b0 fix: validate form edits and enforce task result ownership 2026-10-06 02:20:28 +08:00
Ed1s0nZ 76da98944c fix: mask stored credentials and validate agent saves 2026-10-06 02:04:14 +08:00
Ed1s0nZ 4a5b177947 fix: preserve task terminal state and file navigation paths 2026-10-06 01:48:12 +08:00
Ed1s0nZ 079ba0d2b3 fix: validate login and role inputs and protect task access 2026-10-06 01:36:31 +08:00
Diznev 78973e844e feat: add Russian UI locale (#341)
Add a ru-RU language pack and a Русский entry in the language switcher so the console can be used in Russian. Dates follow the selected locale. Strings that are not translated yet fall back to English.
2026-10-05 15:07:54 +08:00
SycunandParallels 470eb5ead1 feat: add runtime storage cleanup with per-category retention (#310) (#313)
Runtime artifacts (agent workspaces, tool-output spill, C2 payloads, chat
uploads, workflow checkpoints, diagnostic logs) previously accumulated
without bound: most were only removed when a conversation or project was
deleted, and tmp/c2 plus workflow checkpoints were never removed at all.

Add a storage cleaner with named per-category tasks (Gitea-style), a
settings page tab, and a background sweep that is off by default so
upgrading never deletes existing data.

Safety properties, since mis-deleting live task data costs far more than
the disk saved:
- dry-run is the default; a real cleanup requires dry_run=false together
  with confirm=true at the API layer, not just a frontend dialog
- sessions active within active_grace_hours are always skipped, and a
  failed activity lookup skips conservatively (fail closed)
- directories whose conversation/project no longer exists are reclaimed
  as orphans after orphan_grace_days
- scanners never follow symlinks and every candidate path is confined to
  its category root; deletion renames to a .tmp-for-deletion marker first
  so a crash leaves recoverable residue instead of a half-deleted dir
- storage:* permissions are admin-only; without the grantSystemRolePermissions
  skip the default branch would have given operators an irreversible
  file-deletion right

Also fix two confirmed leaks: DeleteConversation left chat_uploads files
on disk (their rows already vanished via ON DELETE CASCADE), and workflow
checkpoints had no deletion path at all.

Co-authored-by: Parallels <parallels@kali-linux-2025-2.localdomain>
2026-09-25 14:46:23 +08:00
Ed1s0nZandCursor 38b96ec67a feat: add TypeSafe Jev as HITL audit backend
Let audit_agent approve or reject with one System One call instead of chat JSON, while keeping the OpenAI-compatible backend as an option.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-22 21:15:53 +08:00
Ed1s0nZandCursor 8da3c8c51b fix: use a closed ring for project preview task stats
Replace the small refresh-arrow icon so it no longer renders as a spike at compact sizes.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-18 17:21:01 +08:00
Ed1s0nZ f7882be546 feat: manage task process lifetimes and preserve turn history 2026-09-16 17:52:58 +08:00
Ed1s0nZ ac101d8476 feat: add batch task approval settings and fix modal dropdown scrolling 2026-09-13 18:02:43 +08:00
Ed1s0nZ 377be6492a fix: refresh navigation permissions before login and on scoped renders 2026-09-08 15:15:18 +08:00
Ed1s0nZ 6ad9ea2d13 feat: add configurable tool call blocking and monitoring 2026-09-08 09:44:32 +08:00
temp c70da22de7 Remove conversation grouping feature 2026-08-26 15:00:09 +08:00
temp fbbe984005 fix: refresh ai channel reasoning selects 2026-08-25 18:51:19 +08:00
temp abc00c1fef fix: auto-detect deepseek profile in settings 2026-08-25 18:40:49 +08:00
temp 21c6ad9bdf feat: persist hitl default config 2026-08-24 19:45:07 +08:00
temp e218316c55 Add token usage tracking and UI refinements 2026-08-24 00:05:05 +08:00
Codex a34cab431a Improve conversation preview layout 2026-08-23 20:09:56 +08:00
temp 3bcf4458c5 Fix finalization cleanup for pending tool executions 2026-08-23 19:57:17 +08:00
RuoJi6 bec2d2faf1 修复多会话任务栏抖动、会话跳回与停止失效 (#264)
* fix(web): stabilize active task ordering

* fix(chat): preserve navigation during conversation startup

* fix(tasks): guarantee hard cancellation

* fix(chat): bind navigation and hard stop targets

* fix(chat): prevent replay from reclaiming navigation
2026-08-19 13:54:30 +08:00
RuoJi6 c7cc0bc9da 修复人工审批长内容遮挡及刷新审批人状态异常 (#263)
* docs(hitl): remove stale asm_list_resources references

* fix(hitl): constrain approval layout and preserve reviewer
2026-08-19 13:31:37 +08:00