Compare commits

..

392 Commits

Author SHA1 Message Date
john a5d109d585 fix(page-data): grant agent role set permission 2026-07-17 09:32:31 +08:00
john 331a863288 merge: fix goosed release dependency check
Memind CI / Test, build, and release guards (push) Successful in 7m27s
2026-07-16 22:37:58 +08:00
john 486e25f86b fix(release): validate composed goosed containers 2026-07-16 22:37:50 +08:00
john f4bc716789 merge: bundle MindSearch MCP runtime
Memind CI / Test, build, and release guards (push) Successful in 2m23s
2026-07-16 22:29:01 +08:00
john 3cafadba5a fix(runtime): bundle MindSearch MCP for production 2026-07-16 22:26:47 +08:00
john 122e478894 merge: pnpm release dependency lock
Memind CI / Test, build, and release guards (push) Successful in 2m54s
2026-07-16 21:44:53 +08:00
john 7b0f269180 fix: lock patched dependencies for pnpm release builds 2026-07-16 21:44:49 +08:00
john c7e4a063bf merge: production dependency security patches
Memind CI / Test, build, and release guards (push) Successful in 2m34s
2026-07-16 21:41:55 +08:00
john fe5d32b451 fix: patch production dependency vulnerabilities 2026-07-16 21:41:40 +08:00
john 30fcbaf613 ci: install locked sharp arm64 runtime
Memind CI / Test, build, and release guards (push) Successful in 3m9s
2026-07-16 21:37:28 +08:00
john e0d4868908 ci: install sqlite test dependency
Memind CI / Test, build, and release guards (push) Failing after 1m15s
2026-07-16 21:34:21 +08:00
john e7d5c09e56 ci: fetch parent for patch validation
Memind CI / Test, build, and release guards (push) Failing after 1m10s
2026-07-16 21:32:21 +08:00
john 475328830a ci: remove external action dependencies
Memind CI / Test, build, and release guards (push) Failing after 1m15s
2026-07-16 21:29:51 +08:00
john 5674d53a64 ci: verify main before production release
Memind CI / Test, build, and release guards (push) Failing after 2s
2026-07-16 21:19:04 +08:00
john 6250b5989c refactor(api): split MindSpace agent jobs client 2026-07-16 21:16:40 +08:00
john ddb3a330f4 refactor(api): split Page Data client 2026-07-16 21:16:40 +08:00
john 8ac159a5ed refactor(api): split MindSpace publication client 2026-07-16 21:15:44 +08:00
john f6dcf5b14a refactor(api): split MindSpace client modules 2026-07-16 21:15:44 +08:00
john f2d0c99f6c fix(ui): support legacy prompts and publication confirmation 2026-07-16 21:15:44 +08:00
john 77f1ea8350 fix(ui): harden product-facing interaction flows 2026-07-16 21:15:44 +08:00
john 4e6abacce1 fix(memory): mark recalled context as untrusted 2026-07-16 21:09:21 +08:00
john 1f7b288a21 fix(analytics): keep readable owner labels server-side 2026-07-16 21:09:20 +08:00
john 320945a485 feat(mindspace): add opt-in local analytics 2026-07-16 21:07:17 +08:00
john 6e460336f7 feat(memory): add gated agent recall and lifecycle controls 2026-07-16 21:07:17 +08:00
john c1012da120 fix(chat): recover active requests and preserve finish order 2026-07-16 21:07:17 +08:00
john 933466c8ab fix: preserve chat order and published page scripts 2026-07-15 14:05:09 +08:00
john b3337c9643 merge: integrate optional MindSearch orchestration 2026-07-15 13:46:51 +08:00
john 5f1c4dcaca feat: add optional MindSearch skill orchestration 2026-07-15 13:46:17 +08:00
john 07f1ad0a6e fix: wait for imgproxy compat health on release 2026-07-15 11:58:01 +08:00
john 3695fecbb6 fix: use explicit docker path in imgproxy release 2026-07-15 11:53:06 +08:00
john 72f1266078 fix: make imgproxy artifact checksums portable 2026-07-15 11:48:09 +08:00
john dd0014db83 fix: reuse local imgproxy image during release 2026-07-15 11:39:02 +08:00
john e2d850c2e9 fix: require exact main release branch for imgproxy 2026-07-15 11:31:43 +08:00
john 3eee44ef5b feat: add reproducible imgproxy runtime release 2026-07-15 11:25:32 +08:00
john 87b03f7848 merge: integrate agent-run page delivery hardening 2026-07-15 10:56:35 +08:00
john a07cf07861 fix(page-data): isolate owner API from public pages 2026-07-15 10:56:22 +08:00
john 72fd88219c fix(mindspace): fail closed on invalid page data delivery 2026-07-14 19:40:47 +08:00
john 192548b0b9 merge: integrate hybrid published page delivery 2026-07-14 19:13:17 +08:00
john 27b11894f2 feat(mindspace): gate published page delivery 2026-07-14 19:13:01 +08:00
john ae9090948a fix(mindspace): relax published page CSP so agent HTML interactions work
Switch default MindSpace HTML delivery to a hybrid inline CSP so onclick handlers and addEventListener pages both run under real HTTP headers, and add Playwright interaction verify beyond HTTP 200 checks.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-13 15:39:39 +08:00
john 6ef3ea89c6 merge: integrate feature/0713-dev into main
# Conflicts:
#	mindspace-page-data-finish-guard.mjs
#	page-data-delivery-assess.mjs
2026-07-13 15:33:45 +08:00
john a6620fb719 feat(mindspace): enforce PostgreSQL user data delivery 2026-07-13 15:29:29 +08:00
john b33c943b69 feat(memory-v2): auto-accept candidate memories in active and canary modes
Let Personal Memory candidates pass policy gates without per-user manual review, while keeping shadow mode for explicit human approval.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-13 14:16:57 +08:00
john 7f7aced751 feat(runtime): wire personal memory observation and skill runtime config
Hook shadow pipeline observation into session finish and agent runs, and
expose skill runtime settings through auth and runtime status endpoints.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-13 14:00:11 +08:00
john a867592367 feat(skill-runtime): restore admin config and manifest keyword routing
Recover skill runtime policy/admin services and Skill Router v2 helpers so
admins can toggle manifest routing and inspect the platform skill catalog.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-13 13:59:59 +08:00
john e90a2da6cb feat(memory-v2): restore personal shadow pipeline and candidate store
Recover WIP modules from stash so admin can persist capability config,
observe chat writes in shadow mode, and review persisted candidates.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-13 13:59:51 +08:00
john 804f13bc04 fix(page-data): harden structural delivery and Portal base URL
Reject /api/page-data/ legacy passthrough, verify live API before send,
and resolve delivery links to Portal (8081) instead of Vite (5173).
Add local repair/verify scripts for daily-register Page Data flow.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-13 09:35:40 +08:00
john 249b0697cb fix(page-data): scope finish guard to current delivery 2026-07-13 06:56:27 +08:00
john cdeb24ba92 fix(page-data): import ensurePageDataHtmlPagesBound in server bootstrap
The bundled portal runtime crashed on boot because workspace deliver referenced
ensurePageDataHtmlPagesBound without importing it from page-data-workspace-ensure.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-13 00:25:02 +08:00
john fb055c6721 fix(page-data): bind Page Data pages structurally on deliver, not by intent
Finish/sync now auto-registers datasets and binds any HTML using page-data-client.js
before publication, so user confirmation cannot publish unbound collect pages.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-13 00:18:49 +08:00
john da422a82e6 fix(wechat): restore session routing exports after merge
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-12 22:44:18 +08:00
john 7005b501af Merge branch 'hotfix/page-data-wechat-complete' 2026-07-12 22:43:46 +08:00
john 502334777e fix(page-data): trust live API smoke and WeChat survey submit compat
Stop blocking WeChat delivery when Page Data insert works but publish
quota blocks h5_publish_records; fix smoke URL missing /api; patch survey
radios for WeChat X5 and detect dataset constants in admin pages.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-12 22:43:42 +08:00
john 16fd99e8ba fix(page-data): trust live API smoke and WeChat survey submit compat
Stop blocking WeChat delivery when Page Data insert works but publish
quota blocks h5_publish_records; fix smoke URL missing /api; patch survey
radios for WeChat X5 and detect dataset constants in admin pages.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-12 22:42:47 +08:00
john 2f7bc3b6e4 fix(csp): allow page-data-client.js in WeChat WebView
WeChat UA uses a relaxed inline CSP without 'self', which blocked
/assets/page-data-client.js and broke public survey submissions.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-12 22:21:57 +08:00
john ca4805533b fix(wechat): isolate page data sessions 2026-07-12 21:13:45 +08:00
john cef3750ac6 fix(page-data): require registered datasets before binding 2026-07-12 18:39:13 +08:00
john 67d529c81e fix(mindspace): keep standalone service data paths under MindSpace root
Prevent Portal .env from overriding MindSpace storage/users roots, and
set launchd env plus runtime docs to use /Users/john/MindSpace paths.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-12 18:06:16 +08:00
john f9561cd91d fix(mindspace): use UUIDs for repair replies 2026-07-12 15:53:11 +08:00
john 73b308af0a fix(page-data): enforce full workspace bind delivery and repair tooling
Prevent false-positive Finish Guard passes and sync-created fake bindings by assessing publication, policy, dataset, injection, and insert smoke before H5 delivery.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-12 15:30:52 +08:00
john f437a37660 fix: import consumeSessionEventsUntilFinish for H5 agent runs
H5 chat via POST /api/agent/runs failed with ReferenceError after the
session Finish alignment change; restore the missing import from
session-reply-wait.mjs.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-12 14:47:36 +08:00
tkmind 5704cb11b0 Merge pull request 'fix(page-data): deliver MindSpace workspace URLs for questionnaires' (#9) from release/0712-portal-prep into main
Merge pull request #9: fix(page-data) deliver MindSpace workspace URLs for questionnaires
2026-07-12 06:03:42 +00:00
john b86ce98d6f merge: sync origin/main before portal release 2026-07-12 13:54:27 +08:00
john 294e331a03 fix(page-data): deliver MindSpace workspace URLs instead of /u/.../pages/ routes.
Page Data questionnaires were returning publication slugs to users; password-mode
pages always fell back to /u/ routes. Prefer MindSpace paths at publish time and
rewrite mistaken delivery links in WeChat and Portal chat.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-12 13:54:24 +08:00
john ee3e405fc7 Merge branch 'codex/portal-resvg-linux-arm64' 2026-07-12 12:19:11 +08:00
john 048f25f580 feat(miniapp): add privacy consent and legal pages
Show privacy popup on launch, gate login on legal consent, and link
user agreement and privacy policy pages in the mini program.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-12 12:18:54 +08:00
john 8928827291 Merge branch 'codex/0708-dev' 2026-07-12 12:18:51 +08:00
john 4e36b77237 Merge branch 'codex/asset-gateway-foundation' 2026-07-12 12:18:51 +08:00
john dc7b440bfb Merge branch 'hotfix/mindspace-url-canonical-0710' 2026-07-12 12:18:51 +08:00
john fdc2712084 fix: bundle Linux ARM64 resvg runtime dependency 2026-07-12 12:04:02 +08:00
john 680d28ac4b fix: reject missing local mindspace cover files 2026-07-12 10:15:26 +08:00
john f4d9897072 feat: add optional asset gateway control plane 2026-07-12 09:51:13 +08:00
john 7dd6b060f7 merge: stabilize MindSpace local workflows 2026-07-12 08:14:13 +08:00
john a3f669d4e7 fix: stabilize MindSpace local workflows
Signed-off-by: john <cynell@139.com>
2026-07-12 08:12:15 +08:00
john 03a79322e4 Merge origin/main into feature/0711-dev before landing schedule reminder fix. 2026-07-12 08:11:50 +08:00
john 97d0e8d970 fix(schedule): auto-create reminders when agent only writes schedule items
When schedule_create_item includes a start time and reminder intent, create the
matching h5_schedule_reminders row in the same tool call so 10:00 pushes are not
lost. Also reconcile Goose SSE request ids with the portal agent-run gate to keep
MindSpace chat streaming reliable.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-12 08:11:43 +08:00
john 57a60d41d7 fix(miniapp): persist session token for WeChat login
Return sessionToken from login endpoints and store it client-side because
wx.request cannot rely on Set-Cookie. Also fix multi-cookie parsing,
start on login page, and guard chat rendering fields.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-11 13:05:44 +08:00
john 3163445a9d fix(miniapp): inline createUuid in config to fix DevTools require
WeChat DevTools failed to resolve utils/uuid.js at runtime; move UUID
generation into config.js which is already loaded by app.js.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-11 13:02:34 +08:00
john c842119929 fix(miniapp): add missing uuid and message-display utils
Commit the utility modules required by api.js, messages.js, and chat page
so WeChat DevTools can resolve require('./uuid') at runtime.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-11 13:01:05 +08:00
john 04ef1c9105 feat(auth): add WeChat mini program login endpoint
Add jscode2session exchange, CSRF bypass for servicewechat.com,
and openid-based auto register/login for the mini program client.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-11 12:41:37 +08:00
john fe6d631ba1 fix(miniapp): declare miniprogram root 2026-07-11 09:50:29 +08:00
john b17b2f18cb fix(miniapp): point API client at portal domain 2026-07-11 09:32:33 +08:00
john 0fd34a5644 feat(miniapp): improve session navigation and auth guard 2026-07-11 08:51:30 +08:00
john 9e5a59b7d9 feat(miniapp): scaffold WeChat mini program MVP 2026-07-11 08:46:08 +08:00
john 32fb2cdeaf feat: chat uploads, vision turn isolation, and MindSpace agent improvements
Add chat file/image upload UX, attachment proxying, vision thumbnails, and per-turn image scoping so agents only use the current upload. Extend MindSpace asset context, billing token state, OA/scenario verify scripts, and related runtime config.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-11 00:23:01 +08:00
john e3063ea806 fix(mindspace): refresh published HTML after workspace sync
Keep online publication snapshots aligned when public/*.html changes, default static page binds to public access with MindSpace delivery URLs, and split browser-safe workspace helpers out of the Vite import chain.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-10 20:44:04 +08:00
john 7f8d692d16 fix(agent): recover stale runs and improve new-user OA delivery
Fix DEV logout cookie clearing, materialize selected MindSpace OA assets before agent runs, and recover zombie runs from synced workspace pages. Add client run wait timeout, harness retry limits, page-edit asset forwarding, and logout/john2 scenario tests.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-10 20:05:52 +08:00
john 880cd59ca5 fix(mindspace): link inline public html paths 2026-07-10 11:53:03 +08:00
john adc13a167e fix(mindspace): canonicalize public page links without MindSpace segment 2026-07-10 11:39:21 +08:00
john aede1e6fcb fix(mindspace): guard published pages against blocked CDN scripts
Pre-bundle Chart.js, auto-rewrite common CDN references at publish and serve time, and block unknown external script src during publication scans so interactive dashboards keep working under CSP.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-10 10:27:42 +08:00
john eea14c1855 Add page data delivery and publication guards 2026-07-08 21:10:47 +08:00
john 8d629e7a4e feat(page-data): owner CRUD, public read, and role policy UI
Expose owner PATCH/soft-delete routes, allow anonymous read/stats on
public pages when policy enables read, and add login_required role
editor to the ops panel with tests and doc updates.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-08 14:54:14 +08:00
john 6b0c633a75 feat(page-data): complete Phase 4-5, ops UI, and publish integration
Add visitor roles, row-level scope, owner ops APIs, MySQL policy index,
Turnstile captcha, browser client SDK, publish-panel dataset binding,
acceptance tests, and usage documentation.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-08 14:52:49 +08:00
john 8d01553469 feat(page-data): add private and public dataset API (phase 1-3)
Extract UserDataSpaceService for shared SQLite access, wire logged-in Page
Data routes, and add public insert plus password-token read/update/delete with
policy storage, rate limits, and regression tests.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-08 12:44:23 +08:00
john 1c8e0db256 docs: clarify development release gates 2026-07-08 12:25:27 +08:00
john ea25058db8 docs: add page data api access plan 2026-07-08 12:25:02 +08:00
john 31742f914e Add 103 H5 rich page rollout runbook 2026-07-08 10:33:23 +08:00
john fd364dbbeb fix(plaza): correct similar recall query params 2026-07-07 16:55:38 +08:00
john ea4c6b707c fix(chat-intent): prefer pages for rich publishable content 2026-07-07 15:40:03 +08:00
john 5da4dac16a Merge branch 'codex/reminder-llm-toggle' 2026-07-07 12:10:37 +08:00
john 81967eaf8c Add wechat reminder LLM toggle 2026-07-07 12:10:21 +08:00
john 1e4f432754 fix(chat): 阻止同会话并发 Agent Run 导致消息错乱
前端 submit 改用 chatStateRef 同步拦截连发;后端 createRun 检测同 session 活跃任务并返回 409,避免多条回复交错落库。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-07 11:48:59 +08:00
john ac520d8ae5 fix(mindspace-public): 公开页区分作者与访客视图 + 图片加载自动重试
工作区直链 /MindSpace/<userId>/public/*.html 此前对所有人(含匿名访客、
转发链接收到的其他登录用户)展示完全相同的悬浮操作按钮,导致非作者也能
看到"发布 Plaza"入口——而 Plaza 发布会把内容归属到操作者自己的账号下,
必须只对作者开放。

- server.mjs: serveUserPublishFile 用现有 session/cookie 鉴权判断访问者是
  否等于 URL 中的 ownerKey,结果透传给 sendPublishFile;该响应内容因人
  而异,显式加 Cache-Control: private, no-store(原来未设置任何缓存头)
- mindspace-public-share-widget.mjs: injectPublicFileShareButton 新增
  isOwner 参数(默认 true 保持兼容),非作者时隐藏"发布 Plaza"按钮与确认
  弹窗,"保存长图"/"公开分享"对所有访客保留
- mindspace-public-delivery.mjs: 透传 isOwner,并注入图片重试脚本
- mindspace-public-image-retry.mjs(新增): 页面级 onerror 之前用捕获阶段
  监听拦截 mindspace 资产图片的加载失败,带退避自动重试 3 次,避免刚生成
  页面时的资产物化竞态被"永久占位符"放大成显示故障

本地起服务用 owner / 非 owner 已登录用户 / 匿名访客三种身份实测验证。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-07 10:56:26 +08:00
john b4171ca268 chore(test): 新增统一测试入口与端到端场景模拟脚本
- scripts/run-memind-tests.mjs:按改动文件自动匹配 test + verify 范围
  (quick/changed/guards/release/full 模式),配套 memind-test skill
- scripts/run-scenario-test.mjs + scenario-test-lib.mjs:真实登录 + 多轮
  聊天 + 页面生成 + 公网可访问性的端到端模拟,配套 memind-scenario-test
  skill 与首个场景 scenarios/suzhou-page.json
- package.json 新增 test:memind / test:scenario 脚本别名

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-07 10:56:26 +08:00
john ec8d0464a3 fix(chat-intent): 隐式攻略/页面生成请求直接路由到 static-page-publish
短句如"苏州攻略页面"此前会被规则/LLM 误判为 product-campaign-page(先追问
促销信息),导致用户体验成"卡住不动"。规则层扩大页面生成意图识别,并新增
coercePageGenerationSkill 在 LLM 判为 product-campaign-page 但明显是内容页
时强制纠正为 static-page-publish,避免不必要的追问。同步更新两个技能文档
的适用边界说明。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-07 10:56:26 +08:00
john 7edafefc56 fix(mindspace): 生成页面统一使用中文友好无衬线字体
页脚品牌行、纯文字页面模板与技能提示词此前用 Georgia/Times 衬线体,中文渲染
效果差;统一改为系统无衬线字体栈(PingFang SC / Microsoft YaHei 等)。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-07 10:56:26 +08:00
john 0d6258d00a chore: remove mm.tkmind.cn references 2026-07-07 10:01:32 +08:00
john cf04e73f51 docs(ops): 同步 103 生产 goosed 扩容为 9 实例
确认 goosed-prod-1..9 映射 18006-18014,更新 topology、发包必看、
发布 skill 与 release 脚本的动态 pool 校验。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-07 09:22:40 +08:00
john 5485cc563b merge origin/main: 合并 runtime bundle 修复与本地图片物化/build 修复 2026-07-07 09:09:32 +08:00
tkmind 0edd531ed9 Merge pull request 'fix(ops): 将 goose session postgres ensure 脚本打入 runtime 包' (#8) from fix/goose-session-postgres-runtime-bundle into main 2026-07-06 09:11:59 +00:00
john 84bc03c9ba fix(ops): 将 goose session postgres ensure 脚本打入 runtime 包
发版后 Portal live 目录为无源码 runtime,ensure 脚本需随包发布;文档与发布检查改为引用 goosed-prod 稳定路径作为 103 兜底。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-06 17:11:40 +08:00
john 3befb0e257 fix(build): runtime 清理失败时回退 shell rm -rf
避免 macOS 上 pnpm node_modules 树导致 ENOTEMPTY 阻断发布构建。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-06 17:06:06 +08:00
john 0ae7a6a677 fix(mindspace): 公开页上传图片物化到 static 路径供转发访问
Finish 同步与首次访问时将私有资产 API 图片复制到 public/.tmp-images,
避免其他用户转发链接后因无登录态无法加载页面内图片。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-06 17:03:47 +08:00
tkmind 1077dd9b97 Merge pull request 'fix(ops): 自愈 goosed 会话 PostgreSQL,防止 H5 卡在创建新对话' (#7) from fix/goose-session-postgres-ensure into main 2026-07-06 09:01:25 +00:00
john b6def0f25b fix(ops): 自愈 goosed 会话 PostgreSQL,防止 H5 卡在创建新对话
103 Colima goosed 依赖宿主机 postgresql@17;库停止时 /agent/start 会 pool timeout 约 60s。新增 ensure 脚本、接入监控与发布前检查,并补充拓扑文档。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-06 16:57:38 +08:00
john ecf553754c docs: 记录 103 发布 0706007 备份路径与回退步骤
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-06 16:14:07 +08:00
john 14a00774d9 feat(h5): web 联网能力、实时查询路由与 session Finish 对齐
- 新增 web 能力并挂载 platform/web(web_search/fetch_url)
- 实时查询强制 web skill,router fallback 与 await session Finish
- Session Broker 覆盖率/指标、stream replay 与相关单测/E2E 脚本

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-06 16:06:26 +08:00
john 08feae8bef feat(h5-session): Session Broker、run SSE replay 与 Finish 竞态修复
落地 H5 Session 架构 Patch 1–5(Broker 收口、Router decision、SSE taxonomy、goosed 边界检查),
并新增可选 MEMIND_RUN_STREAM_REPLAY run 事件回放与 H5 假交付 guard;修复 Finish 先于 agent-run
gate 导致 UI 永久 loading 的竞态,接入 verify:h5-session-patches 回归脚本。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-06 14:19:48 +08:00
john e2ad3bf62b feat(mindspace): 公开页分享组件、workspace 路径与 Plaza 发布增强
- 新增 public share widget 与 workspace relative path 解析
- 增强 publications/chat-plaza 发布链路与缩略图 demo
- 补充 schema、cover 检查脚本与回归测试

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-05 23:14:41 +08:00
tkmind 69be1e5293 Merge pull request 'feat(plaza-ops): 运营后台帖子管理 API' (#6) from feature/plaza-ops-admin into main
Merge pull request #6: Plaza 运营后台帖子管理 API
2026-07-05 12:18:22 +00:00
john 0c2cb9e283 feat(plaza-ops): add post management API for admin console
Expose categories listing, category filter on review queue, and invalidate
feed caches when ops hides a published post.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-05 20:18:02 +08:00
tkmind dd091e6e2c Merge pull request 'feat(chat): Plaza 一键发布 + publication RPC 错误映射' (#5) from feature/rpc-publication-errors into main
Merge pull request #5: Plaza 一键发布 + publication RPC 错误映射
2026-07-05 12:01:42 +00:00
john 8755928405 fix(mindspace): expose findPageBySourceMessage on remote pageService adapter.
Quick Plaza publish resolves existing chat pages by session/message id; production remote adapter rejected the RPC because the binding contract omitted this method.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-05 19:58:42 +08:00
john 3318c04490 feat(chat): add one-click Plaza publish for HTML page messages.
Speed up the quick-plaza path with session snapshot reads, publish timeouts, and a modal fix so parent re-renders no longer abort in-flight requests.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-05 19:58:39 +08:00
john 53eb0014ba fix(mindspace): map publication RPC errors to HTTP status codes
Return 404/401/403 from MindSpace RPC for known publication errors and
preserve error codes through the Portal remote adapter.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-05 19:44:58 +08:00
john 85061dfa9f fix: stream Goosed page replies into chat without waiting for agent run
Subscribe session SSE as soon as the Goosed session is known, keep request
context during waiting, and poll session snapshots so page results appear
in the conversation while generation is still running.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-05 12:25:52 +08:00
john 1165ebf684 fix: normalize Goosed reply payload and restart agent-run worker on release
Add id/created defaults for user_message, ensure metadata in agent-run
gateway before submit, and kickstart the agent-run worker after portal deploy
so queued page-generation runs use the latest runtime bundle.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-05 12:04:31 +08:00
john cb7a446d3e fix: ensure userVisible metadata on Goosed session replies
Goosed rejects /sessions/:id/reply when user_message.metadata lacks
userVisible. Normalize metadata before submit and during agent orchestration
so page-generation runs no longer fail before streaming starts.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-05 11:58:17 +08:00
john 5f8ef9ddb0 fix: make MindSpace docx repair script runtime-safe
Avoid importing mindspace-public-finish-sync in production runtime so release
link repair can copy oa docx files or strip broken anchors without extra deps.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-05 11:29:17 +08:00
john 00a00a1f69 fix: portal stability, session list DB fallback, and UX polish
- Free stale Memind listeners on 8081 before startup and exit cleanly on EADDRINUSE
- Backfill owned sessions missing from Goose via h5_conversation_messages summaries
- Strip Memind task orchestration prefixes from user-facing chat text
- Repair missing public docx links before release MindSpace link checks

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-05 11:26:34 +08:00
john bdeab23b83 fix: persist direct chat transcript before Goosed escalation
Prevent portal direct-chat history from being lost when snapshot cache
is invalidated on Goosed submit by writing non-empty messages to DB first,
and stop caching empty Goose placeholder messages in snapshots.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-05 11:16:55 +08:00
john 614837e199 fix: repair chat history from DB when Goose session has empty placeholders
Portal direct chat → goosed escalation can leave hollow Goose messages while
h5_conversation_messages retains the full dialogue. Backfill session detail
from DB, extend snapshot list fallback, and keep stored session id on transient
boot failures so refresh no longer looks like a blank new chat.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-05 11:04:25 +08:00
john d3239ff292 fix: MindSpace remote sync, thumbnail fallback, and Plaza URL guards
Ensure page sync runs via pageSyncService in remote mode, fall back to
workspace HTML when storage assets are missing, and prevent production
Portal from linking to loopback Plaza URLs baked in at build time.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-05 07:57:04 +08:00
john 4781bbc156 fix: stop chat hang after misrouted themed article requests
Route themed page/article prompts to agent orchestration, reject them
from portal direct chat, and finalize regular sessions to idle when a
direct chat turn already completed.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-05 07:30:37 +08:00
john a29158d589 fix: unblock agent events after portal direct chat escalation
When a session starts with LLM direct chat then escalates to goosed,
invalidate the portal-direct-chat snapshot and stop replaying stale SSE
so page-generation turns stream and finish correctly.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-04 23:15:44 +08:00
john e45c9300bf feat: LLM intent router, direct chat execution, and Memory V2 light intervention
Wire chat intent routing with direct_chat on regular sessions, skill-selected
short-circuit to Agent, memory light/heavy intervention tiers, and fix direct
chat UI stuck streaming after completion.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-04 22:32:57 +08:00
john bfb6356f7d fix: wire memory v2 runtime helpers 2026-07-04 18:59:36 +08:00
john e4657c7e55 fix: rename h5 execution override to deep reasoning 2026-07-04 14:57:13 +08:00
john 12268110f7 fix: add goose execution override for h5 chat 2026-07-04 14:48:45 +08:00
john 927e16d861 fix(brand): force visible platform-brand footer on published pages
Inject serve-time CSS so author styles cannot hide TKMind · 智趣 with
low opacity, which made pages like weather.html look brandless.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-04 14:32:36 +08:00
john b782561d08 fix: skip goosed aux calls for direct chat sessions 2026-07-04 14:25:19 +08:00
john b5a88d9746 fix(brand): require TKMind platform marker on wechat page delivery
Backfill missing platform-brand footer at serve time and block service-
account links when the HTML file omits data-mindspace-page-tag.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-04 14:15:42 +08:00
john cd81c4b2bb fix(release): tolerate volatile persisted files during portal deploy 2026-07-04 14:13:17 +08:00
john 03c46b37c3 fix(og): fall back to thumbnail when declared cover file is missing
WeChat link cards were pointing og:image at mindspace-cover paths that
never landed on disk; serve-time injection now uses thumbnail.png instead.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-04 14:07:49 +08:00
john 29d9a87d4f feat: split h5 direct chat from goosed tasks 2026-07-04 14:02:18 +08:00
john eb8d760dd9 test(wechat): align page fixtures with share preview requirements
Mock HTML in wechat-mp tests now includes mindspace-cover metadata so
page link delivery assertions match production guard behavior.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-04 14:01:39 +08:00
john 31fb0e02cf feat(wechat): require share preview meta before page link delivery
Block service-account page links when HTML lacks mindspace-cover and
description so WeChat forwards always get TKMind branding and thumbnail.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-04 14:00:26 +08:00
john 031c6e086a feat(wechat): migrate schedule and sync handlers into wechat package
Extract schedule, greeting/status/connectivity replies, chat-general prompt, and display-name helpers from wechat-mp.mjs. Route sync intents via classifyWechatIntent and add channel isolation CI check.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-04 13:48:47 +08:00
tkmind fafc1fe7fd fix(guard): idempotent agent-run pause to stop portal restart loop
Skip repeat guard pause actions when code runs already disabled; add resume script and tests.
2026-07-04 05:41:51 +00:00
tkmind 2a3579c73a feat(wechat): channel split with stub-safe page delivery
Introduce wechat/ channel package; never send stub HTML links to service-account users.
2026-07-04 05:21:13 +00:00
john f36e8b9292 fix(build): externalize resvg when bundling wechat-mp runtime
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-04 12:54:27 +08:00
john 6bc5d128d2 fix(wechat): deliver failure notices and hot-swappable wechat-mp bundle
Notify users when HTML publish guards reject stub pages instead of silently
failing, send real page links when non-stub files exist, and split wechat-mp
into wechat-mp.bundle.mjs for fast production updates without full portal rebuilds.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-04 12:52:59 +08:00
john 5ed655b6c3 fix(wechat): detect tool_calls errors in Finish reply and sanitize outbound text
When Goose surfaces session poison errors as assistant text instead of Error events,
assertWechatAgentReplyIsSendable now throws to trigger session recreation. Outbound
sanitization prevents raw API errors from reaching WeChat users.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-04 12:38:00 +08:00
john f3a55dce29 merge: fix/wechat-mp-perf 2026-07-04 12:21:19 +08:00
john 8c72d0c950 fix: tighten WeChat session rotation and defer snapshot refresh
Use session snapshot message counts alongside WeChat route counts so long-lived dedicated sessions rotate before Goose history bloats, and refresh snapshots asynchronously so customer replies are not blocked.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-04 12:21:14 +08:00
john bef72b2768 fix wechat mp session rotation and bootstrap reuse 2026-07-04 12:10:22 +08:00
john 3139395b58 merge: fix/wechat-tool-calls-session-recovery
Auto-recover WeChat agent sessions when tool_calls history is poisoned.
2026-07-04 09:55:06 +08:00
john 7b09abeaa2 fix: auto-recover WeChat agent sessions poisoned by dangling tool_calls
When a dedicated WeChat session history leaves unmatched tool_calls, the next reply fails with a 400 LLM validation error; detect that pattern and recreate the session before retrying.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-04 09:53:59 +08:00
john 42baa3e468 test: align public image domain expectations 2026-07-04 00:23:13 +08:00
john 8d6e237128 merge: feature/generate-docx-sandbox into main for release 2026-07-04 00:21:12 +08:00
john 52c7082c70 feat: add generate_docx sandbox MCP tool for public Word downloads
Expose generate_docx in mindspace-sandbox-mcp so agents can write public/*.docx
before linking HTML download pages, with tests mirroring the Mark summary flow.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-04 00:18:43 +08:00
john 1ac9ad0277 fix: clarify upload errors and raise upload limits 2026-07-04 00:17:58 +08:00
john 702871a98c fix: restore public page share thumbnails from SVG sidecars
Serve missing *.thumbnail.png requests when the SVG sidecar exists, and schedule async PNG rasterization after public HTML is materialized so WeChat og:image URLs stop 404ing.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-04 00:11:40 +08:00
john 553af7ca7a feat: improve H5 chat header with floating session rail and new chat entry
Move recent session chips below the nav on mobile H5/WeChat with three visible tabs and horizontal swipe, and add a new-chat icon next to notifications.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-03 23:21:50 +08:00
john c3c487a8fb fix: serve MindSpace public assets as same-origin relative URLs
Rewrite absolute tkmind asset download links to /api/... at delivery time
and strip base tags that violate public page CSP, so images load on any host.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-03 23:02:47 +08:00
john f543a91cc4 fix: allow inline page scripts in MindSpace public page CSP
Collect sha256 hashes from all inline scripts in published HTML so agent-generated
fade-in animations are not blocked while keeping the share-button CSP model.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-03 22:42:29 +08:00
john cd2cbdbe78 fix: restore m.tkmind.cn public base 2026-07-03 17:27:51 +08:00
john 145bf4eb01 Merge memind-0703-new01 2026-07-03 16:34:31 +08:00
john 9e4074474b fix: harden session event proxy errors 2026-07-03 16:34:05 +08:00
john ebf06b376b docs: clarify local and 103 runtime topology 2026-07-03 16:34:02 +08:00
john 996c83bbc8 Merge wechat mp page routing fix 2026-07-03 10:43:54 +08:00
john 72fc7cc618 fix wechat mp page reply routing 2026-07-03 10:43:13 +08:00
john 20116b161f Merge Memory V2 runtime facade 2026-07-03 09:46:03 +08:00
john 7005c2a834 Add MindSpace service runtime release chain 2026-07-03 09:29:00 +08:00
john ec5b1a6e3f feat: finalize mindspace service extraction phase a 2026-07-03 08:40:28 +08:00
john 506a551438 feat: polish mindspace decoupling flows 2026-07-03 00:34:03 +08:00
john b258004dad feat: complete mindspace conversation packages 2026-07-02 23:46:05 +08:00
john b084f6d23c Add page indexes to conversation manifests 2026-07-02 22:03:59 +08:00
john ab4dab6b38 Link page artifacts to preview route 2026-07-02 22:01:35 +08:00
john 49127d8675 Add conversation package manifest download 2026-07-02 21:58:14 +08:00
john b4ae4a870c Record synced workspace artifacts in packages 2026-07-02 21:55:07 +08:00
john c86a3fd15b Record published companion artifacts 2026-07-02 21:47:10 +08:00
john b38dd5961f Record chat docx artifacts in packages 2026-07-02 21:43:38 +08:00
john 0e00ed52cd Test conversation package route boundary 2026-07-02 21:39:28 +08:00
john 85936fff05 Show conversation package folder in chat 2026-07-02 21:36:33 +08:00
john ca88716d68 Add conversation package client types 2026-07-02 21:33:31 +08:00
john 32296cb422 Expose conversation package manifests 2026-07-02 21:32:34 +08:00
john 0f48792133 Record uploaded assets in conversation packages 2026-07-02 21:28:51 +08:00
john c2308a6ead Record published pages in conversation packages 2026-07-02 21:24:40 +08:00
john 39e4fffe91 Record page drafts in conversation packages 2026-07-02 21:22:43 +08:00
john 97b648322a Add conversation package registry 2026-07-02 21:17:40 +08:00
john 1b3e64703e Write conversation package manifests 2026-07-02 21:15:41 +08:00
john 0d6e4ead01 Add conversation package store 2026-07-02 21:14:43 +08:00
john f0acaec535 Route quick-share URLs through facade 2026-07-02 21:12:22 +08:00
john aba72c6cf8 Route WeChat publish URLs through facade 2026-07-02 21:11:36 +08:00
john 0a0c619aca Route auth publish URLs through facade 2026-07-02 21:10:38 +08:00
john 22b6220fcc Route asset public image URLs through facade 2026-07-02 21:08:41 +08:00
john a700bb3edb Route publish URLs through MindSpace facade 2026-07-02 21:07:51 +08:00
john 253ee870e7 Add MindSpace service facade skeleton 2026-07-02 21:06:03 +08:00
john 66c530b1ed Add MindSpace canonical URL facade 2026-07-02 21:04:49 +08:00
john e4d6267c96 Add MindSpace decoupling foundation 2026-07-02 21:03:14 +08:00
john ddfa60607a feat: add chat page export actions 2026-07-02 19:52:26 +08:00
john 2d777ef394 docs: clarify optional publish attachments 2026-07-02 19:18:56 +08:00
john bb7b82173d chore: update MindSpace brand footer text 2026-07-02 19:09:30 +08:00
john b5781680a8 fix: simplify tool call badges 2026-07-02 19:03:59 +08:00
john 90c776065c Merge branch 'codex/0702-remove-design' 2026-07-02 18:45:35 +08:00
john bea8eb7c1d chore: remove unused design panel 2026-07-02 18:44:20 +08:00
john 87ff84535d Merge branch 'codex/0702-optimization' 2026-07-02 18:40:41 +08:00
john 9135332467 fix: hide fully loaded history notice 2026-07-02 18:39:59 +08:00
john 50929940cc fix: hide project memory refresh notice 2026-07-02 18:35:35 +08:00
john 30ef609eba test: align public image url domain 2026-07-02 18:13:12 +08:00
john 40717d8fc7 Merge branch 'codex/memind-long-image-playwright' 2026-07-02 18:10:55 +08:00
john e94b3740b4 Merge remote-tracking branch 'origin/main' 2026-07-02 18:10:49 +08:00
john f9eb3d1440 feat: add Playwright long image downloads 2026-07-02 18:10:33 +08:00
Your Name 8e0ace1389 chore: add hourly runtime slo soak monitor 2026-07-02 12:45:55 +08:00
Your Name f9a385f333 feat: add agent run heartbeat to slo reports 2026-07-02 12:41:04 +08:00
Your Name 054379ac98 feat: add worker heartbeat for agent runs 2026-07-02 12:38:34 +08:00
Your Name 7a47dc6a98 feat: add task artifact validation for code runs 2026-07-02 12:31:29 +08:00
Your Name 201cc5fb7a fix: harden auth middleware against transient db errors 2026-07-02 12:16:38 +08:00
Your Name c27bf04a71 feat: recover stale running agent runs 2026-07-02 12:12:41 +08:00
Your Name af5396c127 docs: record worker concurrency rollout 2026-07-02 12:08:49 +08:00
Your Name 79d310ba29 chore: keep agent run worker alive during gray rollout 2026-07-02 11:54:29 +08:00
Your Name c0f922b5f8 feat: require validation receipts for h5 code runs 2026-07-02 11:52:40 +08:00
Your Name 80b762053b feat: add agent run guard rollout controls 2026-07-02 11:36:46 +08:00
Your Name 212e163006 feat: add code run rollout policy gates 2026-07-02 10:47:22 +08:00
Your Name f1fd4cc316 feat: add agent run worker status check 2026-07-02 10:36:23 +08:00
Your Name b12c1b371c feat: support worker canary workdir override 2026-07-02 10:26:28 +08:00
Your Name 3654639bb3 feat: add agent run worker launchagent installer 2026-07-02 10:18:27 +08:00
Your Name 6340b57fda feat: validate tool gateway artifacts 2026-07-02 10:12:30 +08:00
Your Name a2d69a0c36 feat: target agent run worker dispatch 2026-07-02 10:02:01 +08:00
Your Name 0cfd2d3d2a fix: map deepseek models for aider 2026-07-02 09:42:08 +08:00
John 21e03d86b5 feat: add tool gateway protocol 2026-07-02 09:23:55 +08:00
John e24e6ca4a7 feat: add runtime worker heartbeat sidecar 2026-07-02 09:03:30 +08:00
John a0af049fa7 fix: pass mindspace link bypass to prod release 2026-07-02 08:49:21 +08:00
John c7d8140a69 feat: gate code runs by user whitelist 2026-07-02 08:42:44 +08:00
John 8a53dff856 chore: prune runtime slo reports 2026-07-02 08:38:56 +08:00
John bb98734d9c fix: let external agent worker drain before exit 2026-07-02 08:30:01 +08:00
John a402509d6e chore: schedule runtime slo reports 2026-07-02 08:12:02 +08:00
John e3ce4032c6 feat: write runtime slo daily reports 2026-07-02 08:09:02 +08:00
John 12f74eb44e feat: add first token latency window stats 2026-07-02 08:06:58 +08:00
John 05d29ce62d feat: add external agent run worker entry 2026-07-02 08:02:03 +08:00
John 3ea973968e feat: add agent run queue controls 2026-07-02 07:52:07 +08:00
John 8e5094fcd9 feat: record first token latency in runtime router 2026-07-02 07:45:47 +08:00
John 41b7b5ffa3 chore: add runtime metrics agent and slo report 2026-07-02 07:41:46 +08:00
John a13808b462 feat: feed worker metrics into runtime router 2026-07-02 07:35:10 +08:00
John b97c8e822e chore: add worker stream reconcile dry run 2026-07-02 07:28:58 +08:00
John e989526886 feat: gate code agent runs server side 2026-07-02 07:25:16 +08:00
John 304a9eaea2 chore: add code run entry check 2026-07-02 07:22:49 +08:00
John ac20ac212e feat: add gated h5 code run entry 2026-07-02 07:19:26 +08:00
John 0271d83756 feat: wire code agent runs to tool mode 2026-07-02 07:16:47 +08:00
John e17dcaf4a8 feat: gate code tools by task mode 2026-07-02 07:12:18 +08:00
John c9b7252832 fix: avoid opening sse in runtime check 2026-07-02 07:06:25 +08:00
John fa0024907b docs: record runtime ops rollout 2026-07-02 07:05:07 +08:00
John 4420cca340 chore: add runtime observability ops 2026-07-02 07:04:50 +08:00
John 04e308e582 feat: add streaming runtime router 2026-07-02 06:55:26 +08:00
john 8260ff1e0e docs: enforce main-only release gate 2026-07-01 23:35:55 +08:00
john 4fc59729ee fix: add session origin tracking + idle rotation foundation (schema/auth/config)
Backend infrastructure for WeChat/H5 session unification:

- schema.sql: h5_user_sessions adds origin ENUM('h5','wechat') column
- db.mjs: idempotent migration for origin column (adds after user_id)
- user-auth.mjs:
  - setSessionOrigin(sessionId, origin) - tag where session was created
  - getSessionOrigins(sessionIds) - batch lookup for history labeling
  - touchWechatAgentRoute(appId, openid) - refresh activity timestamp
- wechat-mp.mjs:
  - DEFAULT_SESSION_IDLE_ROTATE_MS = 30min (env-configurable)
  - loadWechatMpConfig includes sessionIdleRotateMs

Tests: 50/50 pass ✓

Still TODO:
- ensureWechatAgentSession idle rotation check + setSessionOrigin call
- runIntentMessage grantedSkills flow + touchWechatAgentRoute calls
- Frontend type/UI component updates
- Integration test for idle rotation

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-01 21:10:56 +08:00
john ec375b1402 fix(wip): WIP - partial unify WeChat/H5 skill prompts (build agent changes)
- Reuse H5's buildAutoChatSkillPrefix in buildWechatAgentPrompt signature
- Inject autoSkillPrefix into voice/text message prompts
- Add origin tagging in GET /sessions for h5/wechat channel labels

Still TODO (will complete in next cycle):
- Full resolveGrantedSkills → buildWechatAgentPrompt flow
- ensureWechatAgentSession idle rotation logic
- setSessionOrigin + touchWechatAgentRoute calls
- Backend schema/migrations (h5_user_sessions origin column)
- Frontend type + UI component updates

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-01 21:07:25 +08:00
john 164c6627a0 fix: register direct wechat sessions after start fallback 2026-07-01 18:36:46 +08:00
john c0ed894cff merge: record 0701bug002 into main 2026-07-01 18:35:36 +08:00
john 44d41d9851 merge: record remaining local branches into main 2026-07-01 18:35:25 +08:00
john 73a90c80fd fix: normalize alternate tkmind publish links 2026-07-01 18:34:04 +08:00
john 1297531b04 docs: record v2 direct-injection release id for 103 rollback
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-01 18:32:27 +08:00
john de5fab370c fix(agent): inject Shanghai time into each reply message
103 goosed harness_remember returns remembered:false, so session memory
never carried the time anchor. Prepend buildCurrentTimeAgentPrefix on every
H5 /reply and WeChat agent prompt so the model sees Asia/Shanghai clock.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-01 18:32:27 +08:00
john 75e5a56b86 docs: record 103 agent-time-fix release id for rollback
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-01 18:31:32 +08:00
john 62c1d72470 fix(agent): inject Asia/Shanghai time anchor on 0630007 line
Agent replies were reporting UTC time because 0630007-memind never injected
TKMind 当前时间基准 into session memory. Port the time anchor from the
0630004 work only—no miniapp branch changes—and add a 103 rollback script.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-01 18:31:32 +08:00
john 235ca0971e fix: reconcile reused wechat agent sessions 2026-07-01 18:30:50 +08:00
john 9aa5229af8 docs: add portal-release skill for package/deploy/verify/rollback
Codifies the 103 production release workflow used for the
0701bug003 deploy: doc-mandated pre-release tests, build + dry-run,
release-portal-runtime-prod.sh, full post-deploy verification
(health, /auth/login, all 4 goosed ports, log keyword scan, real
API-driven page-create smoke test), and both a preferred rollback
(redeploy previous good commit) and an emergency manual rollback path.

Passwords are taken from env vars (JOHN_PASSWORD/H5_ACCESS_PASSWORD),
matching the existing scripts/fruit-theme-john-e2e.mjs convention —
never hardcoded in the skill file.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-01 18:19:40 +08:00
john 862824202f fix: guide agent to a real public link instead of dead-ending on apps__create_app
Diagnosed via production session logs (RDS + shared goose PG) that some
users' page-generation attempts drifted: the agent used apps__create_app
(no public URL) then fabricated a placeholder domain when asked for a
link, and separately burned many turns scraping unreachable/anti-bot
search engines. Steer both flows toward the already-working path instead
of banning tools outright:

- apps__create_app is fine for designing/previewing a page, but the
  agent must still write_file the result into public/*.html per the
  static-page-publish skill and return a link built from the real
  public URL template (no invented domains)
- for real-world lookups, load_skill('web') first and prefer
  Bing/360 over retrying google.com or hammering anti-bot sites

Also folds in generate_docx guidance for Word-download attachments
(sandbox-fs tool) that landed in the same files during this pass.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-01 18:19:40 +08:00
john b273bb7aa2 fix: gate public page download links before Portal release
Add a MindSpace public HTML checker for missing companion docx/PDF paths, wire it into runtime packaging and release-portal-runtime-prod.sh, and document the workflow for agents and ops.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-01 18:18:27 +08:00
john 5a970e612e chore: enforce standard branch release workflow 2026-07-01 18:14:24 +08:00
john 394d3640d1 fix(chat): speed up history switch 2026-07-01 18:13:24 +08:00
john b7af5b00dc fix(release): restart m.tkmind.cn portal tunnel after Portal deploy
Bundle memind-portal-tunnel.sh into the runtime artifact and kickstart
cn.tkmind.memind-portal-tunnel on 103 after Portal health checks so 105
nginx can reach 127.0.0.1:19081 following runtime releases.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-01 18:12:31 +08:00
john d7cbf3cc96 chore: add 105 runtime and openhands ops tooling 2026-07-01 18:10:48 +08:00
john 65e8a3a5a8 fix: escape docx publish hints in workspace templates 2026-07-01 18:08:06 +08:00
john ee3dd3b23c fix: require docx generation for downloadable pages 2026-07-01 18:08:06 +08:00
john 6cb1a2475d fix: harden public download companion sync 2026-07-01 18:08:06 +08:00
john 6e4e0e2937 refactor: centralize wechat notification dispatch 2026-07-01 18:08:06 +08:00
john 9c653e9b16 feat: auto grant one-time low balance gift for new users 2026-07-01 18:08:06 +08:00
john ae6eaf8c3e docs: 103 发布 0630004 回退说明与备份路径
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-01 18:08:06 +08:00
john 722b18326f feat(mindspace): 0630004 空间 UI、聊天连接、微信分享与 Agent 能力
含 MindSpace 三列布局与统计修复、聊天加载态与连接降级、平台页脚标记与 og:site_name 微信卡片、勾选资料删除 Agent 接口及内部话术过滤。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-01 18:08:06 +08:00
john b1b8d3afc6 docs: 103 发布 0630003 回退说明与备份路径
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-01 18:08:06 +08:00
john 71e536eceb feat(mindspace): 悬浮聊天勾选资料联动、UI 与交互优化
勾选单个文件时 Agent 获知上下文并主动问候;打开悬浮窗使用新会话。
统一弹窗浅色主题、固定高度与输入区布局,支持点击外部收起。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-01 18:08:06 +08:00
john 2c91689692 feat(schedule): 待办提醒推送、行事历仅展示提醒与管理 API
单次提醒 worker 投递、local 时间写入校验、未来 7 天提醒列表与忽略/批量删除;行事历去掉事项重复展示。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-01 18:08:06 +08:00
john 06eb129a28 fix(mindspace): 修复删除时无法解析 MySQL JSON 导致页面复活
source_snapshot_json 在 mysql2 中已是对象,JSON.parse 失败会使 relative_path 丢失、工作区 HTML 未清理;同步后页面重新出现。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-01 18:08:06 +08:00
john 2f6a52151a docs: 103 发布 0630001 回退说明与备份路径
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-01 18:08:06 +08:00
john ea6c49f046 feat(mindspace): 全部页面管理、级联删除与页面同步去重
支持全部页面分页/多选/删除/分享,删除时可选移除广场帖并清理工作区附件;修复并发同步重复创建页面,并补齐预览下载链接重写与 iframe 下载权限。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-01 18:08:06 +08:00
john 6e6d00568a merge: integrate 0629004-bug 2026-07-01 17:57:14 +08:00
john 0293abc11f merge: integrate codex/mindspace-ui 2026-07-01 17:57:11 +08:00
john 7f0b216775 docs: add portal-release skill for package/deploy/verify/rollback
Codifies the 103 production release workflow used for the
0701bug003 deploy: doc-mandated pre-release tests, build + dry-run,
release-portal-runtime-prod.sh, full post-deploy verification
(health, /auth/login, all 4 goosed ports, log keyword scan, real
API-driven page-create smoke test), and both a preferred rollback
(redeploy previous good commit) and an emergency manual rollback path.

Passwords are taken from env vars (JOHN_PASSWORD/H5_ACCESS_PASSWORD),
matching the existing scripts/fruit-theme-john-e2e.mjs convention —
never hardcoded in the skill file.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-01 15:21:55 +08:00
john 27960a3762 fix: guide agent to a real public link instead of dead-ending on apps__create_app
Diagnosed via production session logs (RDS + shared goose PG) that some
users' page-generation attempts drifted: the agent used apps__create_app
(no public URL) then fabricated a placeholder domain when asked for a
link, and separately burned many turns scraping unreachable/anti-bot
search engines. Steer both flows toward the already-working path instead
of banning tools outright:

- apps__create_app is fine for designing/previewing a page, but the
  agent must still write_file the result into public/*.html per the
  static-page-publish skill and return a link built from the real
  public URL template (no invented domains)
- for real-world lookups, load_skill('web') first and prefer
  Bing/360 over retrying google.com or hammering anti-bot sites

Also folds in generate_docx guidance for Word-download attachments
(sandbox-fs tool) that landed in the same files during this pass.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-01 14:19:09 +08:00
john 945b0a609b fix: guide agent to a real public link instead of dead-ending on apps__create_app
Diagnosed via production session logs (RDS + shared goose PG) that some
users' page-generation attempts drifted: the agent used apps__create_app
(no public URL) then fabricated a placeholder domain when asked for a
link, and separately burned many turns scraping unreachable/anti-bot
search engines. Steer both flows toward the already-working path instead
of banning tools outright:

- apps__create_app is fine for designing/previewing a page, but the
  agent must still write_file the result into public/*.html per the
  static-page-publish skill and return a link built from the real
  public URL template (no invented domains)
- for real-world lookups, load_skill('web') first and prefer
  Bing/360 over retrying google.com or hammering anti-bot sites

Also folds in generate_docx guidance for Word-download attachments
(sandbox-fs tool) that landed in the same files during this pass.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-01 14:11:09 +08:00
john b4a2b2bdaf fix: gate public page download links before Portal release
Add a MindSpace public HTML checker for missing companion docx/PDF paths, wire it into runtime packaging and release-portal-runtime-prod.sh, and document the workflow for agents and ops.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-01 12:40:59 +08:00
john 07530a888c fix: escape docx publish hints in workspace templates 2026-07-01 12:13:26 +08:00
john ea4daa1298 fix: require docx generation for downloadable pages 2026-07-01 12:07:46 +08:00
john 58521df36a fix: harden public download companion sync 2026-07-01 11:10:58 +08:00
john 5d9f91ad92 chore: enforce standard branch release workflow 2026-07-01 10:53:11 +08:00
john a2fc5c55ad docs: record v2 direct-injection release id for 103 rollback
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-01 08:42:52 +08:00
john 27db709815 fix(agent): inject Shanghai time into each reply message
103 goosed harness_remember returns remembered:false, so session memory
never carried the time anchor. Prepend buildCurrentTimeAgentPrefix on every
H5 /reply and WeChat agent prompt so the model sees Asia/Shanghai clock.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-01 08:40:27 +08:00
john e328dd541d docs: record 103 agent-time-fix release id for rollback
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-01 08:35:07 +08:00
john 7e3c018a55 fix(agent): inject Asia/Shanghai time anchor on 0630007 line
Agent replies were reporting UTC time because 0630007-memind never injected
TKMind 当前时间基准 into session memory. Port the time anchor from the
0630004 work only—no miniapp branch changes—and add a 103 rollback script.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-01 08:32:02 +08:00
john 6cd453284b refactor: centralize wechat notification dispatch 2026-06-30 21:26:46 +08:00
john cd1ff6758d feat: auto grant one-time low balance gift for new users 2026-06-30 20:39:46 +08:00
john f7c35f37e5 docs: 103 发布 0630004 回退说明与备份路径
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-30 09:35:08 +08:00
john 2b8dba1784 feat(mindspace): 0630004 空间 UI、聊天连接、微信分享与 Agent 能力
含 MindSpace 三列布局与统计修复、聊天加载态与连接降级、平台页脚标记与 og:site_name 微信卡片、勾选资料删除 Agent 接口及内部话术过滤。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-30 09:30:51 +08:00
john 0203d81942 docs: 103 发布 0630003 回退说明与备份路径
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-30 02:20:11 +08:00
john 92b093199a feat(mindspace): 悬浮聊天勾选资料联动、UI 与交互优化
勾选单个文件时 Agent 获知上下文并主动问候;打开悬浮窗使用新会话。
统一弹窗浅色主题、固定高度与输入区布局,支持点击外部收起。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-30 02:17:36 +08:00
john 14f46cf318 feat(schedule): 待办提醒推送、行事历仅展示提醒与管理 API
单次提醒 worker 投递、local 时间写入校验、未来 7 天提醒列表与忽略/批量删除;行事历去掉事项重复展示。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-30 02:02:58 +08:00
john 7906f3c36d fix(mindspace): 修复删除时无法解析 MySQL JSON 导致页面复活
source_snapshot_json 在 mysql2 中已是对象,JSON.parse 失败会使 relative_path 丢失、工作区 HTML 未清理;同步后页面重新出现。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-30 01:39:47 +08:00
john e93fb6a75f docs: 103 发布 0630001 回退说明与备份路径
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-30 01:24:33 +08:00
john 66ca0b3bec feat(mindspace): 全部页面管理、级联删除与页面同步去重
支持全部页面分页/多选/删除/分享,删除时可选移除广场帖并清理工作区附件;修复并发同步重复创建页面,并补齐预览下载链接重写与 iframe 下载权限。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-30 01:22:38 +08:00
john 4e7ef3d853 docs: 103 发布 0629002 回退说明与备份路径
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-30 00:29:38 +08:00
john 98721371a4 fix(mindspace): edit_file 落盘、Finish 聊天 merge 与回归守卫
- finish-sync 支持 edit_file 覆盖 public HTML
- Finish 同步 merge 本地流式消息,剥离 agent 内部前缀
- 新增 verify:mindspace-publish-guards 与 AGENTS.md 跨工具说明
- 发版脚本接入回归门禁;103 runtime 发布含备份回退

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-30 00:27:15 +08:00
john 6f89a9a236 feat: add test HTML page with centered card layout and alert button
Co-authored-by: aider (deepseek/deepseek-chat) <aider@aider.chat>
2026-06-29 23:28:48 +08:00
john 742aee7148 merge: 0629001 into 0629002
合并反馈、语音 ASR、MindSpace 修复等 0629001 发布改动,并与 Agent Runs 网关改动完成冲突解决。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-29 22:51:03 +08:00
john 8f620fa714 feat(agent): 聊天提交统一走 POST /agent/runs 异步网关
引入 Agent Run 网关替代直连 /sessions/:id/reply,并在 api_lockdown 白名单中放行新入口,避免策略拦截导致聊天不可用。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-29 22:50:00 +08:00
john dff0308ccb fix: optimize mindspace category counts 2026-06-29 22:43:22 +08:00
john 4fcb48395e fix: prevent mindspace space endpoint optional data timeout 2026-06-29 22:37:30 +08:00
john a40e340a41 release: prepare 0629001 portal updates 2026-06-29 22:20:04 +08:00
john 18ea4f82fd feat(feedback): 新增用户反馈提交、分页列表与语音描述
支持 Bug/需求提交、截图与聊天同款语音输入,全站反馈分页浏览与详情页,并从聊天与空间页提供入口。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-29 20:49:15 +08:00
john 08c5b22d4a fix(voice): 浏览器语音默认走服务端 ASR
Web Speech 依赖 Google,国内浏览器常无法转文字;支持麦克风时改为录音后走自有 ASR,并补全网络异常时的降级匹配。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-29 12:34:34 +08:00
john cc98cf02fa style(chat): highlight tap-to-open hint 2026-06-29 11:28:54 +08:00
john 0187f26c5b fix(release): 将 skills/ 目录打入 Portal runtime 产物
生产 Agent 需从 live 目录读取平台技能(含 docx-generate),无源码 runtime 必须携带 skills 树。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-29 11:23:37 +08:00
john d67adc1df8 fix(skills): 禁止 HTML base64 内嵌 docx,新增 docx-generate 技能
避免 Agent 在下载页用 data URI 嵌入 Word 导致文件截断乱码;规范公网下载须单独落盘并用相对路径链接。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-29 11:19:20 +08:00
john e0e03e95b1 fix(chat): speed up history switch 2026-06-29 11:15:40 +08:00
john 637b32515a fix(mindspace): sync nested OA files and count workspace assets
Recursive workspace sync now imports files in oa/private/public subfolders,
references workspace paths without duplicating storage, and includes
workspace-sourced assets in category itemCount. Refresh counts when leaving
a category view.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-29 10:34:18 +08:00
john 2b344dfa60 fix(release): restart m.tkmind.cn portal tunnel after Portal deploy
Bundle memind-portal-tunnel.sh into the runtime artifact and kickstart
cn.tkmind.memind-portal-tunnel on 103 after Portal health checks so 105
nginx can reach 127.0.0.1:19081 following runtime releases.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-29 10:22:19 +08:00
john 12a1247c1f fix(mindspace): sync nested OA files and count workspace assets
Recursive workspace sync now imports files in oa/private/public subfolders,
references workspace paths without duplicating storage, and includes
workspace-sourced assets in category itemCount. Refresh counts when leaving
a category view.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-29 10:11:28 +08:00
john 16828a58f7 merge: codex/mindspace-ui into main 2026-06-29 07:15:47 +08:00
john 3e313dc8a3 merge: codex/wechat-memory into main 2026-06-29 07:15:39 +08:00
john 29f6c0095f fix: harden conversation memory extraction flow 2026-06-29 07:14:42 +08:00
john 9465803d95 feat: refine mindspace asset card actions 2026-06-29 07:08:59 +08:00
john e80831ad4f feat: add wechat publish recovery and conversation memory 2026-06-29 07:08:59 +08:00
john f8787bd330 chore: add 105 runtime and openhands ops tooling 2026-06-29 07:01:26 +08:00
john 2e9fcaf9ba feat: refine mindspace asset card actions 2026-06-29 07:00:29 +08:00
john 66acbc902c feat: add wechat publish recovery and conversation memory 2026-06-29 06:59:37 +08:00
john 615a1e9bf4 Include WeChat menu scripts in portal runtime 2026-06-29 06:46:35 +08:00
john 504513747e fix: reuse verified requested page links for wechat 2026-06-28 22:13:08 +08:00
john 81c38226e5 fix: require publish skill for wechat page tasks 2026-06-28 21:54:15 +08:00
john 82ac5fc744 fix: normalize alternate tkmind publish links 2026-06-28 15:38:31 +08:00
john f31775b0c7 fix: persist wechat session history and page links 2026-06-28 15:29:39 +08:00
john fa2e385849 fix: detect sandbox fs html writes for wechat pages 2026-06-28 15:06:24 +08:00
john 34ae9de100 fix: harden wechat page publish link validation 2026-06-28 14:53:09 +08:00
john ea19ffb5fa feat: improve mindspace asset handling and local runtime paths 2026-06-28 12:18:26 +08:00
john 1af680c6cb chore: align local paths and add colima dev flow 2026-06-28 08:20:53 +08:00
john 451918fbec Fix local startup schema parsing 2026-06-28 07:04:26 +08:00
john faac6d9772 merge: goosed-mcp-release (schema fix + mcp paths + chat UI + runtime fixes) 2026-06-28 06:59:21 +08:00
john 4a9bc710f1 feat: sync portal runtime fixes for release 2026-06-27 22:28:41 +08:00
john 8264e71f9e feat: release chat and mindspace UI updates 2026-06-27 21:57:21 +08:00
john c924b2bb77 docs: add release must-read checklist 2026-06-27 21:48:27 +08:00
john 0420c42fe2 fix: make schema bootstrap mysql safe 2026-06-27 21:40:58 +08:00
john fc5b50c936 fix: make goosed mcp paths container safe 2026-06-27 21:31:02 +08:00
john f4e8bb51a1 fix: reconcile reused wechat agent sessions 2026-06-27 18:33:53 +08:00
john 58d824f5e5 fix: dereference node_modules symlink in runtime build 2026-06-27 18:19:13 +08:00
john 0a79a99df9 chore: remove duplicate auth export in release bundle 2026-06-27 18:14:30 +08:00
john 4bb4858e84 feat: package portal updates for 103 release 2026-06-27 18:13:44 +08:00
john def9b0b5eb chore: Add backup files to .gitignore
- *.bak 备份文件不提交到版本控制
2026-06-27 08:25:34 +08:00
john da239bdf09 feat: Add imgproxy signer service
- imgproxy-signer.mjs: 图片代理签名服务
2026-06-27 08:25:27 +08:00
john 3bb5d21425 chore: Add runtime portal files and assets
- Portal 运行时文件和配置
- 测试资源和验证文件
- Plaza 封面图片资源
2026-06-27 08:25:18 +08:00
john a2374c3cd6 chore: Update configs and build files
- .gitignore 更新
- Caddyfile LB 配置更新
- WeChat MP 菜单脚本更新
- package-lock.json 更新
2026-06-27 08:25:11 +08:00
john 1798c07d42 docs: Update documentation and release rules
- 架构和规划文档更新
- 开发、工程、生产发布规则更新
- 服务隔离和升级指南
- README 更新
2026-06-27 08:25:06 +08:00
john 25f8223253 refactor: Business logic and dependencies updates
- 核心服务代码更新 (db, server, auth, proxy)
- Agent 相关模块更新 (mindspace, experience)
- 前端组件和 hooks 更新
- 数据库 schema 更新
- 依赖版本更新
2026-06-27 08:25:02 +08:00
john f1220a7905 feat: Goosed 本地 Docker 构建方案
- scripts/verify-goosed-docker.sh: 一键本地构建脚本
- docker-compose.local.yml: 本地开发环境
- docs/goosed-docker-local-verification.md: 本地测试指南
- docs/goosed-local-build-delivery.md: 构建交付说明
- docs/goosed-phase1-local-plan.md: 实施计划

完全本地化,无 CI 依赖,手工构建交付。
2026-06-27 08:24:57 +08:00
john 8627188ee7 feat: DesignSkillPanel — awesome-design-md 前台 UI 集成
- 新增 DesignSkillPanel 组件:54 品牌风格选择网格 + 任务描述输入
- ChatPanel 工具栏增加 design 按钮,点击弹出面板
- 生成结果回填到输入框,用户可编辑后发送
- 新增 API:listDesignStyles / invokeDesignSkill(走 /admin-api/skills/)
- .env.local: H5_DEV_ADMIN=http://127.0.0.1:8085(对接本地 memindadm)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-26 19:44:21 +08:00
john 8502775042 Fix UUID leaking as user display name in agent context
resolveUserAddressName now filters UUID-format strings (same as wx_*),
preventing user.id from being used as a display name when nickname/
displayName is absent.

buildSessionMemoryEntries always calls ensureUserMemoryProfile when
userContext is available so stale profiles with UUID display names are
auto-healed on next session init.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-26 15:56:22 +08:00
john 9b4a25799f Add smart ACK provider for WeChat MP replies
Replace fixed ackText with a rule-based AckProvider that picks
response templates by message type and intent (translate, summary,
rewrite, poster, ppt, mindmap, code, search, schedule). Pure sync,
zero I/O, auto-falls back to config.ackText on any error.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-26 15:19:03 +08:00
john 9ed4fd48d7 Fix sandbox MCP path resolution for session policy sync.
Resolve mindspace-sandbox-mcp.mjs from the code module location instead of h5Root, and copy it into the portal runtime artifact so goosed can spawn sandbox-fs on production.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-26 13:36:05 +08:00
john d51df2fb0a Hide goose from user-facing connection errors 2026-06-25 23:44:58 +08:00
john e133f9a3a4 Point gadm root to admin console 2026-06-20 16:11:57 +08:00
john daa5ab7199 Document gadm ops root routing 2026-06-20 16:09:03 +08:00
john 02c651a3d0 Unify current release docs and isolation notes 2026-06-20 15:54:19 +08:00
john db0149b025 Add release flow topology to deploy guide 2026-06-20 15:53:01 +08:00
john a0b684dba7 Add unified release topology to README 2026-06-20 15:52:04 +08:00
john fe4172d07e Add release entry overview to README 2026-06-20 15:47:41 +08:00
john 41470bafcb Unify plaza and gadm release docs 2026-06-20 15:46:32 +08:00
john cb51b94f2c Document gadm release flow 2026-06-20 15:41:22 +08:00
john 44e962e270 Document plaza 105-to-studio flow 2026-06-20 15:39:19 +08:00
john 2f07f3733e Add 105 rsync exclude rules 2026-06-20 15:18:59 +08:00
john 70492d9eba Add attachment text extraction, auto web news skill, and chat/voice UI updates.
Simplify asset upload temp paths, refresh deploy docs for Aliyun DNS topology, and ship MindSpace content-scan and auth improvements.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-20 15:08:10 +08:00
john 2e5afe3bfd feat: add fetch_news.py script to aggregate news from HN, Reddit, and GitHub
Co-authored-by: aider (deepseek/deepseek-chat) <aider@aider.chat>
2026-06-20 08:15:48 +08:00
john c4de6716f1 Restore Studio rsync exclude rules for safe production deploys.
Re-add the deploy exclude file and protect .tailscale so rsync --delete cannot remove production-only runtime data.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-19 23:09:22 +08:00
john 229805a070 Improve WeChat MP replies and ship MindSpace/H5 production updates.
Add WeChat service account routing with sync acks, connectivity tests, and context isolation; document deploy runbooks; and bundle related MindSpace, voice, Plaza, and server gateway changes for production rollout.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-19 23:06:43 +08:00
Your Name b0f5d6a51c Extract memind_adm admin server, add local dev tooling, and remove image-generation.
Split platform admin and ops APIs into standalone admin-server.mjs with network guards; simplify billing to RMB token pricing, refactor user auth, and add rsync deploy plus local-test scripts and docs.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-17 16:39:39 -07:00
John ab0718938e Fix OA workspace cover thumbnails and add space chat new session.
Resolve mindspace-cover images from workspace directories when generating feed thumbnails, refresh stale SVGs missing embedded photos, and disable thumbnail API caching so fixes take effect immediately. Also add a new session control to the space chat panel, including on mobile.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-16 17:57:00 -07:00
John 6d99d762da Add image-designer skill, align billing to DeepSeek ×1, and enrich Plaza demo.
Introduce AI image generation with chat shortcut and agent API, improve MindSpace chat-to-page save resolution, and seed Plaza covers with production deploy scripts.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-16 16:29:19 -07:00
John 03690ee354 Fix duplicate session billing and align pricing with DeepSeek ×3.
Serialize billSessionUsage with row locks, expose rates on recharge, add compensation script and admin usage views.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-16 04:45:15 -07:00
john befeedfd37 Remove embedded admin UI and redirect admins to standalone ops app.
Extract admin routes from the main SPA, add plaza-api bootstrap module, and track ops pnpm lockfile.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-16 19:43:56 +08:00
john f818dd0307 Add WeChat in-app JSAPI recharge for g2.tkmind.cn.
Use JSAPI with bound openid inside WeChat instead of QR long-press, and include related auth redirect and admin UX fixes.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-16 16:20:04 +08:00
John bb70634a96 Remove recent billing list from balance popover.
Keep the popover focused on balance summary and token usage without fetching usage records on open.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-16 01:03:35 -07:00
John 79457230c1 Improve MindSpace visual editor UX and default RMB billing.
Add color-coded edit highlights with an in-preview legend, strip CSP meta
for srcdoc editing, and simplify fullscreen preview to immersive visual edit
only. Default billing to CNY token rates unless H5_USE_BACKEND_COST=1.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-16 00:59:28 -07:00
john 8d2f55771c Fix MindSpace preview crash and simplify balance ring popover.
Wrap preview mode in ChatProvider so useChat works, and drop recharge ledger from the balance dropdown to keep it compact.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-16 15:55:20 +08:00
John d376161ab0 docs: publish v0.1.0-baseline for team development
Announce the v0.1.0-baseline tag (25d9c8c) as the starting point for all
future branches and document checkout workflow in docs/BASELINE.md.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-15 23:46:26 -07:00
1162 changed files with 214626 additions and 6705 deletions
@@ -0,0 +1,110 @@
---
name: memind-page-data-survey-verify
description: >-
Verify Page Data survey update chains (e.g. john4 children-hobby q4_diet_meals)
without manual chat input. Use when the user asks to 验证问卷链路, 饮食偏好测试,
page-data-collect 回归, 儿童爱好问卷验证, or after agent-run / MCP / page-data changes.
---
# Page Data 问卷链路自动验证
用户说「**帮我验证问卷 / 饮食偏好链路**」「**不用我手动测**」时,**必须**走本 skill,不要只在浏览器里手点。
## 两条路径
| 路径 | 何时用 | 命令 | 耗时 |
|------|--------|------|------|
| **A. 产物验证(默认)** | Agent 已跑完,或只改 Page Data / HTML / 策略 | 见下方 | ~5s |
| **B. 全链路 E2E** | 要测 Agent 聊天 + 工具 + 交付 | 见下方 | ~310min |
### A. 产物验证(推荐日常)
前提:Portal 已运行(`pnpm dev`),默认 `http://127.0.0.1:8081`
```bash
npm run verify:children-hobby-diet-survey
```
等价:
```bash
node scripts/verify-children-hobby-diet-survey.mjs
```
可选:
```bash
node scripts/verify-children-hobby-diet-survey.mjs --no-insert # 不写测试提交
node scripts/verify-children-hobby-diet-survey.mjs --no-runs # 不查 orphan running
```
**自动检查项:**
1. SQLite 表 `children_hobby_survey``q4_diet_meals`
2. dataset 注册 insert 列含 `q4_diet_meals`
3. 问卷 / 后台 HTML 含饮食字段与 Page Data 客户端
4. 公开页 policy 允许 insert `q4_diet_meals`
5. MindSpace URL HTTP 200
6. 公开 insert API 实测提交(默认开启)
7. 无 orphan `running` agent run(避免前端一直 loading
### B. 全链路 E2E(测 Agent
```bash
npm run test:scenario:john4-diet
```
场景文件:[`scenarios/john4-children-hobby-diet-update.json`](../../../scenarios/john4-children-hobby-diet-update.json)
- 账户:`john4` / `888888`(可用 `JOHN4_PASSWORD` 覆盖)
- 话术:**「问卷页面再增加一个饮食偏好,比如每日几顿这种」**
- 技能:`page-data-collect`
- 超时:10 分钟
- 结束后自动跑与路径 A 相同的产物验证
## Agent 工作流
1. **确认 Portal**`curl -sf http://127.0.0.1:8081/auth/status`
2. **默认跑路径 A**;用户明确要测 Agent 再跑路径 B
3. **失败时**:读失败项 → 修代码/环境 → 重跑同一条命令
4. **汇报**:用下方模板
## 已知链路风险(非权限问题)
验证通过仍可能出现过这些**过程性**问题,写入排查结论时一并说明:
| 现象 | 根因 | 是否权限 |
|------|------|----------|
| 前端一直 loading | agent run 孤儿化(Portal 重启) | ❌ |
| 工具 `-32603: Transport closed` | sandbox-fs MCP 子进程断开 | ❌ |
| insert 403 columns_not_allowed | policy 未更新(bind 失败) | ⚠️ 策略,非用户账号 |
| Agent 用 shell 写 HTML | MCP 不稳定时的绕路 | ❌ |
## 结果模板
```markdown
## 问卷饮食偏好链路验证
- 模式:产物验证 / E2E
- Portalhttp://127.0.0.1:8081
- 用户:john4
- 结果:通过 / 失败
### 检查项
1. SQLite q4_diet_meals — 通过/失败
2. HTML 问卷+后台 — 通过/失败
3. Page Data policy — 通过/失败
4. 公开 insert API — 通过/失败
5. Agent run 无 orphan — 通过/失败
### 失败项与下一步
```
## 与其它 skill 分工
| 诉求 | 用哪个 |
|------|--------|
| 验证已有问卷增量(本案例) | **本 skill** |
| 通用聊天+做页面场景 | `memind-scenario-test` |
| 改代码后单测/守卫 | `memind-test` |
| Page Data 单元测试 | `npm run verify:page-data` |
@@ -0,0 +1,108 @@
---
name: memind-scenario-test
description: >-
Run Memind end-to-end scenario simulations (login, multi-turn chat, page
generation, public URL checks). Use when the user asks for 模拟场景测试, 场景测试,
E2E 流程验证, 模拟用户操作, or describes a step-by-step chat/page test flow.
---
# Memind 场景模拟测试
用户说「**帮我模拟场景测试**」或描述多步聊天/做页面流程时,**必须**走本 skill,不要手动拼 curl 或浏览器点选。
## 唯一入口
```bash
node scripts/run-scenario-test.mjs --scenario <id>
```
列出场景:
```bash
node scripts/run-scenario-test.mjs --list
```
## 前置条件
1. 本地 Portal 已运行(默认 `http://127.0.0.1:8081`,可用 `pnpm dev`
2. goosed / agent 链路可用(场景会真实发消息并等待 agent 回复)
3. 账户默认 `john` / `888888`;密码可用 `JOHN_PASSWORD` 覆盖
启动前检查:
```bash
curl -sf http://127.0.0.1:8081/auth/status
```
## 默认场景:苏州攻略页面
对应用户定义的流程,场景文件 [`scenarios/suzhou-page.json`](../../../scenarios/suzhou-page.json)
1. 登录 `john` / `888888`
2. 发送 `hi`,等待 assistant 回复
3. 发送 `帮我看看苏州攻略,1日攻略,做一个页面`
4. 验证:收到回复、含苏州关键词、有公网页面链接、HTTP 200、页面内容命中关键词
执行:
```bash
node scripts/run-scenario-test.mjs --scenario suzhou-page
```
## Agent 工作流
1. **确认场景**:用户未指定时默认 `suzhou-page`;说了别的流程则查 `--list` 或新建场景文件
2. **确认服务**Portal `/auth/status` 必须 200
3. **执行脚本**:完整跑完,不要中途改用浏览器手点
4. **失败处理**:读失败项 → 修代码或环境 → 重跑同一场景
5. **汇报**:用下方模板
## 扩展新场景
复制 [`scenarios/_template.json`](../../../scenarios/_template.json) 为 `scenarios/<id>.json`
步骤类型(当前支持):
| action | 说明 |
|--------|------|
| `login` | HTTP 登录,取 cookie + userId |
| `chat` | 发消息(同 session 多轮),等 run 终态 + assistant 新回复 |
`chat.expect` 可选断言:
- `assistantMinChars` / `timeoutMs`
- `replyKeywords`:回复文本关键词
- `page.keywords` / `requirePublicLink` / `requireHttp200` / `requireMindspaceCover`
新增更复杂步骤(截图、微信、多账户)时:先扩展 `scripts/scenario-test-lib.mjs`,再加场景 JSON,**不要**在 skill 里写死一次性命令。
## 结果模板
```markdown
## 场景测试结果
- 场景:suzhou-page(苏州攻略一日游页面)
- Portalhttp://127.0.0.1:8081
- 账户:john
- 结果:通过 / 失败
### 步骤
1. 登录 — 通过
2. hi → 回复 — 通过(N 字)
3. 苏州页面 — 通过 / 失败
### 页面(如有)
- 链接:
- HTTP
- 关键词:
### 失败项与下一步
```
## 与 memind-test 的分工
| 诉求 | 用哪个 |
|------|--------|
| 模拟真实用户聊天 + 做页面 | **本 skill**`run-scenario-test.mjs` |
| 改代码后跑单测/回归守卫 | `memind-test` skill`run-memind-tests.mjs` |
| 103 发包 | `portal-release` skill |
+78
View File
@@ -0,0 +1,78 @@
---
name: memind-test
description: >-
Run Memind scoped or release tests automatically after code changes. Use when
the user asks to test, verify, run tests, check regressions, or before
merging/releasing; also after editing protected MindSpace/chat/agent paths.
---
# Memind 自动测试
不要手动拼凑 `node --test` 命令。统一入口:
```bash
node scripts/run-memind-tests.mjs --mode <mode>
```
## 选模式
| 用户意图 | 模式 |
|----------|------|
| 改完代码、日常验证 | `changed`(默认) |
| 快速冒烟 | `quick` |
| 只跑回归守卫 | `guards` |
| 发包前 | `release` |
| 全量单测 | `full` |
示例:
```bash
node scripts/run-memind-tests.mjs
node scripts/run-memind-tests.mjs --mode quick
node scripts/run-memind-tests.mjs --mode release
```
对比基准分支时用 `--base origin/main`
## Agent 工作流
1. **判断模式**:用户说「测试/验证/跑一下」→ `changed`;说「发包前」→ `release`;说「全量」→ `full`
2. **执行**:在仓库根目录跑脚本,不要跳过。
3. **失败时**:读报错 → 修代码 → 用同一模式重跑,直到通过。
4. **汇报**:用下方模板,不要只说「通过了」。
## 受保护路径(改后必跑 guards)
改这些文件时,即使 `changed` 未命中也要加跑 `guards`
- `mindspace-public-finish-sync.mjs``chat-finish-sync.mjs`
- `conversation-display.mjs``src/utils/message.ts``src/hooks/useTKMindChat.ts`
- `mindspace-pages.mjs``mindspace-page-sync-service.mjs``server.mjs`
```bash
node scripts/run-memind-tests.mjs --mode guards
```
详见 [docs/regression-guards/README.md](../../../docs/regression-guards/README.md)。
## 结果模板
```markdown
## 测试结果
- 模式:`changed` / `quick` / `guards` / `release` / `full`
- 变更文件:N 个(列出关键路径)
- 执行:X 个 test + Y 个 verify
- 结果:通过 / 失败
### 失败项(如有)
- 命令:
- 错误摘要:
- 下一步:
```
## 与发布 skill 的关系
- 日常开发:本 skill + `changed` / `guards`
- 103 生产发布:用 `portal-release` skill,其发包前测试与本 skill 的 `release` 模式一致
- 不要混用「手动挑几个 test 文件」替代上述入口
+170
View File
@@ -0,0 +1,170 @@
---
name: portal-release
description: Package, deploy, verify, and roll back the Memind Portal runtime on 103 production. Use for any "打包/发布/上线/回滚/发布验证" request targeting 103.
---
# Portal 生产发布 / 验证 / 回滚
103(`john@58.38.22.103`)是唯一生产 Portal 主机。这个 skill 是打包、发布、验证、回滚的**唯一入口**——不要现场发明新流程,不要直接 SSH 到 103 手改代码或手写文件到 `MindSpace/`
## 0. 发布前置检查(必须)
```bash
git status --short
```
**worktree 必须干净。** 如果这个仓库有并发运行的其他 agent/session(本仓库经常有),工作区里可能混着别人未提交的改动:
- 先辨认清楚哪些文件是"这次要发布的改动",哪些是别人正在写的无关改动
- **不要**未经确认就自己 stash 别人的未提交内容——这是需要用户明确同意的动作,先问,拿到同意后再 `git stash push -u -m "<说明>" -- <具体文件...>`
- 发布完成后必须 `git stash pop` 把对方的改动还回去,不要留着不还
确认当前分支和要发布的 commit 就是打算上线的那个(`git log --oneline -3`)。
## 1. 发布前测试(必须,对应 docs/发包必看.md #1.5
```bash
node --test db.test.mjs capabilities.test.mjs llm-providers.test.mjs wechat-mp.test.mjs
```
全绿之后才能进入打包发布,不要跳过。
## 2. 打包 + 发布(唯一入口)
先 dry-run 确认构建产物正常(不会碰生产):
```bash
bash scripts/release-portal-runtime-prod.sh --skip-tests --dry-run
```
确认无误后正式发布(`--skip-tests` 是因为第 1 步已经手动跑过;这里不再重复跑脚本内置的窄范围测试):
```bash
bash scripts/release-portal-runtime-prod.sh --skip-tests --yes
```
这个脚本会自动完成:
1. 本机构建 `.runtime/portal`
2. 上传到 103
3. **103 备份当前 `/Users/john/Project/Memind` 全目录**`full_backup`
4. **103 单独备份持久目录**`.env``MindSpace/``data/``users/``.tailscale/``public/plaza-covers/``logs/``persist_backup`
5. 原子切换 live 目录(旧源码树移入 `archived_source`,不是删除)
6. 更新 LaunchAgent,健康检查 `http://127.0.0.1:8081/api/status` 200
7. 脚本内置 `trap rollback ERR`:如果切换过程中途失败,会自动尝试把旧目录移回来并重启旧服务——但**这只覆盖脚本执行期间的失败**,脚本成功退出之后发现问题需要走第 4 节手动回滚
**记录脚本输出里的这几行,回滚和报告都要用**
```
release_id=...
archived_source=/Users/john/Project/archives/Memind-source-before-<release_id>
full_backup=/Users/john/Project/backups/memind/memind-full-<release_id>-before.tar.gz
persist_backup=/Users/john/Project/backups/memind/memind-persisted-<release_id>-before.tar.gz
```
## 3. 发布后验证(必须,不能只看 /api/status
### 3.1 健康检查 + auth/login(本机执行)
```bash
curl -k -i https://m.tkmind.cn/auth/login \
-H 'content-type: application/json' \
--data '{"username":"john","password":"wrong-password"}' | head -20
```
必须是 **401** + `用户名或密码错误`。如果是 `503` + `未配置用户数据库或访问密码`,说明用户系统 bootstrap 失败——不是简单健康检查能发现的问题,必须当场处理,不能算发布成功。
### 3.2 Portal + 九个 goosed 实例(SSH 103
```bash
ssh john@58.38.22.103 '
printf "portal="; curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:8081/api/status
for p in $(seq 18006 18014); do
printf "goosed_${p}="
curl -k -s -o /dev/null -w "%{http_code}\n" https://127.0.0.1:${p}/status
done
pid=$(pgrep -f "node .*server.mjs" | head -1)
echo "portal_pid=${pid}"
ps eww -p "$pid" | tr " " "\n" | awk -F= "/^(DATABASE_URL|H5_PORT|TKMIND_API_TARGETS|GOOSED_MCP_NODE_PATH|GOOSED_MCP_SERVER_PATH)=/ {print \$1\"=SET\"}"
'
```
必须全部是 `200`Portal + 9 个 goosed target),五个 env var 全部 `SET`
### 3.3 日志关键词检查(SSH 103
```bash
ssh john@58.38.22.103 '
tail -200 ~/Library/Logs/memind-portal.log |
egrep "User auth bootstrap failed|ER_PARSE_ERROR|Cannot find package|Failed to add extension|No such file|Unknown extension|Provider not set|not configured" || echo "no error keywords found"
'
```
新启动之后不能再出现这些关键词。
### 3.4 真实业务路径验证(必须,测试账号 `john`)
只看健康接口不算数,必须走一次真实的"生成页面 → 发布 → 能访问"链路。**禁止直接 SSH 到 103 手写文件到 `MindSpace/` 目录充当验证**——那是绕过应用本身的路径,不代表真实用户会走的流程,而且是对生产文件系统的越权写入。只能通过应用自己的 API。
密码通过环境变量传入,**不要把明文密码写进这个文件或提交到仓库**(沿用 `scripts/fruit-theme-john-e2e.mjs` 里的既有约定:`JOHN_PASSWORD` / `H5_ACCESS_PASSWORD`,向用户当场要,或从 `.env` 之外的安全渠道取):
```bash
CJ=/tmp/portal-release-verify-cookies.txt
# 1. 登录(JOHN_PASSWORD 从环境变量取,不要硬编码)
curl -k -s -c "$CJ" -X POST https://m.tkmind.cn/auth/login \
-H 'Content-Type: application/json' \
-d "{\"username\":\"john\",\"password\":\"${JOHN_PASSWORD}\"}"
# 必须 authenticated:true
# 2. 通过真实 API 创建一个页面(验证 mindspace pages 管线本身没坏)
BODY=$(node -e "console.log(JSON.stringify({title:'发布验证页',summary:'release verify',content:'<!DOCTYPE html><html><head><meta charset=\"UTF-8\"><title>发布验证页</title><meta name=\"mindspace-cover\" content=\'{\"tag\":\"报告\"}\'></head><body>ok</body></html>',content_format:'html',page_type:'html',category_code:'draft'}))")
curl -k -s -X POST https://m.tkmind.cn/api/mindspace/v1/pages \
-H "Content-Type: application/json" -b "$CJ" -c "$CJ" -d "$BODY"
# 必须 201hasThumbnail:true
# 3. 只读验证公网静态页服务没坏:用一个已知存在的已发布页面,不要新写文件
curl -k -s -o /dev/null -w '%{http_code}\n' \
"https://m.tkmind.cn/MindSpace/<已知已发布用户ID>/public/<已知文件名>.html"
# 必须 200
```
第 2 步创建的测试页面记录会留在生产库里(`draft`/`private`,风险很低)。**不要自己调用 DELETE 清理**——删除生产数据记录需要用户明确同意,验证完之后把 page id 报给用户,让用户决定是否清理。
## 4. 手动回滚(脚本成功退出之后才发现问题时用)
**优先方式:重新发布上一个已知good的 commit**,而不是手动倒腾备份目录——这样能完整复用第 2 节的持久化保留逻辑,不会把回滚期间用户新写的 `MindSpace`/`data`/`users` 数据搞丢:
```bash
git log --oneline -5 # 找到上一个已验证通过的 commit
git checkout <上一个好的 commit 或分支>
bash scripts/release-portal-runtime-prod.sh --skip-tests --yes
# 然后重新走第 3 节完整验证
```
**紧急方式**(本地仓库回不去、必须直接用远端备份时):
```bash
ssh john@58.38.22.103 '
launchctl bootout gui/$(id -u)/cn.tkmind.memind-portal 2>/dev/null || true
lsof -tiTCP:8081 -sTCP:LISTEN | xargs kill 2>/dev/null || true
mv /Users/john/Project/Memind /Users/john/Project/Memind-bad-release-$(date +%s)
mv <archived_source 路径> /Users/john/Project/Memind
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/cn.tkmind.memind-portal.plist
launchctl kickstart -k gui/$(id -u)/cn.tkmind.memind-portal
'
```
⚠️ `archived_source` 里的 `MindSpace`/`data`/`users` 是**发布那一刻**的快照。如果坏版本上线后已经有用户写入了新数据,直接整体换回去会丢失这段时间的新数据——先确认这一点,必要时把坏版本目录里当前的 `MindSpace`/`data`/`users` 复制出来,回滚后再合并回去,而不是整体覆盖。回滚后必须重新走第 3 节验证。
## 5. 发布完成后的最小回报格式(必须,不能只说"已发布成功")
- release id / git head / git branch
- full backup 路径
- persisted backup 路径
- Portal 健康结果(200/非200
- `/auth/login` 结果(401 + 正确消息,还是别的)
- `18006``18014` 健康结果(共 9 个 target)
- 日志关键词检查结果
- 第 3.4 节真实业务路径验证结果(含遗留的测试 page id,交给用户决定是否清理)
- 是否发现并处理了问题;如果发布后发现回滚,说明触发原因
+31
View File
@@ -0,0 +1,31 @@
---
description: 标准化分支、测试、发布闸门(始终应用)
alwaysApply: true
---
# 标准化开发测试发布闸门
开始任何开发、修复、发布前,先读:
- `ENGINEERING_WORKFLOW_RULES.md`
- `PRODUCTION_RELEASE_RULES.md`
- `AGENTS.md`
必须遵守:
- 新建分支必须基于最新 `origin/main`,推荐执行 `bash scripts/new-branch.sh feature/xxx`
- 分支代码必须先合并进 `main`,确认 `main` 正常后,才允许发布
- 发布只能从完整 `main` 打整包,禁止从功能分支、单个 commit、单个修复或局部差异单包发布
- 发布前必须确认 CI 已通过,且没有未合并的关键变更
- 发布前必须重新检查当前分支是否落后 `origin/main`
- 发布来源必须是干净、可追溯的 Git commit
- 禁止从脏工作区、detached HEAD、落后主线的分支发布
- 禁止直接 `rsync` 到 `103/105` 或 SSH 到生产手改源码
发布前必须执行:
```bash
bash scripts/check-release-ready.sh
```
如需临时绕过,只能在用户明确批准后使用项目文档中记录的显式环境变量。
@@ -0,0 +1,27 @@
---
description: MindSpace 公开页 edit_file 落盘与聊天 Finish 同步回归守卫(勿盲覆盖)
globs: mindspace-public-finish-sync.mjs,chat-finish-sync.mjs,conversation-display.mjs,src/hooks/useTKMindChat.ts,src/utils/message.ts,server.mjs,chat-skills.mjs
alwaysApply: false
---
# MindSpace 发布 & 聊天 Finish — 回归守卫
已验证行为(2026-06-29)。删改下列逻辑前必须先读 `docs/regression-guards/mindspace-publish-and-chat-finish.md` 并跑 `npm run verify:mindspace-publish-guards`。
## 公开 HTML
- `edit_file` 的 `old_str`/`new_str` **必须**经 `mindspace-public-finish-sync.mjs` 落盘并**覆盖**已有 `public/*.html`
- 不得回退为仅处理 `write_file` 全量 `content`
## 聊天 Finish
- **禁止** `syncSessionMessages` / `UpdateConversation` 用服务端 snapshot **盲覆盖**本地已展示消息
- Finish 同步 **必须**使用 `mergeConversationSnapshot`(见 `chat-finish-sync.mjs`),并在服务端条数落后时重试
- **禁止**无 hint 时命中 session snapshot 缓存(需 `hint_mc` 与 `hint_ua` 同时匹配)
- 用户可见文案 **必须**优先 `metadata.displayText`;否则用 `deriveUserFacingText` 剥离 routing / skill / `[用户身份]` 等 agent-only 前缀
## 改完必跑
```bash
npm run verify:mindspace-publish-guards
```
@@ -0,0 +1,108 @@
---
name: memind-scenario-test
description: >-
Run Memind end-to-end scenario simulations (login, multi-turn chat, page
generation, public URL checks). Use when the user asks for 模拟场景测试, 场景测试,
E2E 流程验证, 模拟用户操作, or describes a step-by-step chat/page test flow.
---
# Memind 场景模拟测试
用户说「**帮我模拟场景测试**」或描述多步聊天/做页面流程时,**必须**走本 skill,不要手动拼 curl 或浏览器点选。
## 唯一入口
```bash
node scripts/run-scenario-test.mjs --scenario <id>
```
列出场景:
```bash
node scripts/run-scenario-test.mjs --list
```
## 前置条件
1. 本地 Portal 已运行(默认 `http://127.0.0.1:8081`,可用 `pnpm dev`
2. goosed / agent 链路可用(场景会真实发消息并等待 agent 回复)
3. 账户默认 `john` / `888888`;密码可用 `JOHN_PASSWORD` 覆盖
启动前检查:
```bash
curl -sf http://127.0.0.1:8081/auth/status
```
## 默认场景:苏州攻略页面
对应用户定义的流程,场景文件 [`scenarios/suzhou-page.json`](../../../scenarios/suzhou-page.json)
1. 登录 `john` / `888888`
2. 发送 `hi`,等待 assistant 回复
3. 发送 `帮我看看苏州攻略,1日攻略,做一个页面`
4. 验证:收到回复、含苏州关键词、有公网页面链接、HTTP 200、页面内容命中关键词
执行:
```bash
node scripts/run-scenario-test.mjs --scenario suzhou-page
```
## Agent 工作流
1. **确认场景**:用户未指定时默认 `suzhou-page`;说了别的流程则查 `--list` 或新建场景文件
2. **确认服务**Portal `/auth/status` 必须 200
3. **执行脚本**:完整跑完,不要中途改用浏览器手点
4. **失败处理**:读失败项 → 修代码或环境 → 重跑同一场景
5. **汇报**:用下方模板
## 扩展新场景
复制 [`scenarios/_template.json`](../../../scenarios/_template.json) 为 `scenarios/<id>.json`
步骤类型(当前支持):
| action | 说明 |
|--------|------|
| `login` | HTTP 登录,取 cookie + userId |
| `chat` | 发消息(同 session 多轮),等 run 终态 + assistant 新回复 |
`chat.expect` 可选断言:
- `assistantMinChars` / `timeoutMs`
- `replyKeywords`:回复文本关键词
- `page.keywords` / `requirePublicLink` / `requireHttp200` / `requireMindspaceCover`
新增更复杂步骤(截图、微信、多账户)时:先扩展 `scripts/scenario-test-lib.mjs`,再加场景 JSON,**不要**在 skill 里写死一次性命令。
## 结果模板
```markdown
## 场景测试结果
- 场景:suzhou-page(苏州攻略一日游页面)
- Portalhttp://127.0.0.1:8081
- 账户:john
- 结果:通过 / 失败
### 步骤
1. 登录 — 通过
2. hi → 回复 — 通过(N 字)
3. 苏州页面 — 通过 / 失败
### 页面(如有)
- 链接:
- HTTP
- 关键词:
### 失败项与下一步
```
## 与 memind-test 的分工
| 诉求 | 用哪个 |
|------|--------|
| 模拟真实用户聊天 + 做页面 | **本 skill**`run-scenario-test.mjs` |
| 改代码后跑单测/回归守卫 | `memind-test` skill`run-memind-tests.mjs` |
| 103 发包 | `portal-release` skill |
+79
View File
@@ -0,0 +1,79 @@
---
name: memind-test
description: >-
Run Memind scoped or release tests automatically after code changes. Use when
the user asks to test, verify, run tests, check regressions, or before
merging/releasing; also after editing protected MindSpace/chat/agent paths.
---
# Memind 自动测试
不要手动拼凑 `node --test` 命令。统一入口:
```bash
node scripts/run-memind-tests.mjs --mode <mode>
```
## 选模式
| 用户意图 | 模式 |
|----------|------|
| 改完代码、日常验证 | `changed`(默认) |
| 快速冒烟 | `quick` |
| 只跑回归守卫 | `guards` |
| 发包前 | `release` |
| 全量单测 | `full` |
示例:
```bash
node scripts/run-memind-tests.mjs
node scripts/run-memind-tests.mjs --mode quick
node scripts/run-memind-tests.mjs --mode release
```
对比基准分支时用 `--base origin/main`
## Agent 工作流
1. **判断模式**:用户说「测试/验证/跑一下」→ `changed`;说「发包前」→ `release`;说「全量」→ `full`
2. **执行**:在仓库根目录跑脚本,不要跳过。
3. **失败时**:读报错 → 修代码 → 用同一模式重跑,直到通过。
4. **汇报**:用下方模板,不要只说「通过了」。
## 受保护路径(改后必跑 guards)
改这些文件时,即使 `changed` 未命中也要加跑 `guards`
- `mindspace-public-finish-sync.mjs``chat-finish-sync.mjs`
- `conversation-display.mjs``src/utils/message.ts``src/hooks/useTKMindChat.ts`
- `mindspace-pages.mjs``mindspace-page-sync-service.mjs``server.mjs`
```bash
node scripts/run-memind-tests.mjs --mode guards
```
详见 [docs/regression-guards/README.md](../../../docs/regression-guards/README.md)。
## 结果模板
```markdown
## 测试结果
- 模式:`changed` / `quick` / `guards` / `release` / `full`
- 变更文件:N 个(列出关键路径)
- 执行:X 个 test + Y 个 verify
- 结果:通过 / 失败
### 失败项(如有)
- 命令:
- 错误摘要:
- 下一步:
```
## 与发布 skill 的关系
- 日常开发:本 skill + `changed` / `guards`
- **模拟用户聊天/做页面**:用 `memind-scenario-test` skill`run-scenario-test.mjs`
- 103 生产发布:用 `portal-release` skill,其发包前测试与本 skill 的 `release` 模式一致
- 不要混用「手动挑几个 test 文件」替代上述入口
+175 -34
View File
@@ -1,28 +1,129 @@
# TKMind H5 环境变量(复制为 .env 后按需修改)
#
# 本地开发(默认只做本地,不自动发布生产):
# 1. pnpm dev # 热更新 (http://127.0.0.1:5173)
# 2. pnpm run test:local # 生产构建本地跑 (http://127.0.0.1:8081)
# 3. pnpm run test:fruit-john-e2e # john 水果主题:预览图 + 可点击链接 + 我的空间
# 4. node scripts/mindspace-rebuild-thumbnails.mjs # 批量重建预览图(可选)
#
# 发布生产:仅当明确要求「发布生产」时再执行:
# pnpm run deploy:105 或 pnpm run deploy:prod 或 ./rsync_to_server.sh
# 105 配置见 deploy/h5-105.env.example
# 本地开发(127.0.0.1 + 端口,见 docs/local-dev.md
# pnpm dev
# MindSpace: http://127.0.0.1:5173/?preview=mindspace
#
# 后端代理(server.mjs / vite dev proxy 共用)
TKMIND_API_TARGET=https://127.0.0.1:18006
TKMIND_SERVER__SECRET_KEY=local-dev-secret
H5_PORT=8081
# Agent 生成链接用(本地开发建议 8081;生产再改为 https://goo.tkmind.cn
H5_PUBLIC_BASE_URL=http://127.0.0.1:8081
# MindSpace 与 Plaza 跨子域共享登录(如 g2.tkmind.cn + plaza.tkmind.cn
# H5_COOKIE_DOMAIN=.tkmind.cn
# Vite UI 预览用 5173Agent 交付的 MindSpace 公开页 + Page Data API 走 Portal8081)。
# pnpm dev / dev-core 在未显式覆盖时会把 H5_PUBLIC_BASE_URL 设为 8081
H5_PUBLIC_BASE_URL=http://127.0.0.1:5173
# Local Umami analytics (disabled by default; points only to the local
# memind-analytics service when enabled).
# MEMIND_ANALYTICS_ENABLED=true
# MEMIND_ANALYTICS_URL=http://127.0.0.1:3100
# MEMIND_ANALYTICS_WEBSITE_ID=<local Umami Website ID>
# MEMIND_ANALYTICS_ID_SECRET=<local-only pseudonymization secret>
# MEMIND_ANALYTICS_DOMAINS=127.0.0.1,localhost
# 生产 H5 public base 当前临时切到 https://mm.tkmind.cn。
# 后续公网 H5 不再依赖 105 转发链路;m.tkmind.cn 仅作为 legacy/rollback 记录处理。
# H5_PUBLIC_BASE_URL=https://mm.tkmind.cn
# VITE_MINDSPACE_BASE=https://mm.tkmind.cn
# Memind 2.0 runtime control plane(生产启用 Redis;本地开发可留空回退到健康轮询)
# MEMIND_RUNTIME_REDIS_URL=redis://127.0.0.1:6379/0
# MEMIND_RUNTIME_REDIS_NAMESPACE=memind:runtime
# Code-tool agent run 灰度开关(默认关闭)。
# 后端必须先开启 MEMIND_AGENT_CODE_RUNS_ENABLEDH5 构建开关才会生效。
# 开启后,页面编辑子聊天会传 tool_mode=code;普通聊天仍需同时开启 AUTODETECT 才会按文本自动识别代码任务。
# MEMIND_AGENT_CODE_RUNS_ENABLED=0
# VITE_AGENT_CODE_RUNS_ENABLED=0
# VITE_AGENT_CODE_RUNS_AUTODETECT=0
# Tool Gateway Queue v0/agent/runs 后台任务队列,默认保守限流)。
# MEMIND_AGENT_RUN_QUEUE_CONCURRENCY=1
# MEMIND_AGENT_RUN_TIMEOUT_MS=900000
# P6.1 外部 Tool Worker 接管入口。默认 Portal 内部 auto-dispatch 保持开启;
# 只有外部 worker 验证就绪后,才把 Portal 设为 0 并独立运行 scripts/agent-run-worker.mjs。
# MEMIND_AGENT_RUN_AUTODISPATCH=1
# MEMIND_AGENT_RUN_WORKER_POLL_MS=1000
# MEMIND_AGENT_RUN_WORKER_BATCH_SIZE=1
# MEMIND_AGENT_RUN_HEARTBEAT_MS=30000
# MEMIND_AGENT_RUN_HEARTBEAT_STALE_MS=90000
# MEMIND_AGENT_RUN_WORKER_EXPECT_RUNNING=0
# Runtime SLO 日报(默认每日 23:55 写 reports/runtime-slo)。
# MEMIND_RUNTIME_REPORT_DIR=/Users/john/Project/Memind/reports/runtime-slo
# MEMIND_RUNTIME_SLO_HOUR=23
# MEMIND_RUNTIME_SLO_MINUTE=55
# H5 Session Brokerdocs/h5-session-architecture-20260706.md Patch 1+
# 本地开发:Patch 2 接入后可设 1 验证 broker 路径;默认 0 保持 userAuth 直调。
# 103 生产:仅在灰度窗口于服务器 /Users/john/Project/Memind/.env 设置,勿把生产值写入 Git。
# MEMIND_SESSION_BROKER_ENABLED=0
# --- 本地全量联调示例(复制到 .env,勿提交 Git)---
# MEMIND_SESSION_BROKER_ENABLED=1
# MEMIND_ROUTER_NORMALIZED_DECISION=1
# MEMIND_SSE_EVENT_TAXONOMY=1
# MEMIND_RUN_STREAM_REPLAY=1
# MEMIND_SESSION_STREAM_REPLAY=1
# MEMIND_SESSION_BROKER_METRICS=1
# MEMIND_H5_HTML_FINISH_GUARD=1
# 启动后 Portal 日志应出现:[Portal] H5 session flags: ...
# 103 生产 goosed 多实例示例(仅服务器 .env,见 docs/103-runtime-topology.md):
# TKMIND_API_TARGET=https://127.0.0.1:18006
# TKMIND_API_TARGET_1=https://127.0.0.1:18007
# H5 Router normalized decisiondocs/h5-session-architecture-20260706.md Patch 3
# 默认 0/offgateway 仍读 legacy route
# shadow:只打 [router-shadow] 日志,行为不变
# 1/ongateway 优先读 classification.decision.route / session_hint
# MEMIND_ROUTER_NORMALIZED_DECISION=0
# H5 Session stream replaydocs/h5-session-architecture-20260706.md Patch 4c
# 默认 0session SSE 仍纯透传 goosed;设 1 时 Portal 持久化 session 事件并支持 Last-Event-ID 重连补发。
# MEMIND_SESSION_STREAM_REPLAY=0
# H5 Session Broker metricsdocs/h5-session-architecture-20260706.md §13.4
# 默认 0:不打 structured log;设 1 时输出 [session_broker.*] 行
# MEMIND_SESSION_BROKER_METRICS=0
# H5 SSE event taxonomydocs/h5-session-architecture-20260706.md Patch 4
# 默认 0:不改变 SSE wire format;设 1 时在 session/run SSE payload 附加 taxonomy 字段(shadow)。
# MEMIND_SSE_EVENT_TAXONOMY=0
# H5 goosed proxy boundarydocs/h5-session-architecture-20260706.md Patch 5
# CI/发版前跑:npm run verify:goosed-proxy-boundary
# 新增 goosed 调用须走 tkmind-proxyMindSpace 例外见 goosed-proxy-boundary.mjs allowlist
# H5 public HTML 假交付 guarddocs/pending-fixes/h5-public-html-fake-delivery-guard-20260706.md
# 默认 0:仅 warn;设 1 时 Finish 后检测缺失 public/*.html / assets/* 并自动 session repair(每 session 1 次)
# MEMIND_H5_HTML_FINISH_GUARD=0
# H5 run SSE replayPatch 4b,仅本地/测试分支;默认关,未合并 main / 未上 103)
# 设 1 时 GET /agent/runs/:id/events 使用 h5_agent_run_events + Last-Event-ID 重连回放
# MEMIND_RUN_STREAM_REPLAY=0
# ===== memind_adm(独立后台服务)=====
# 平台超管 /admin-api/* 与广场运营 /api/ops/v1/* 已从公网服务拆出,独立进程运行。
# 登录仍在主域完成;后台凭 H5_COOKIE_DOMAIN=.tkmind.cn 共享的会话 Cookie 鉴权(生产务必设置)。
ADMIN_PORT=8082
ADMIN_HOST=127.0.0.1
ADMIN_PUBLIC_HOST=gadm.tkmind.cn
# 本进程挂载哪些控制台(可拆分架构):admin=平台超管, ops=广场运营。
# 默认两者合一;将来拆成两个进程时,A 实例设 admin、B 实例设 ops,路由代码无需改动。
# ADMIN_CONSOLES=admin,ops
# 每控制台独立网络护栏(逗号分隔;留空=放开。支持精确 IP 与 CIDR)。
# 超管面建议收得最紧(仅内网/VPN),广场运营可放宽给审核团队网段。
# ADMIN_API_ALLOWED_HOSTS=gadm.tkmind.cn
# ADMIN_API_IP_ALLOWLIST=10.0.0.0/8,127.0.0.1
# OPS_API_ALLOWED_HOSTS=gadm.tkmind.cn
# OPS_API_IP_ALLOWLIST=
# 多用户系统(MySQL 配置后启用;未配置时回退到 H5_ACCESS_PASSWORD
DATABASE_URL=mysql://boot:password@localhost:3306/tkmind
# 或分别设置 MYSQL_HOST / MYSQL_PORT / MYSQL_USER / MYSQL_PASSWORD / MYSQL_DATABASE
H5_USERS_ROOT=/root/tkmind_go/users
# 新用户赠送余额(人民币分,500 = ¥5.00;勿与美元 cents 混淆)
H5_SIGNUP_BALANCE_CENTS=500
H5_ADMIN_USERNAME=admin
H5_ADMIN_PASSWORD=change-me-admin
@@ -31,28 +132,37 @@ H5_ADMIN_PASSWORD=change-me-admin
# LLM Key 数据库加密(可选;默认派生自 TKMIND_SERVER__SECRET_KEY
# H5_SETTINGS_ENCRYPTION_KEY=change-me-encryption-key
# 启动时自动导入 Relay(若不存在同名配置)
# H5_RELAY_BOOTSTRAP_NAME=Relay Buyer Ollama
# H5_RELAY_BOOTSTRAP_NAME=Local Goose Relay DeepSeek
# H5_RELAY_BOOTSTRAP_URL=http://127.0.0.1:18300/relay/buyer/v1/chat/completions
# H5_RELAY_BOOTSTRAP_API_KEY=your-bearer-token
# H5_RELAY_BOOTSTRAP_MODEL=qwen2.5:3b
# H5_RELAY_BOOTSTRAP_MODELS=qwen2.5:3b,llama3.2:1b
# H5_RELAY_BOOTSTRAP_PROVIDER=ollama
# H5_RELAY_BOOTSTRAP_MODEL=deepseek-chat
# H5_RELAY_BOOTSTRAP_MODELS=deepseek-chat,deepseek-reasoner
# H5_RELAY_BOOTSTRAP_PROVIDER=deepseek
# 一键对齐本地 goosed + Goose Desktop relaynode scripts/fix-local-goose-relay.mjs
# 本地 Ollama fallbackDeepSeek 额度不足,或 andu Relay 500agent 请求体含 tools 超过 ~8.5KB)时自动切换
# Local Ollama fallback — creditsExhausted or relay 500 (nginx body limit with tool payloads).
# H5_LOCAL_LLM_FALLBACK=0
# H5_LOCAL_LLM_URL=http://127.0.0.1:11434/v1/chat/completions
# H5_LOCAL_LLM_MODEL=qwen2.5-coder:7b
# H5_LOCAL_LLM_MODEL=qwen2.5:3b
# H5_LOCAL_LLM_API_KEY=ollama
# H5_LOCAL_LLM_NAME=Local Ollama 7B
H5_ACCESS_PASSWORD=change-me
# 计费(Phase 2
# H5_USE_BACKEND_COST=1 # 优先用后端 accumulatedCostUSD)计费
# H5_USD_CNY_RATE=7.2
# H5_BILL_INPUT_CENTS_PER_1K=2
# H5_BILL_OUTPUT_CENTS_PER_1K=6
# 计费(Phase 2,金额单位均为人民币分
# 默认按 Token 单价扣费;生产推荐开启成本模式(见 docs/h5-metering-gateway.md
# H5_USE_BACKEND_COST=0
# H5_BILL_INPUT_CENTS_PER_1K=2 # 输入 Token2 分/1k(¥0.02/1k
# H5_BILL_OUTPUT_CENTS_PER_1K=6 # 输出 Token6 分/1k(¥0.06/1k
# H5_MIN_BILL_CENTS=1
# 成本模式:上游 accumulated_cost(USD) × 汇率 × 毛利
# H5_USE_BACKEND_COST=1
# H5_USD_CNY_RATE=7.2
# H5_MARGIN_MULTIPLIER=1.2
# 当 goose Finish 未带 accumulatedCost 时,按 token 估算上游 USD 成本(默认开启,设 0 关闭)
# H5_COST_ESTIMATE_FROM_TOKENS=1
# H5_COST_ESTIMATE_INPUT_USD_PER_1M=0.27
# H5_COST_ESTIMATE_OUTPUT_USD_PER_1M=1.1
# 用户自助充值(微信支付)
# H5_RECHARGE_TIERS_CENTS=500,1000,3000,5000,10000,20000
@@ -81,6 +191,10 @@ H5_ACCESS_PASSWORD=change-me
# H5_WECHAT_PLATFORM_CERT="-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----"
#
# H5_WECHAT_NOTIFY_URL=https://goo.tkmind.cn/webhooks/wechat-pay/notify
# 微信内 JSAPI 支付(服务号网页):
# - 服务号「设置 → 功能设置 → JS接口安全域名」:mm.tkmind.cn
# - 商户平台「产品中心 → 开发配置 → 支付授权目录」:https://mm.tkmind.cn/
# - 用户须先用同一服务号微信 OAuth 登录(获取 openid)后再充值
# 本地调试验签可临时开启(生产务必关闭):
# H5_WECHAT_SKIP_NOTIFY_VERIFY=0
@@ -95,6 +209,10 @@ H5_ACCESS_PASSWORD=change-me
# H5_WECHAT_OPEN_APP_ID=
# H5_WECHAT_OPEN_APP_SECRET=
# 微信小程序原生登录(wx.login → /auth/wechat-miniapp/login
# H5_WECHAT_MINIAPP_APP_ID=wx...
# H5_WECHAT_MINIAPP_APP_SECRET=小程序AppSecret
# 本地开发:pnpm dev 会自动启动 server.mjs + vite
# 若只跑前端:pnpm dev:vite(需另开 pnpm dev:server
# H5_DEV_PORTAL=http://127.0.0.1:8081
@@ -118,24 +236,47 @@ VITE_TKMIND_WORKING_DIR=/Users/john/PycharmProjects/tkmind
# 历史列表每次展示/加载条数(默认 25,与 desktop 一致)
# VITE_SESSION_PAGE_SIZE=25
# Plaza 发现广场(本机为主,105 已停用
# PLAZA_AUTO_APPROVE=true
# 文档:docs/plaza-local.md
# 首次:sudo pnpm setup:plaza-dns # 仅纯本地 HTTPS 时需要;走 Tunnel 请用 setup:plaza-dns:remove
# 日常:pnpm dev:plaza | 浏览器:pnpm open:plaza | 诊断:pnpm check:plaza
# 公网 plaza.tkmind.cn 经 Cloudflare Tunnel → 本机 :3001(需 dev:plaza 常驻)
# PLAZA_LOCAL_HOST=plaza.tkmind.cn
# Plaza 发现广场(独立域名 plaza.tkmind.cnPortal 前端链接见 VITE_PLAZA_BASE
# PLAZA_PUBLIC_BASE=https://plaza.tkmind.cn
# VITE_PLAZA_BASE=https://plaza.tkmind.cn
# CLOUDFLARE_TUNNEL_CONFIG=/Users/john/Project/ollama/cloudflare/config.yml
# CLOUDFLARE_TUNNEL_NAME=ollama-tkmind
# 本地 dev 脚本会自动注入 VITE_PLAZA_BASE=http://127.0.0.1:3001;勿把该值留进生产构建用的 .env
# VITE_PLAZA_BASE=http://127.0.0.1:3001
# 文档:docs/plaza-local.md | 本地:http://127.0.0.1:3001/plaza | 生产:https://plaza.tkmind.cn/plaza
# MindSpace(默认启用;子功能需按需开启)
# MINDSPACE_ENABLED=false
# MINDSPACE_UPLOAD_ENABLED=false
# MINDSPACE_PUBLISH_ENABLED=true
# MINDSPACE_PRIVATE_ENABLED=false
# MINDSPACE_MAX_FILE_BYTES=5242880
# Agent 后台任务(创建/执行空间内 Agent 任务,默认关闭)
# MINDSPACE_AGENT_JOBS_ENABLED=true
# MINDSPACE_INTERNAL_AGENT_SECRET=local-dev-secret
# MINDSPACE_STORAGE_ROOT=/path/to/mindspace-storage
# MINDSPACE_FREE_PUBLIC_PAGE_LIMIT=10
# ---------------------------------------------------------------------------
# Memind runtime profile(本地 vs 生产 必须区分)
# 由 scripts/memind-runtime-profile.mjs 在 pnpm dev / server.mjs 启动时应用。
#
# | profile | 场景 | MindSpace 数据路径 |
# |----------------|-------------------|--------------------|
# | local | 本机日常开发 | <repo>/data/mindspace |
# | split-service | 本机验证 103 拆分 | /Users/john/MindSpace/data/mindspace |
# | production | 103 生产服务器 | 103 .env 为准,勿提交 Git |
# ---------------------------------------------------------------------------
# 【本地开发 — 复制到 .env 的默认值】
MEMIND_RUNTIME_PROFILE=local
# MINDSPACE_STORAGE_ROOT 留空即可,自动使用 <repo>/data/mindspace
# 【本机 split-service 联调 — 需要独立 MindSpace LaunchAgent 已启动】
# MEMIND_RUNTIME_PROFILE=split-service
# MINDSPACE_REMOTE_BASE_URL=http://127.0.0.1:8082
# MINDSPACE_REMOTE_AUTH_TOKEN=local-dev-secret
# MINDSPACE_STORAGE_ROOT=/Users/john/MindSpace/data/mindspace
# 【103 生产 — 仅在服务器维护,示例勿照抄密钥】
# MEMIND_RUNTIME_PROFILE=production
# MINDSPACE_SERVER_ADAPTER=remote
# MINDSPACE_REMOTE_BASE_URL=http://127.0.0.1:8082
# MINDSPACE_REMOTE_AUTH_TOKEN=<与 cn.tkmind.mindspace-service 一致>
# MINDSPACE_STORAGE_ROOT=/Users/john/MindSpace/data/mindspace
+69
View File
@@ -0,0 +1,69 @@
name: Memind CI
on:
push:
branches:
- main
pull_request:
branches:
- main
workflow_dispatch:
permissions:
contents: read
concurrency:
group: memind-ci-${{ gitea.ref }}
cancel-in-progress: true
jobs:
verify:
name: Test, build, and release guards
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Check out exact commit
run: |
git init .
git remote add origin https://git.tkmind.cn/tkmind/memind.git
git fetch --depth=2 origin "${{ gitea.sha }}"
git checkout --detach FETCH_HEAD
test "$(git rev-parse HEAD)" = "${{ gitea.sha }}"
- name: Install system test dependencies
run: |
apt-get update
apt-get install --yes --no-install-recommends sqlite3
rm -rf /var/lib/apt/lists/*
- name: Install locked dependencies
run: |
npm ci --include=optional
SHARP_ARM64_VERSION="$(node -p "require('./package-lock.json').packages['node_modules/@img/sharp-linux-arm64'].version")"
LIBVIPS_ARM64_VERSION="$(node -p "require('./package-lock.json').packages['node_modules/@img/sharp-libvips-linux-arm64'].version")"
npm install --no-save --package-lock=false \
"@img/sharp-linux-arm64@${SHARP_ARM64_VERSION}" \
"@img/sharp-libvips-linux-arm64@${LIBVIPS_ARM64_VERSION}"
node -e "import('sharp').then((sharp) => sharp.default({ create: { width: 1, height: 1, channels: 4, background: '#000' } }).png().toBuffer())"
- name: Check patch formatting
run: git diff --check HEAD^
- name: Run full test suite
run: npm test
- name: Build production frontend
run: npm run build
- name: Verify MindSpace publish guards
run: npm run verify:mindspace-publish-guards
- name: Verify MindSpace page sync guards
run: npm run verify:mindspace-page-sync-guards
- name: Verify Page Data delivery
run: npm run verify:page-data
- name: Check published download links
run: npm run check:mindspace-public-links
+5
View File
@@ -2,10 +2,12 @@ node_modules/
ops/node_modules/
dist/
ops/dist/
.runtime/
.env
.env.local
.env.*.local
scripts/g2-aliyun-cert.env
*.log
*.pid
@@ -18,3 +20,6 @@ users/
.DS_Store
.idea/
.vscode/
.aider*
.env.experience-test
*.bak
+63
View File
@@ -0,0 +1,63 @@
Portal runtime artifact
This directory is meant to run on production without the source tree.
Required persisted items to inherit on the host:
.env
MindSpace/
data/
users/
.tailscale/
public/plaza-covers/
logs/
Bundled alongside server.mjs (required for sandbox-fs MCP):
mindspace-sandbox-mcp.mjs (esbuild bundle; includes schedule-service deps)
Post-deploy validation (scripts/check-mindspace-public-links.mjs):
Scans MindSpace/*/public/*.html for missing relative href/src/cover targets.
Runtime install mode: bundle-node-modules
Bundle target: node24
Platform agent skills (synced into user workspaces):
skills/
Key runtime differences must stay in .env, not in the artifact:
DATABASE_URL / MYSQL_*
H5_PUBLIC_BASE_URL
TKMIND_API_TARGETS / TKMIND_API_TARGET / TKMIND_API_TARGET_1
H5_USERS_ROOT / MINDSPACE_STORAGE_ROOT / MEMIND_SHARED_PUBLISH_ROOT
Deployment and operations transport:
H5 public domain: mm.tkmind.cn
Current public path: mm.tkmind.cn -> local nginx -> Portal :8081
Legacy rollback-only path: m.tkmind.cn -> 105 nginx -> reverse SSH tunnel -> Portal :8081
Future H5 traffic must not depend on 105 forwarding unless explicitly rolling back.
Streaming runtime operations:
node scripts/check-stream-runtime.mjs
node scripts/runtime-worker-drain.mjs status
node scripts/runtime-worker-drain.mjs reconcile
node scripts/runtime-worker-drain.mjs reconcile --apply
node scripts/runtime-worker-metrics.mjs status
node scripts/runtime-worker-metrics.mjs sample
bash scripts/install-runtime-metrics-agent.sh
node scripts/runtime-worker-heartbeat.mjs once
node scripts/runtime-worker-heartbeat.mjs serve
bash scripts/install-runtime-heartbeat-agent.sh
node scripts/runtime-slo-report.mjs
node scripts/runtime-slo-report.mjs --write-report
node scripts/runtime-slo-report.mjs --write-report --prune --retention-days 30
bash scripts/install-runtime-slo-report-agent.sh
bash scripts/install-runtime-slo-soak-agent.sh
node scripts/runtime-worker-drain.mjs drain goosed-3
node scripts/runtime-worker-drain.mjs undrain goosed-3
node scripts/check-tool-runtime.mjs
node scripts/check-agent-code-run-entry.mjs
curl -sk https://mm.tkmind.cn/api/runtime/status # includes toolRuntime.queue
node scripts/agent-run-worker.mjs --status
node scripts/agent-run-worker.mjs --once
bash scripts/install-agent-run-worker-agent.sh # installs disabled by default
node scripts/check-agent-run-worker.mjs # read-only LaunchAgent/queue check
node scripts/agent-run-guard.mjs # dry-run auto-pause guard check
node scripts/agent-run-guard.mjs --apply # stop worker and disable code-run gate when thresholds trip
bash scripts/install-agent-run-guard-agent.sh # installs guard LaunchAgent
+151
View File
@@ -0,0 +1,151 @@
import fs from 'node:fs';
import path from 'node:path';
const SKIP_REFERENCE = /^(?:https?:|mailto:|javascript:|data:|tel:|#|\/\/)/i;
const DOWNLOAD_EXTENSIONS = /\.(?:docx|doc|pdf|xlsx|xls|pptx|ppt|zip|rar|7z|csv)$/i;
export function isFilesystemPublicReference(raw) {
const value = String(raw ?? '').trim();
if (!value) return false;
if (SKIP_REFERENCE.test(value)) return false;
// /api/... and /MindSpace/... are server routes, not on-disk siblings of public HTML.
if (value.startsWith('/')) return false;
return true;
}
/** @deprecated use isFilesystemPublicReference */
export function isRelativePublicReference(raw) {
return isFilesystemPublicReference(raw);
}
export function isDownloadLikeReference(raw, source = '') {
if (!isFilesystemPublicReference(raw)) return false;
const ref = normalizeReferencePath(raw);
if (DOWNLOAD_EXTENSIONS.test(ref)) return true;
return /\bdownload\b/i.test(String(source ?? ''));
}
export function normalizeReferencePath(raw) {
const trimmed = String(raw ?? '')
.trim()
.split('#')[0]
.split('?')[0]
.trim();
if (!trimmed) return '';
try {
return decodeURIComponent(trimmed);
} catch {
return trimmed;
}
}
export function resolveReferencePath(htmlDir, raw) {
const ref = normalizeReferencePath(raw);
if (!ref) return null;
return path.resolve(htmlDir, ref);
}
function parseMindspaceCoverPaths(contentAttr) {
const paths = [];
if (!contentAttr) return paths;
let parsed = null;
try {
parsed = JSON.parse(contentAttr);
} catch {
for (const key of ['cover', 'image']) {
const match = contentAttr.match(new RegExp(`"${key}"\\s*:\\s*"([^"]+)"`));
if (match?.[1]) paths.push(match[1]);
}
return paths;
}
for (const key of ['cover', 'image']) {
if (parsed?.[key]) paths.push(String(parsed[key]));
}
return paths;
}
export function collectPublicHtmlReferences(html, htmlDir, { downloadsOnly = false } = {}) {
const refs = [];
const seen = new Set();
const add = (raw, source) => {
if (downloadsOnly && !isDownloadLikeReference(raw, source)) return;
if (!downloadsOnly && !isFilesystemPublicReference(raw)) return;
const ref = normalizeReferencePath(raw);
if (!ref) return;
const key = `${source}\0${ref}`;
if (seen.has(key)) return;
seen.add(key);
refs.push({
ref,
source,
resolvedPath: resolveReferencePath(htmlDir, ref),
});
};
for (const match of String(html ?? '').matchAll(/\b(?:href|src)\s*=\s*["']([^"']+)["']/gi)) {
add(match[1], match[0]);
}
if (!downloadsOnly) {
for (const match of String(html ?? '').matchAll(
/<meta\b[^>]*\bname\s*=\s*["']mindspace-cover["'][^>]*>/gi,
)) {
const tag = match[0];
const contentMatch =
tag.match(/\bcontent\s*=\s*"([^"]*)"/i) ?? tag.match(/\bcontent\s*=\s*'([^']*)'/i);
for (const coverPath of parseMindspaceCoverPaths(contentMatch?.[1])) {
add(coverPath, 'mindspace-cover');
}
}
}
return refs;
}
export function findMissingPublicHtmlReferences(htmlPath, html = null, options = {}) {
const resolvedHtmlPath = path.resolve(htmlPath);
const content = html ?? fs.readFileSync(resolvedHtmlPath, 'utf8');
const htmlDir = path.dirname(resolvedHtmlPath);
const missing = [];
const seen = new Set();
for (const item of collectPublicHtmlReferences(content, htmlDir, options)) {
const key = item.ref;
if (seen.has(key)) continue;
seen.add(key);
if (!item.resolvedPath || !fs.existsSync(item.resolvedPath)) {
missing.push({ htmlPath: resolvedHtmlPath, ...item });
}
}
return missing;
}
export function listPublicHtmlFiles(publishRoot, { userId = null } = {}) {
const root = path.resolve(publishRoot);
if (!fs.existsSync(root)) return [];
const userDirs = userId
? [path.join(root, userId)]
: fs.readdirSync(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => path.join(root, d.name));
const files = [];
for (const userDir of userDirs) {
const publicDir = path.join(userDir, 'public');
if (!fs.existsSync(publicDir) || !fs.statSync(publicDir).isDirectory()) continue;
for (const name of fs.readdirSync(publicDir)) {
if (!name.toLowerCase().endsWith('.html')) continue;
files.push(path.join(publicDir, name));
}
}
return files.sort();
}
export function scanPublicHtmlLinks(publishRoot, options = {}) {
const issues = [];
for (const htmlPath of listPublicHtmlFiles(publishRoot, options)) {
issues.push(...findMissingPublicHtmlReferences(htmlPath, null, options));
}
return issues;
}
File diff suppressed because it is too large Load Diff
+22
View File
@@ -0,0 +1,22 @@
{
"name": "tkmind-h5-portal-runtime",
"private": true,
"type": "module",
"engines": {
"node": ">=22"
},
"dependencies": {
"@node-rs/argon2": "^2.0.2",
"@resvg/resvg-js": "^2.6.2",
"debug": "^4.4.3",
"express": "^4.21.2",
"http-proxy-middleware": "^3.0.3",
"jsonrepair": "^3.14.0",
"mysql2": "^3.22.5",
"playwright": "^1.61.1",
"qrcode": "^1.5.4",
"redis": "^4.7.1",
"sharp": "^0.35.2",
"undici": "^6.26.0"
}
}
@@ -0,0 +1 @@
nXjhx0ErC6MhQ0SZ
Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

@@ -0,0 +1,50 @@
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>微信分享预览 · 连云港三天两夜攻略 🌊</title>
<style>
* { box-sizing: border-box; }
body { margin: 0; min-height: 100vh; padding: 24px; background: #ececec; font-family: ui-sans-serif, -apple-system, BlinkMacSystemFont, sans-serif; color: #111; }
.wrap { max-width: 420px; margin: 0 auto; }
h1 { margin: 0 0 8px; font-size: 18px; }
.hint, .note { margin: 0 0 16px; color: #666; font-size: 13px; line-height: 1.6; }
.card { display: grid; grid-template-columns: 1fr 72px; gap: 12px; padding: 12px; border-radius: 8px; background: #fff; box-shadow: 0 1px 0 rgba(0,0,0,.06); }
.card-main { min-width: 0; }
.card-title { margin: 0; font-size: 16px; font-weight: 600; line-height: 1.35; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.card-desc { margin: 6px 0 0; color: #888; font-size: 13px; line-height: 1.45; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.card-foot { display: flex; align-items: center; gap: 6px; margin-top: 10px; color: #999; font-size: 12px; }
.card-foot img { width: 16px; height: 16px; border-radius: 999px; object-fit: cover; }
.card-thumb { width: 72px; height: 72px; border-radius: 4px; object-fit: cover; background: #f3f3f3; }
.card-thumb-empty { display: grid; place-items: center; color: #bbb; font-size: 12px; }
.meta { margin-top: 18px; padding: 14px; border-radius: 10px; background: rgba(255,255,255,.72); font-size: 12px; line-height: 1.7; word-break: break-all; }
code { background: rgba(0,0,0,.06); padding: 1px 4px; border-radius: 4px; }
</style>
</head>
<body>
<div class="wrap">
<h1>微信链接卡片预览</h1>
<p class="hint">本地模拟的是「粘贴链接后看到的卡片」,不是 JS-SDK 内部分享弹层。源链接:<code>https://m.tkmind.cn/MindSpace/john/public/lianyungang-guide.html</code></p>
<p class="note">修复后:标题 + 描述 + 缩略图 + 底部「TKMind 智趣」小图标应同时出现。</p>
<article class="card" aria-label="微信分享卡片预览">
<div class="card-main">
<h2 class="card-title">连云港三天两夜攻略 🌊</h2>
<p class="card-desc">三天两夜·沙滩酒店·必吃美食</p>
<div class="card-foot">
<img src="http://127.0.0.1:8081/brand/tkmind-icon.png" alt="" onerror="this.style.display='none'">
<span>TKMind 智趣</span>
</div>
</div>
<img class="card-thumb" src="https://images.unsplash.com/photo-1507525428034-b723cf961d3e?auto=format&amp;fit=crop&amp;w=200&amp;q=80" alt="">
</article>
<div class="meta">
<div><strong>og:title</strong> 连云港三天两夜攻略 🌊</div>
<div><strong>og:description</strong> 三天两夜·沙滩酒店·必吃美食</div>
<div><strong>og:site_name</strong> TKMind 智趣</div>
<div><strong>og:image</strong> https://images.unsplash.com/photo-1507525428034-b723cf961d3e?auto=format&amp;fit=crop&amp;w=200&amp;q=80</div>
<div><strong>icon</strong> /brand/tkmind-icon.png</div>
</div>
</div>
</body>
</html>
@@ -0,0 +1,41 @@
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>微信分享预览工具</title>
<style>
* { box-sizing: border-box; }
body { margin: 0; min-height: 100vh; padding: 24px; background: #f3f3f3; font-family: ui-sans-serif, -apple-system, BlinkMacSystemFont, sans-serif; color: #111; }
.panel { max-width: 560px; margin: 0 auto; padding: 20px; border-radius: 16px; background: #fff; box-shadow: 0 8px 30px rgba(0,0,0,.06); }
h1 { margin: 0 0 8px; font-size: 22px; }
p { margin: 0 0 16px; color: #666; line-height: 1.6; font-size: 14px; }
label { display: block; margin-bottom: 8px; font-size: 13px; font-weight: 600; }
input { width: 100%; padding: 12px 14px; border: 1px solid #ddd; border-radius: 10px; font: inherit; }
button { margin-top: 14px; width: 100%; padding: 12px 14px; border: 0; border-radius: 10px; background: #2f6f57; color: #fff; font: inherit; font-weight: 700; cursor: pointer; }
code { background: rgba(0,0,0,.06); padding: 1px 4px; border-radius: 4px; }
</style>
</head>
<body>
<div class="panel">
<h1>微信分享预览</h1>
<p>输入已发布页面路径,本地模拟微信「粘贴链接后」看到的卡片。开发环境走 Portal API:<code>/dev/wechat-share-preview</code></p>
<form id="preview-form">
<label for="url">页面 URL 或路径</label>
<input id="url" name="url" placeholder="/MindSpace/john/public/demo.html" required>
<button type="submit">生成预览</button>
</form>
</div>
<script>
document.getElementById('preview-form').addEventListener('submit', (event) => {
event.preventDefault();
const value = document.getElementById('url').value.trim();
if (!value) return;
const target = value.startsWith('http')
? `/dev/wechat-share-preview?url=${encodeURIComponent(value)}`
: `/dev/wechat-share-preview?url=${encodeURIComponent(value.startsWith('/') ? value : `/${value}`)}`;
window.location.href = target;
});
</script>
</body>
</html>
+159
View File
@@ -0,0 +1,159 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="John 的专属欢迎页面 - TKMind 为您呈现">
<meta name="mindspace-cover" content='{"tag":"报告","emoji":"👋","accent":"#f093fb","accent2":"#24243e","subtitle":"Hello John","cover":"https://images.unsplash.com/photo-1579547945413-497e1b99dac0?w=1200&q=80"}'>
<title>Hello, John!</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
background: linear-gradient(135deg, #0f0c29, #302b63, #24243e);
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
overflow: hidden;
}
/* 动态粒子背景 */
.bg-particles {
position: fixed;
inset: 0;
z-index: 0;
overflow: hidden;
}
.bg-particles span {
position: absolute;
width: 6px;
height: 6px;
background: rgba(255, 255, 255, 0.15);
border-radius: 50%;
animation: float 20s infinite;
}
.bg-particles span:nth-child(1) { top: 10%; left: 10%; animation-duration: 18s; animation-delay: 0s; }
.bg-particles span:nth-child(2) { top: 30%; left: 80%; width: 10px; height: 10px; animation-duration: 22s; animation-delay: 2s; }
.bg-particles span:nth-child(3) { top: 70%; left: 20%; animation-duration: 16s; animation-delay: 4s; }
.bg-particles span:nth-child(4) { top: 85%; left: 85%; width: 8px; height: 8px; animation-duration: 24s; animation-delay: 1s; }
.bg-particles span:nth-child(5) { top: 50%; left: 50%; width: 4px; height: 4px; animation-duration: 20s; animation-delay: 3s; }
.bg-particles span:nth-child(6) { top: 15%; left: 60%; animation-duration: 19s; animation-delay: 5s; }
.bg-particles span:nth-child(7) { top: 60%; left: 5%; width: 7px; height: 7px; animation-duration: 21s; animation-delay: 0.5s; }
.bg-particles span:nth-child(8) { top: 40%; left: 70%; width: 5px; height: 5px; animation-duration: 17s; animation-delay: 2.5s; }
@keyframes float {
0% { transform: translateY(0) rotate(0deg); opacity: 0; }
10% { opacity: 1; }
90% { opacity: 1; }
100% { transform: translateY(-100vh) rotate(720deg); opacity: 0; }
}
.card {
position: relative;
z-index: 1;
text-align: center;
padding: 60px 80px;
background: rgba(255, 255, 255, 0.05);
border-radius: 24px;
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
border: 1px solid rgba(255, 255, 255, 0.1);
box-shadow:
0 25px 50px rgba(0, 0, 0, 0.3),
inset 0 1px 0 rgba(255, 255, 255, 0.1);
animation: fadeIn 1.2s ease-out;
}
h1 {
font-size: 72px;
font-weight: 700;
background: linear-gradient(135deg, #f093fb, #f5576c, #4facfe);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
margin-bottom: 16px;
animation: pulse 3s ease-in-out infinite;
letter-spacing: 4px;
}
p {
font-size: 24px;
color: rgba(255, 255, 255, 0.7);
letter-spacing: 2px;
}
.emoji {
font-size: 48px;
display: block;
margin-bottom: 24px;
animation: wave 2s ease-in-out infinite;
}
.footer {
margin-top: 36px;
font-size: 13px;
color: rgba(255, 255, 255, 0.3);
letter-spacing: 1px;
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(30px) scale(0.95);
}
to {
opacity: 1;
transform: translateY(0) scale(1);
}
}
@keyframes pulse {
0%, 100% { transform: scale(1); }
50% { transform: scale(1.03); }
}
@keyframes wave {
0%, 100% { transform: rotate(0deg); }
25% { transform: rotate(15deg); }
75% { transform: rotate(-15deg); }
}
@media (max-width: 600px) {
.card {
padding: 40px 32px;
margin: 20px;
border-radius: 16px;
}
h1 {
font-size: 48px;
}
p {
font-size: 18px;
}
.emoji {
font-size: 36px;
}
}
</style>
</head>
<body>
<div class="bg-particles">
<span></span><span></span><span></span><span></span>
<span></span><span></span><span></span><span></span>
</div>
<div class="card">
<span class="emoji">👋</span>
<h1>Hello!</h1>
<p>Welcome, John</p>
<div class="footer">powered by TKMind</div>
</div>
</body>
</html>
Binary file not shown.

After

Width:  |  Height:  |  Size: 407 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 569 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 328 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 212 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 407 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 292 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 292 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 555 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 292 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 407 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 555 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 569 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 292 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 328 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 407 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 672 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 723 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 672 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 458 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 723 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 723 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 672 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 458 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 672 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 723 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 309 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 338 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 338 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 294 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 294 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 190 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 309 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 338 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 309 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 294 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 309 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 338 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 190 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 294 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 210 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 334 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 376 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 334 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 334 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 157 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 157 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 376 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 334 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 210 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 342 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 342 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 353 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 613 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 342 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 353 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 353 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 306 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 274 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 353 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 342 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 342 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 342 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 274 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 613 KiB

Some files were not shown because too many files have changed in this diff Show More