DesignOps Agent
1f9f285435
feat(w5): P1 把 .op 图形写进 Penpot(映射 + 增量 add/mod/del)+ 镜像 0.1.16
...
designops-gateway / build (push) Failing after 2s
- src/convert/op-to-penpot.ts:.op → Penpot shape 模型
· stableUuid:shape/page id 由 source+page+路径派生 → 重跑同一 .op 命中同一对象(否则每次保存都追加一份副本)
· collectShapes:frame/group/rect/ellipse/text 映射,text 生成 Penpot content 树
(root→paragraph-set→paragraph→text)
· 不支持的节点类型记入 skipped 并带原因,**不**用相似图元顶替
· 顶层非 frame 图元包一个生成 frame(exporter 只渲染 frame)
· planShapeSync:按字段快照做 diff → add-obj / mod-obj(仅变更字段) / del-obj
- P1 管道:SVG 资产之后 push 图形;每个 .op 一个 Penpot 页面;映射持久化到 /data/penpot-shapes.json
· 无变化时仍 success 但上报 add=0 mod=0 del=0(跑过≠推了东西)
- penpot 连接器新增 rpcTransit(发预编码 transit 体,共享 401 重试)
- OpNode/Fill 统一为单一模型(op-to-svg 导出,op-to-penpot 复用)
- 测试 68/68(12 例映射/幂等/字段级 diff)
2026-09-28 04:51:38 +08:00
DesignOps Agent
5e4acf5b81
feat(w4): 记录验收 —— P3 多页/增量实测 + 发布画廊浏览器证据
...
designops-gateway / build (push) Failing after 1s
- 三场景实测:首发布 2/2/0;无改动 0/2;只改一帧后代 1/1(仅该帧 sha 变化)
- 浏览器实测画廊:2 页 2 帧 2 SVG、revn 16、无 console 错误
- 截图 docs/evidence/storybook-publish-gallery.png
- 记录两处被验证纠错:改错对象导致误判、镜像 tag 静默 no-op
okf: 新增 P3 多页增量发布不变式 P1-P7
2026-09-28 04:48:21 +08:00
DesignOps Agent
8054e95fb2
fix(w4): 修正 storybook 镜像 tag 未生效(上次替换目标 0.1.2 与实际 0.1.1 不匹配,静默 no-op)
...
designops-gateway / build (push) Failing after 2s
实测教训:ArgoCD 纳管后,集群里的 image 会**回退到仓库值**——我之前的 0.1.2 是用
kubectl set image 直接改的、没进仓库,于是被 ArgoCD 改回 0.1.1。
本次把 tag 真正改为 0.1.3,并用 grep 复核写入结果(不再盲信 replace)。
2026-09-28 04:47:26 +08:00
DesignOps Agent
bc0ae34c74
feat(w4): Storybook 多页发布画廊(消费 P3 manifest)+ storybook 0.1.3
...
designops-gateway / build (push) Failing after 2s
- stories/publish.ts:manifest 解析(缺 sha 的帧丢弃、空页保留)+ 测试 4 例
- stories/PublishGallery.stories.tsx:按 manifest 枚举全部页面/帧并内联 SVG,
不硬编码任何 frame id —— Penpot 加页/加帧后重新发布即自动出现
- storybook 镜像 0.1.3 经 Git 升级(ArgoCD 纳管)
2026-09-28 04:37:46 +08:00
DesignOps Agent
b14c8d8fc6
feat(w4): P3 多页 + 增量发布(manifest/签名/变更计划)+ 镜像 0.1.15
...
designops-gateway / build (push) Failing after 4s
- src/publish/manifest.ts:pagesOf/framesOf/frameSignature/planExports/load+save(原子写)
签名基于文件数据(帧子树规范化哈希),**不依赖导出结果**,因此能真正跳过导出
- P3 改为遍历全部页面 → 只导出签名变化的 frame → 写 manifest → emit 计数
- GET /publish/manifest.json 暴露消费方契约(页面→帧→sha256)
- 测试 56/56(含 7 例增量/多页用例)
- 镜像经 Git 升级到 0.1.15(ArgoCD 纳管后不再 kubectl set image)
2026-09-28 04:33:04 +08:00
DesignOps Agent
90dc2ad860
feat(w3): GitOps 闭环 —— ArgoCD 纳管 designops 组件(漂移自愈 + 仓库驱动均已实测)
...
designops-gateway / build (push) Failing after 1s
- Application designops: Synced + Healthy,automated{prune,selfHeal}
- 漂移自愈:set env TOKENS_DIR=/tmp/drift 落地后约 10s 被改回 /data/tokens
- 仓库驱动:push COMMENTS_SYNC_INTERVAL_MS → t+190s 自动同步到 rev 679663ba
- 安全:摘除 Deployment 中的明文 PENPOT_TOKEN/PENPOT_SECRET_KEY,改 envFrom Secret,
并彻底移除静态 PENPOT_TOKEN(会话由 keeper 持有)
- 回归:凭证改造后 P3 id=192 success,四条流水线最新均 success
okf: 新增 ArgoCD 接入不变式 G1-G6
2026-09-28 04:31:34 +08:00
DesignOps Agent
679663bac9
feat(w3): 仓库驱动变更样例 — 显式声明 COMMENTS_SYNC_INTERVAL_MS
...
designops-gateway / build (push) Failing after 1s
用于验证 GitOps 正向链路(仓库→Gitea→ArgoCD→集群):只有仓库声明了该值,
集群出现该 env 即证明同步来自仓库而非手工 kubectl。
2026-09-28 04:26:28 +08:00
DesignOps Agent
37db7477a1
feat(w3): 把 designops 自研组件固化为 ArgoCD 可同步的 kustomize 清单
...
designops-gateway / build (push) Failing after 2m30s
- infra/gitops/apps/designops/{kustomization,gateway,gateway-ingress,storybook}.yaml
- gateway Deployment 走 envFrom 两个 Secret,**移除明文 PENPOT_TOKEN/PENPOT_SECRET_KEY**
(原先它们以明文 env 存在于 Deployment spec,入库即泄密)
- 加上 readiness/liveness(=/healthz) 与资源 requests/limits
- 明确纳管边界:PVC 与 Secret 刻意不纳管(prune 会删数据/凭据不入库)
- storybook.yaml 从 infra/k3s/storybook/ 迁入本目录(kustomize 不允许目录外资源)
2026-09-28 04:14:04 +08:00
DesignOps Agent
5e603f0c8a
feat(w2): Penpot 会话轮换机制(会话保活 + 401 自动重登)
...
designops-gateway / build (push) Failing after 20m21s
调研结论:access token 在 Penpot 2.18 无法经 RPC 授权(perms 只能 REPL 追加),
故采用会话保活。续期窗口以登录响应的 Comment=Renewal at(<+6h) 为准,而非 7 天过期。
- penpot-session.ts:登录/落盘(0600 原子写)/陈旧判定/合并并发刷新/fail-open/status
- penpot.ts:sessionProvider 每次读实时 cookie;401 → 强制重登 → 只重试一次
- index.ts:启动 ensureFresh + 小时级 tick;healthz 暴露会话健康(不含密钥)
- P3 的 exporter cookie 改为 provider,刷新对运行中流水线即时生效
修掉真 bug:seed cookie 年龄未知却当成新鲜 → 整个续期窗口不登录、从不写会话文件;
改为 seed 一律视为陈旧。
实测:会话文件 mode 600;healthz penpotSession 指标正常;植入假 cookie 后日志出现
'401 received, forcing re-login' + 'refreshed successfully' 且 P4 仍 success;
重启后 ageSeconds 46→72(复用同一 cookie,无新刷新)。测试 49/49
okf: 新增 Penpot 会话轮换不变式 S1-S7
2026-09-28 04:12:16 +08:00
DesignOps Agent
75e5f1a727
feat(w1): /review 鉴权 + 公网发布打通(含 ECS 入口与出网真根因)
...
designops-gateway / build (push) Failing after 1s
/review 鉴权
- gateway/src/auth.ts:Basic + Bearer,timingSafeEqual 比较,未配置凭据即 fail-closed
- 401 带 WWW-Authenticate;保护 /review 与 /review/*;测试 40/40 全绿
- Secret designops-review-auth 注入(不入库)
公网(两层根因,均已修)
- Caddyfile 缺 *.designops.osc.life 站点块 → 追加(备份 + validate + reload)
- ECS 出网走 mihomo fake-IP TUN 且 TUN 不通 → ACME 拿不到证书;
改用同机 HTTP 代理 127.0.0.1:7890 + NO_PROXY 列出 k3s 上游 → 三域名 Let's Encrypt 签发成功
发布前置安全
- Penpot 注册域白名单 osc.life(非白名单域 400 email-domain-is-not-allowed)
实测:公网 review 无凭据 401 / Basic 200;penpot、storybook 首页 200;
storybook/gateway/tokens.css 200;ssl_verify_result=0;既有站点保持 200
okf: 新增 ECS 公网入口与出网不变式;docs: 五项收尾计划(含 W1 验收记录)
2026-09-28 04:06:02 +08:00
DesignOps Agent
9d049295f9
feat(storybook): 交互原型端到端打通 + 产物契约修正 + 集群内 registry 分发
...
designops-gateway / build (push) Failing after 4s
Storybook(apps/designops-storybook/)
- Storybook 10 + react-vite;交互原型 story(Penpot 导出 artboard + 热点 + 流程状态 + 事件日志)
与令牌画廊 story;gateway base 支持 window/query/build/同源 四级解析,默认 /gateway
- 纯函数抽到 stories/tokens.ts + 3 个 node:test 回归测试
真实浏览器验证(复用 penpot-exporter 的 playwright/chromium)
- 4 个令牌面板成行;:root 自定义属性真有值(#7C5CFF/8px,非 fallback);artboard SVG 渲染;
热点 3 个;点击推进到 step-2;无 console 错误;截图 docs/evidence/storybook-prototype.png
渲染暴露并修正的真 bug
- P2 曾把 ES module(export default) 写进 tokens.json 却按 application/json 提供
→ 拆为 tokens.json(DTCG JSON) / tokens.js(ESM) / tokens.css;路由同步类型与白名单
- flattenTokens 把带 的 DTCG 叶子当分组递归 → 取不到任何令牌;改为 即叶子
基础设施
- 镜像改经集群内 registry 10.43.31.72:5000 分发(IfNotPresent,去 nodeSelector),
修复 imagePullPolicy:Never 导致的 ErrImageNeverPull
- 补 infra/k3s/gateway-ingress.yaml(此前 gateway 主机无任何 Ingress → 全 404)
- /gateway 同源前缀(Traefik stripPrefix)暴露 tokens/assets,免 CORS/免第二证书
测试:gateway 34/34、storybook 3/3
2026-09-28 03:40:17 +08:00
DesignOps Agent
424accce3d
fix(infra): hairpin NAT 修复持久化 + 自愈(4 节点实测)
...
designops-gateway / build (push) Failing after 20m4s
- 新增 infra/k3s/install-hairpin-fix.sh:oneshot service + 2min timer,幂等
- runbook 增持久化章节:验证方法、已部署节点表、RemainAfterExit 踩坑
- 实测:规则幂等(计数恒 1);承载真实流量 18762 pkts/2189K;
zbzxai 删规则后 ≤1 个 timer 周期自动恢复;4 节点 enabled+active
2026-09-28 03:17:30 +08:00
DesignOps Agent
f36773ef40
feat(p4): Penpot 评论聚合 + 评审页 端到端打通(四管道全绿)
...
designops-gateway / build (push) Failing after 2m31s
P4 聚合
- 双路入库:webhook 推送(create-comment-thread / create-comment)+ 60s 轮询兜底
- 去重键 (source, tool, external_id) + 部分唯一索引;db.ts 加可重入 ALTER 迁移
- 行语义区分 thread / comment(meta.kind);历史无 kind 行按 position 有无回退
评审页
- 渲染位置/页面/文件/resolved/unread;全部字段 HTML 转义(存储型 XSS 防护)
- meta_json / position_json 解析失败降级为空对象,单条坏数据不 500
配置/清单
- COMMENTS_SYNC_INTERVAL_MS 配置项;Helm values/templates 对齐 0.1.8
验证:comments-sync 11/11 success;P1/P2/P3/P4 最新运行均 success;
GET /review 200,XSS 载荷已转义且原始 script 不出现;测试 32/32 pass
okf: 新增 P4 聚合不变式规则(C1-C5)
2026-09-28 01:54:38 +08:00
DesignOps Agent
2234dc071f
feat(p3): Penpot 画框 → exporter 渲染 → SVG 资产库 端到端打通
...
designops-gateway / build (push) Failing after 2s
新增共享 Transit-JSON 编解码(gateway/src/connectors/transit.ts)
- encode: map 用 '^ ' 标记、RPC 参数键用 keyword、DTCG 键保持字符串、UUID 用 ~u
- decode: 兼容两种实测线格式(RPC 错误体 map 数组 / exporter 成功体普通对象 + '~:' 前缀 + '~#uri')
PenpotExporter 重写为真实实现
- transit+json + X-Shared-Key + 会话 cookie
- 逐 frame 导出(页面导出必超时:viewer 只对 frame 生成 #screenshot-<id>)
- 两跳取字节:句柄 :uri → 回 backend GET /assets/by-id/<id>
P3 管道
- 按 name 匹配 set-file-shared/create-share-link(type 被 Penpot dissoc)
- props 嵌套的 fileId 解析;空页面/无 frame 显式报错而非假成功
- SVG 头校验,杜绝非 SVG 冒充 kind=svg
修复
- exporter PENPOT_REDIS_URI: penpot-valkey-master → penpot-valkey-primary(真实 service 名)
- 两管道 fileId/profileId 解析补充 props 分支
验证:真实 set-file-shared webhook → status=success;GET /assets/<sha> 200 image/svg+xml 1367B
测试 26/26 pass;镜像 designops-gateway:0.1.5
okf: 新增 exporter 契约规则 + P3 复盘 + 2 条 feedback→rule
2026-09-28 01:43:34 +08:00
DesignOps Agent
1307c14852
feat(p2): Penpot webhook -> DTCG -> tokens.css 端到端打通
...
designops-gateway / build (push) Failing after 1m11s
修正 10 个根因(全部源码定位 + 集群实测):
- 认证:连接器改发 Cookie: auth-token(access token 默认空权限)→ 消除 401
- 触发:Penpot webhook 载荷 dissoc 掉 :type,按 name 匹配事件
- 参数:get-file 必填 :id;且禁止传部分 features(check-client-features! 400)
- 校验:新增 GET/HEAD /webhooks/:source,满足 Penpot validate-webhook! 的 HEAD 探测
- 编译:kebabCase 净化 set 名中的 '/',产出合法 CSS ident
- 持久化:挂 PVC,ASSETS_DIR/WATCH_DIR/TOKENS_DIR 指向 /data/*,重启不丢
- P3:改用真实 exporter 接口并显式失败,不再把 JSON 冒充 SVG 入库
新增 gateway/test/p2-pipeline.test.mjs(6 例);测试 17/17 pass
镜像 designops-gateway:0.1.4;okf 规则 + 复盘落库
2026-09-28 01:32:23 +08:00
yushanhe
a28692f20d
fix(penpot): support session cookie, host header override, correct RPC path
...
designops-gateway / build (push) Failing after 3s
Verified against live Penpot on k3s (designops namespace):
- RPC path is /api/rpc/command/<cmd> for ALL methods (no /query path)
- access tokens are created with EMPTY perms (Anonymous); use session
cookie (auth-token) or grant perms via SQL/repl
- registration: prepare-register-profile (fullname+email+password) -> token
-> register-profile
- added optional hostHeader for reaching an ingress by node IP during
local testing (production uses normal DNS)
P2 integration verified end-to-end: login -> get-teams -> get-projects
-> create-file (DesignOps Tokens) -> get-file roundtrip.
2026-09-28 00:27:40 +08:00
yushanhe
9b4629e6eb
docs: add k3s hairpin NAT root-cause fix runbook
...
designops-gateway / build (push) Failing after 2m30s
Root cause: kube-proxy KUBE-MARK-MASQ excludes pod CIDR
(!10.42.0.0/16) -> same-node pod->clusterIP gets no SNAT ->
conntrack reverse fails -> client RST (tcpdump: SYN/SYN-ACK/RST).
Fix: iptables -t nat -I POSTROUTING 1 -s 10.42.0.0/16
-m conntrack --ctstate DNAT --ctorigdst 10.43.0.0/16 -j MASQUERADE
(must use --ctorigdst; -d clusterIP matches nothing in POSTROUTING)
Verified: Penpot homepage + API HTTP 200, 10/10 pods Running.
2026-09-28 00:23:47 +08:00
yushanhe
c5d16b4494
fix: penpot deployed — root cause was k3s same-node hairpin NAT
...
designops-gateway / build (push) Failing after 3s
tcpdump evidence: SYN -> SYN-ACK -> immediate RST, SYN seq fixed
(retransmit). Same-node pod -> clusterIP hairpin NAT is broken; fix =
use headless / StatefulSet stable DNS (resolves to pod IP).
- postgres: penpot-postgresql-hl (headless)
- valkey: penpot-valkey-primary-0.penpot-valkey-headless (StatefulSet DNS)
- also fixed valkey service name (penpot-valkey-primary, not -master)
Result: 10/10 pods Running, homepage HTTP 200.
2026-09-28 00:15:38 +08:00
yushanhe
07d9fc9d6e
feat: add Penpot helm values + fix D13 (reuse Rancher/ArgoCD, not Flux)
...
designops-gateway / build (push) Failing after 6s
- k3s cluster verified ready: 4 nodes, Traefik ingress, local-path SC,
Rancher+ArgoCD+Fleet already present (via SSH to control node)
- penpot-values.yaml for helm install (local-path + traefik + mcp)
- D13 corrected: reuse existing GitOps stack instead of introducing Flux
2026-09-27 22:50:55 +08:00
yushanhe
dc38fe74fa
fix: parse OpenPencil MCP result.content[0].text in connector
...
designops-gateway / build (push) Failing after 5s
MCP tools/call returns result.content[0].text (JSON string); connector
now parses it. Verified e2e against headless server: get_document_info
→ object, list_variables → {variables:[]}.
2026-09-27 22:46:58 +08:00
yushanhe
737d5b8e7a
feat: add Penpot exporter SVG connector (P3, UNVERIFIED pending service)
designops-gateway / build (push) Failing after 1m2s
2026-09-27 22:45:12 +08:00
yushanhe
ccb8df4c1d
docs: add gateway README + update plan progress (P1/P2 done, k3s blocked)
designops-gateway / build (push) Failing after 1m30s
2026-09-27 22:44:42 +08:00
yushanhe
48b630c951
feat: add core unit tests, review UI, Dockerfile and Helm chart
...
designops-gateway / build (push) Failing after 1m11s
- 7 unit tests (op-to-svg/config/dtcg) pass via node --test
- review page: comment form + asset preview; assets route MIME by kind
- gateway Dockerfile (node:24-alpine multi-stage + op binary)
- Helm chart (deployment/service/ingress/pvc + secret injection)
2026-09-27 22:44:00 +08:00
yushanhe
dec3172271
feat: add DTCG compiler + P2 token compile pipeline (with unit tests)
...
designops-gateway / build (push) Failing after 1m31s
- dtcg-compile: DTCG tree -> :root CSS vars + ES module (lightweight,
no style-dictionary dependency; $type inheritance, kebab-case names)
- P2 pipeline: webhook update-file -> pull DTCG -> compileAndWrite
tokens.css/tokens.json
- 3 unit tests (flatten/type-inheritance/js-strip) pass via node --test
2026-09-27 22:38:36 +08:00
yushanhe
1e38e0756d
feat: implement DesignOps Gateway core (connectors + pipelines + routes)
...
designops-gateway / build (push) Failing after 18m38s
- Node+TS+Fastify skeleton with node:sqlite (zero native deps)
- config/db/bus + OpenPencil MCP + Penpot RPC connectors
- pipelines P1 (.op->SVG->asset), P2 (token->SD), P3 (publish->SVG)
- routes /healthz, /webhooks/:source, /assets/:sha256, /review
- verified: typecheck+build green, P1 e2e (.op->SVG->asset->HTTP)
2026-09-27 22:34:25 +08:00
yushanhe
d4c5a8b604
docs: add function-level @skill annotations (27 key functions)
...
designops-gateway / build (push) Failing after 9s
- openpencil: from_document, McpTool, Codegen, render_svg_bytes, main x2
- penpot: make-rpc-handler, webhook-permissions, get-file, persist-file!,
make-token, process-sd-tokens, resolve-tokens-tree, start, initialize
- excalidraw: exportToSvg, scene exportToSvg, serializeAsJSON, Excalidraw
- style-dictionary: class, buildAllPlatforms, formats, transforms, convertToDTCG
- storybook: run, build, buildStaticStandalone
2026-09-27 22:24:48 +08:00
yushanhe
06c02e9f92
docs: annotate 17 core integration modules with OKF @module headers
...
designops-gateway / build (push) Failing after 38s
- openpencil: editor-core state, mcp, codegen, svg export
- penpot: rpc, webhooks, files-update, tokens-lib, style-dictionary
- excalidraw: export utils, scene export, json
- style-dictionary: formats, transforms, convertToDTCG
- storybook: build-static, core-server index
2026-09-27 22:09:59 +08:00
yushanhe
f097f5bc21
chore: bootstrap DesignOps monorepo (5 subprojects + OKF + annotations)
...
designops-gateway / build (push) Failing after 20m0s
- merge openpencil/penpot/excalidraw/style-dictionary/storybook as native
monorepo code (upstream .git removed; origins in okf/manifest.md)
- add project-level okf/ (manifest + memory/rule/skill/decision/lesson)
- add AGENTS.md (OKF annotation standard) + monorepo .gitignore
- annotate 9 entry files with @module/@skill/@rule headers
- add GitOps deploy bundle (infra/gitops/) + Gitea CI (.gitea/workflows/)
2026-09-27 21:28:44 +08:00