@agent-spaces/server 0.3.63 → 0.3.65
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters/claude-code-runtime/index.js +68 -2
- package/dist/adapters/claude-code-runtime/message-format.js +27 -1
- package/dist/adapters/claude-code-runtime/sdk-config.js +12 -0
- package/dist/adapters/git.js +168 -57
- package/dist/agents/agent-designer.js +66 -12
- package/dist/agents/agent-message-parts.js +1 -1
- package/dist/agents/commit-agent.js +4 -2
- package/dist/agents/issue-task-controller.js +7 -3
- package/dist/app.js +56 -69
- package/dist/package.json +1 -1
- package/dist/routes/agent-commands.js +72 -0
- package/dist/routes/agent-sse.js +7 -0
- package/dist/routes/agent.js +18 -1
- package/dist/routes/database.js +346 -0
- package/dist/routes/git.js +198 -267
- package/dist/routes/kanban.js +39 -0
- package/dist/routes/robot-account.js +68 -0
- package/dist/services/agent-commands.js +168 -0
- package/dist/services/agent.js +36 -2
- package/dist/services/builtin-tools/command-tools.js +117 -0
- package/dist/services/builtin-tools/database-tools.js +578 -0
- package/dist/services/builtin-tools/index.js +5 -0
- package/dist/services/builtin-tools/input-helpers.js +26 -0
- package/dist/services/builtin-tools/issue-tools.js +209 -0
- package/dist/services/builtin-tools/kanban-tools.js +281 -0
- package/dist/services/database-vector.js +244 -0
- package/dist/services/git-operation-log.js +40 -0
- package/dist/services/global-wechat-qr.js +72 -0
- package/dist/services/hook-engine.js +175 -17
- package/dist/services/kanban.js +50 -0
- package/dist/services/notification-hub/bot-agent.js +3 -1
- package/dist/services/notification-hub/service.js +12 -2
- package/dist/services/robot-account.js +34 -0
- package/dist/services/workspace.js +2 -0
- package/dist/storage/database-store.js +365 -0
- package/dist/storage/kanban-store.js +142 -0
- package/dist/storage/robot-account-store.js +39 -0
- package/dist/web/404.html +1 -1
- package/dist/web/__next.__PAGE__.txt +4 -4
- package/dist/web/__next._full.txt +24 -31
- package/dist/web/__next._head.txt +4 -4
- package/dist/web/__next._index.txt +14 -14
- package/dist/web/__next._tree.txt +3 -8
- package/dist/web/_next/static/chunks/0-a.-hl3wv99k.js +1 -0
- package/dist/web/_next/static/chunks/{0ctg5qmw7uu.1.js → 0-pi.67w.ymsr.js} +3 -3
- package/dist/web/_next/static/chunks/0-v_p6j5u3_9l.js +1 -0
- package/dist/web/_next/static/chunks/0.-x29t-8gk0r.js +1 -0
- package/dist/web/_next/static/chunks/0.6b64sy0g5.3.js +3 -0
- package/dist/web/_next/static/chunks/0.l5e8~r7_0~p.js +1 -0
- package/dist/web/_next/static/chunks/00-syqzi-6zxr.js +1 -0
- package/dist/web/_next/static/chunks/{13~y-b.b9rrw4.js → 01~quun6sefgl.js} +1 -1
- package/dist/web/_next/static/chunks/02802taez976w.js +67 -0
- package/dist/web/_next/static/chunks/02j4sr9psucf-.js +1 -0
- package/dist/web/_next/static/chunks/033.awk90g6eh.js +1 -0
- package/dist/web/_next/static/chunks/06.kdsa9rr2h1.js +1 -0
- package/dist/web/_next/static/chunks/{0-oog4zg4_m~m.css → 062f9zqctzg.b.css} +0 -3
- package/dist/web/_next/static/chunks/06si8l0doqe8p.js +1 -0
- package/dist/web/_next/static/chunks/08ugbvzr20drp.js +2 -0
- package/dist/web/_next/static/chunks/{0kof5qdg8c2-k.js → 08x85faoz58i7.js} +37 -37
- package/dist/web/_next/static/chunks/0_cqojbge48kq.js +5 -0
- package/dist/web/_next/static/chunks/0_mvduwjsm35w.js +1 -0
- package/dist/web/_next/static/chunks/0d6~~lv0-6kex.js +3 -0
- package/dist/web/_next/static/chunks/{0ogpc3f3keopc.js → 0db14450oqzhg.js} +2 -2
- package/dist/web/_next/static/chunks/0fttswpzu69qx.js +1 -0
- package/dist/web/_next/static/chunks/0gdwop9cnpmtu.js +1 -0
- package/dist/web/_next/static/chunks/0ghx3j_.-gdyd.js +1 -0
- package/dist/web/_next/static/chunks/0j-l7l_k9jt45.js +1 -0
- package/dist/web/_next/static/chunks/0k4zdm72k_bfy.js +1 -0
- package/dist/web/_next/static/chunks/0kbvoxla7f751.js +1 -0
- package/dist/web/_next/static/chunks/{0aa6bcdmtpekn.js → 0l2w0qz1ea7ql.js} +2 -2
- package/dist/web/_next/static/chunks/0p3h-h3zj5ujg.js +30 -0
- package/dist/web/_next/static/chunks/0paaat8y96ayc.js +7 -0
- package/dist/web/_next/static/chunks/0pm-un~-sy3rl.js +1 -0
- package/dist/web/_next/static/chunks/0pq318f8xgafg.js +1 -0
- package/dist/web/_next/static/chunks/0t6s8of0qr6nc.js +1 -0
- package/dist/web/_next/static/chunks/0u6h-hqc_i52e.js +1 -0
- package/dist/web/_next/static/chunks/0uxzi~9b~k4mn.js +31 -0
- package/dist/web/_next/static/chunks/{002-dxhags4dj.js → 0v6hte2z-32ca.js} +2 -2
- package/dist/web/_next/static/chunks/{014x2qbuiszni.js → 0vis~lx0nxgn-.js} +3 -3
- package/dist/web/_next/static/chunks/{0y09i51u6ixq5.js → 0w7.tb29958zj.js} +1 -1
- package/dist/web/_next/static/chunks/0xbaakj0dfc0..js +1 -0
- package/dist/web/_next/static/chunks/0yd.m1afqg.2t.js +3 -0
- package/dist/web/_next/static/chunks/0yhbr8hl09b-5.js +1 -0
- package/dist/web/_next/static/chunks/0zncg76rgtbm-.js +1 -0
- package/dist/web/_next/static/chunks/0z~vqzbm_q371.js +1 -0
- package/dist/web/_next/static/chunks/0~~_ltu6dx_ch.js +1 -0
- package/dist/web/_next/static/chunks/{02c22g~xd-y30.js → 11cchuwoupmbf.js} +2 -2
- package/dist/web/_next/static/chunks/12jm4gwmvq-0q.js +90 -0
- package/dist/web/_next/static/chunks/12oxcgyhpaxw~.js +1 -0
- package/dist/web/_next/static/chunks/1452eibz62gs6.css +1 -0
- package/dist/web/_next/static/chunks/16zlreiems5cn.js +1 -0
- package/dist/web/_next/static/chunks/18awqjk9-o5m0.js +1 -0
- package/dist/web/_next/static/chunks/18c7g84y01mj0.js +1 -0
- package/dist/web/_next/static/chunks/{turbopack-0ndm2zc_pdptk.js → turbopack-11qjwlynmfc-n.js} +1 -1
- package/dist/web/_not-found/__next._full.txt +31 -30
- package/dist/web/_not-found/__next._head.txt +4 -4
- package/dist/web/_not-found/__next._index.txt +14 -14
- package/dist/web/_not-found/__next._not-found.__PAGE__.txt +2 -2
- package/dist/web/_not-found/__next._not-found.txt +3 -3
- package/dist/web/_not-found/__next._tree.txt +3 -3
- package/dist/web/_not-found.html +1 -1
- package/dist/web/_not-found.txt +31 -30
- package/dist/web/index.html +1 -1
- package/dist/web/index.txt +24 -31
- package/dist/web/login/__next._full.txt +32 -36
- package/dist/web/login/__next._head.txt +4 -4
- package/dist/web/login/__next._index.txt +14 -14
- package/dist/web/login/__next._tree.txt +3 -8
- package/dist/web/login/__next.login.__PAGE__.txt +4 -4
- package/dist/web/login/__next.login.txt +3 -3
- package/dist/web/login.html +1 -1
- package/dist/web/login.txt +32 -36
- package/dist/web/settings/__next._full.txt +34 -38
- package/dist/web/settings/__next._head.txt +4 -4
- package/dist/web/settings/__next._index.txt +14 -14
- package/dist/web/settings/__next._tree.txt +3 -8
- package/dist/web/settings/__next.settings.__PAGE__.txt +4 -4
- package/dist/web/settings/__next.settings.txt +5 -5
- package/dist/web/settings/agents/__next._full.txt +27 -32
- package/dist/web/settings/agents/__next._head.txt +4 -4
- package/dist/web/settings/agents/__next._index.txt +14 -14
- package/dist/web/settings/agents/__next._tree.txt +3 -8
- package/dist/web/settings/agents/__next.settings.agents.__PAGE__.txt +4 -4
- package/dist/web/settings/agents/__next.settings.agents.txt +3 -3
- package/dist/web/settings/agents/__next.settings.txt +5 -5
- package/dist/web/settings/agents.html +1 -1
- package/dist/web/settings/agents.txt +27 -32
- package/dist/web/settings/mcps/__next._full.txt +27 -32
- package/dist/web/settings/mcps/__next._head.txt +4 -4
- package/dist/web/settings/mcps/__next._index.txt +14 -14
- package/dist/web/settings/mcps/__next._tree.txt +3 -8
- package/dist/web/settings/mcps/__next.settings.mcps.__PAGE__.txt +4 -4
- package/dist/web/settings/mcps/__next.settings.mcps.txt +3 -3
- package/dist/web/settings/mcps/__next.settings.txt +5 -5
- package/dist/web/settings/mcps.html +1 -1
- package/dist/web/settings/mcps.txt +27 -32
- package/dist/web/settings/models/__next._full.txt +27 -32
- package/dist/web/settings/models/__next._head.txt +4 -4
- package/dist/web/settings/models/__next._index.txt +14 -14
- package/dist/web/settings/models/__next._tree.txt +3 -8
- package/dist/web/settings/models/__next.settings.models.__PAGE__.txt +4 -4
- package/dist/web/settings/models/__next.settings.models.txt +3 -3
- package/dist/web/settings/models/__next.settings.txt +5 -5
- package/dist/web/settings/models.html +1 -1
- package/dist/web/settings/models.txt +27 -32
- package/dist/web/settings/output-styles/__next._full.txt +27 -32
- package/dist/web/settings/output-styles/__next._head.txt +4 -4
- package/dist/web/settings/output-styles/__next._index.txt +14 -14
- package/dist/web/settings/output-styles/__next._tree.txt +3 -8
- package/dist/web/settings/output-styles/__next.settings.output-styles.__PAGE__.txt +4 -4
- package/dist/web/settings/output-styles/__next.settings.output-styles.txt +3 -3
- package/dist/web/settings/output-styles/__next.settings.txt +5 -5
- package/dist/web/settings/output-styles.html +1 -1
- package/dist/web/settings/output-styles.txt +27 -32
- package/dist/web/settings/prompts/__next._full.txt +27 -32
- package/dist/web/settings/prompts/__next._head.txt +4 -4
- package/dist/web/settings/prompts/__next._index.txt +14 -14
- package/dist/web/settings/prompts/__next._tree.txt +3 -8
- package/dist/web/settings/prompts/__next.settings.prompts.__PAGE__.txt +4 -4
- package/dist/web/settings/prompts/__next.settings.prompts.txt +3 -3
- package/dist/web/settings/prompts/__next.settings.txt +5 -5
- package/dist/web/settings/prompts.html +1 -1
- package/dist/web/settings/prompts.txt +27 -32
- package/dist/web/settings/providers/__next._full.txt +27 -32
- package/dist/web/settings/providers/__next._head.txt +4 -4
- package/dist/web/settings/providers/__next._index.txt +14 -14
- package/dist/web/settings/providers/__next._tree.txt +3 -8
- package/dist/web/settings/providers/__next.settings.providers.__PAGE__.txt +4 -4
- package/dist/web/settings/providers/__next.settings.providers.txt +3 -3
- package/dist/web/settings/providers/__next.settings.txt +5 -5
- package/dist/web/settings/providers.html +1 -1
- package/dist/web/settings/providers.txt +27 -32
- package/dist/web/settings/skills/__next._full.txt +27 -32
- package/dist/web/settings/skills/__next._head.txt +4 -4
- package/dist/web/settings/skills/__next._index.txt +14 -14
- package/dist/web/settings/skills/__next._tree.txt +3 -8
- package/dist/web/settings/skills/__next.settings.skills.__PAGE__.txt +4 -4
- package/dist/web/settings/skills/__next.settings.skills.txt +3 -3
- package/dist/web/settings/skills/__next.settings.txt +5 -5
- package/dist/web/settings/skills.html +1 -1
- package/dist/web/settings/skills.txt +27 -32
- package/dist/web/settings/tools/__next._full.txt +38 -0
- package/dist/web/settings/tools/__next._head.txt +6 -0
- package/dist/web/settings/tools/__next._index.txt +15 -0
- package/dist/web/settings/tools/__next._tree.txt +3 -0
- package/dist/web/settings/tools/__next.settings.tools.__PAGE__.txt +9 -0
- package/dist/web/settings/tools/__next.settings.tools.txt +5 -0
- package/dist/web/settings/tools/__next.settings.txt +7 -0
- package/dist/web/settings/tools.html +1 -0
- package/dist/web/settings/tools.txt +38 -0
- package/dist/web/settings.html +1 -1
- package/dist/web/settings.txt +34 -38
- package/dist/web/workflows/__next._full.txt +32 -38
- package/dist/web/workflows/__next._head.txt +4 -4
- package/dist/web/workflows/__next._index.txt +14 -14
- package/dist/web/workflows/__next._tree.txt +3 -8
- package/dist/web/workflows/__next.workflows.__PAGE__.txt +4 -4
- package/dist/web/workflows/__next.workflows.txt +3 -3
- package/dist/web/workflows.html +1 -1
- package/dist/web/workflows.txt +32 -38
- package/dist/web/workspace/_/__next._full.txt +31 -36
- package/dist/web/workspace/_/__next._head.txt +4 -4
- package/dist/web/workspace/_/__next._index.txt +14 -14
- package/dist/web/workspace/_/__next._tree.txt +4 -8
- package/dist/web/workspace/_/__next.workspace.$d$id.__PAGE__.txt +3 -3
- package/dist/web/workspace/_/__next.workspace.$d$id.txt +3 -3
- package/dist/web/workspace/_/__next.workspace.txt +3 -3
- package/dist/web/workspace/_.html +1 -1
- package/dist/web/workspace/_.txt +31 -36
- package/dist/web/workspaces/__next._full.txt +30 -37
- package/dist/web/workspaces/__next._head.txt +4 -4
- package/dist/web/workspaces/__next._index.txt +14 -14
- package/dist/web/workspaces/__next._tree.txt +3 -8
- package/dist/web/workspaces/__next.workspaces.__PAGE__.txt +4 -4
- package/dist/web/workspaces/__next.workspaces.txt +3 -3
- package/dist/web/workspaces.html +1 -1
- package/dist/web/workspaces.txt +30 -37
- package/dist/ws/agent-prompt.js +45 -8
- package/dist/ws/agent-runner.js +88 -10
- package/package.json +1 -1
- package/dist/web/_next/static/chunks/0-1bfvfwifh-m.js +0 -1
- package/dist/web/_next/static/chunks/02mf61htij8g0.js +0 -31
- package/dist/web/_next/static/chunks/046me66nilkff.js +0 -1
- package/dist/web/_next/static/chunks/04v-pqqs-2lvp.css +0 -1
- package/dist/web/_next/static/chunks/06w~.izyfylap.js +0 -1
- package/dist/web/_next/static/chunks/09t62a89~jesc.js +0 -3
- package/dist/web/_next/static/chunks/09y_3krccdd~u.js +0 -1
- package/dist/web/_next/static/chunks/0_e~hmntdfop9.js +0 -1
- package/dist/web/_next/static/chunks/0_udc.6.tueey.js +0 -1
- package/dist/web/_next/static/chunks/0cke33d38fnby.js +0 -90
- package/dist/web/_next/static/chunks/0cyq~8xb~r5fc.js +0 -1
- package/dist/web/_next/static/chunks/0ewceguykiut5.js +0 -1
- package/dist/web/_next/static/chunks/0fxa1edqr7dve.js +0 -1
- package/dist/web/_next/static/chunks/0hra80eyuu37u.js +0 -1
- package/dist/web/_next/static/chunks/0ie7y4k2ncvnn.js +0 -1
- package/dist/web/_next/static/chunks/0igc~uli58ncw.js +0 -2
- package/dist/web/_next/static/chunks/0msb2mi3hiu5_.js +0 -67
- package/dist/web/_next/static/chunks/0p1n8bvfnpl41.js +0 -1
- package/dist/web/_next/static/chunks/0ppr271hz0xoq.js +0 -1
- package/dist/web/_next/static/chunks/0s_dva~eh2yhi.js +0 -3
- package/dist/web/_next/static/chunks/0typj55ox8d5i.js +0 -1
- package/dist/web/_next/static/chunks/0w2p4ldi2aymp.js +0 -1
- package/dist/web/_next/static/chunks/0zc0xgp5ourcn.js +0 -1
- package/dist/web/_next/static/chunks/0zmhdridea1s5.js +0 -90
- package/dist/web/_next/static/chunks/10.alq.6stmld.js +0 -1
- package/dist/web/_next/static/chunks/11b3zgk1etlkw.js +0 -7
- package/dist/web/_next/static/chunks/11qp8r5dotf7d.js +0 -1
- package/dist/web/_next/static/chunks/12mxlicp247c8.js +0 -1
- package/dist/web/_next/static/chunks/135w27dd8c19s.js +0 -5
- package/dist/web/_next/static/chunks/176dc-dtokxxi.js +0 -16
- package/dist/web/_next/static/chunks/17g-0pqre.anw.js +0 -1
- package/dist/web/_next/static/media/0a7740363b4d4863-s.1110aazvokzp..woff2 +0 -0
- package/dist/web/_next/static/media/0da9c7f357bd9d4d-s.0ek5sshv8wk3m.woff2 +0 -0
- package/dist/web/_next/static/media/1b99372b3eaef0c8-s.p.0gx2haw2tmll8.woff2 +0 -0
- package/dist/web/_next/static/media/41e95f694c5c4549-s.0r1jrq7neqdsq.woff2 +0 -0
- package/dist/web/_next/static/media/5c285b27cdda1fe8-s.p.0yo6-5yoeeudq.woff2 +0 -0
- package/dist/web/_next/static/media/5f9d24ebef5d5292-s.0esuu2f5si~v8.woff2 +0 -0
- package/dist/web/_next/static/media/6c55a692938ebbbc-s.0g6rbszwfgn9y.woff2 +0 -0
- package/dist/web/_next/static/media/8e6fa89aa22d24ec-s.p.0uvzar8hswo3p.woff2 +0 -0
- package/dist/web/_next/static/media/a218039a3287bcfd-s.p.17-1enzs_j91b.woff2 +0 -0
- package/dist/web/_next/static/media/b2ea385cb5ae8625-s.0kjod.kaq1k69.woff2 +0 -0
- package/dist/web/_next/static/media/bdc7e24a509eb931-s.0apt5mko2.qn3.woff2 +0 -0
- package/dist/web/_next/static/media/c3cb240f9c892514-s.163v2i5cux7-c.woff2 +0 -0
- package/dist/web/_next/static/media/e2334d715941921e-s.p.12skym0rqknxy.woff2 +0 -0
- package/public/output-styles/carmack-mode.md +0 -381
- package/public/output-styles/codex-rigor-mode.md +0 -114
- package/public/output-styles/dhh-mode.md +0 -265
- package/public/output-styles/evan-you-mode.md +0 -539
- package/public/output-styles/index.json +0 -37
- package/public/output-styles/jobs-mode.md +0 -369
- package/public/output-styles/linus-mode.md +0 -135
- package/public/output-styles/uncle-bob-mode.md +0 -221
- package/public/prompt/andrej-karpathy-skills.md +0 -65
- package/public/prompt/claude-token-efficient-coding.md +0 -35
- package/public/prompt/index.json +0 -12
- package/public/skills/index.json +0 -92
- package/public/skills/planning-with-files/planning-with-files-zh/SKILL.md +0 -243
- package/public/skills/planning-with-files/planning-with-files-zh/scripts/check-complete.ps1 +0 -44
- package/public/skills/planning-with-files/planning-with-files-zh/scripts/check-complete.sh +0 -46
- package/public/skills/planning-with-files/planning-with-files-zh/scripts/init-session.ps1 +0 -124
- package/public/skills/planning-with-files/planning-with-files-zh/scripts/init-session.sh +0 -124
- package/public/skills/planning-with-files/planning-with-files-zh/scripts/session-catchup.py +0 -438
- package/public/skills/planning-with-files/planning-with-files-zh/templates/findings.md +0 -29
- package/public/skills/planning-with-files/planning-with-files-zh/templates/progress.md +0 -40
- package/public/skills/planning-with-files/planning-with-files-zh/templates/task_plan.md +0 -58
- package/public/skills/superpowers/brainstorming/SKILL.md +0 -164
- package/public/skills/superpowers/brainstorming/scripts/frame-template.html +0 -214
- package/public/skills/superpowers/brainstorming/scripts/helper.js +0 -88
- package/public/skills/superpowers/brainstorming/scripts/server.cjs +0 -354
- package/public/skills/superpowers/brainstorming/scripts/start-server.sh +0 -148
- package/public/skills/superpowers/brainstorming/scripts/stop-server.sh +0 -56
- package/public/skills/superpowers/brainstorming/spec-document-reviewer-prompt.md +0 -49
- package/public/skills/superpowers/brainstorming/visual-companion.md +0 -287
- package/public/skills/superpowers/dispatching-parallel-agents/SKILL.md +0 -182
- package/public/skills/superpowers/executing-plans/SKILL.md +0 -70
- package/public/skills/superpowers/finishing-a-development-branch/SKILL.md +0 -251
- package/public/skills/superpowers/receiving-code-review/SKILL.md +0 -213
- package/public/skills/superpowers/requesting-code-review/SKILL.md +0 -103
- package/public/skills/superpowers/requesting-code-review/code-reviewer.md +0 -168
- package/public/skills/superpowers/subagent-driven-development/SKILL.md +0 -279
- package/public/skills/superpowers/subagent-driven-development/code-quality-reviewer-prompt.md +0 -25
- package/public/skills/superpowers/subagent-driven-development/implementer-prompt.md +0 -113
- package/public/skills/superpowers/subagent-driven-development/spec-reviewer-prompt.md +0 -61
- package/public/skills/superpowers/systematic-debugging/CREATION-LOG.md +0 -119
- package/public/skills/superpowers/systematic-debugging/SKILL.md +0 -296
- package/public/skills/superpowers/systematic-debugging/condition-based-waiting-example.ts +0 -158
- package/public/skills/superpowers/systematic-debugging/condition-based-waiting.md +0 -115
- package/public/skills/superpowers/systematic-debugging/defense-in-depth.md +0 -122
- package/public/skills/superpowers/systematic-debugging/find-polluter.sh +0 -63
- package/public/skills/superpowers/systematic-debugging/root-cause-tracing.md +0 -169
- package/public/skills/superpowers/systematic-debugging/test-academic.md +0 -14
- package/public/skills/superpowers/systematic-debugging/test-pressure-1.md +0 -58
- package/public/skills/superpowers/systematic-debugging/test-pressure-2.md +0 -68
- package/public/skills/superpowers/systematic-debugging/test-pressure-3.md +0 -69
- package/public/skills/superpowers/test-driven-development/SKILL.md +0 -371
- package/public/skills/superpowers/test-driven-development/testing-anti-patterns.md +0 -299
- package/public/skills/superpowers/using-git-worktrees/SKILL.md +0 -215
- package/public/skills/superpowers/using-superpowers/SKILL.md +0 -117
- package/public/skills/superpowers/using-superpowers/references/codex-tools.md +0 -59
- package/public/skills/superpowers/using-superpowers/references/copilot-tools.md +0 -42
- package/public/skills/superpowers/using-superpowers/references/gemini-tools.md +0 -51
- package/public/skills/superpowers/verification-before-completion/SKILL.md +0 -139
- package/public/skills/superpowers/writing-plans/SKILL.md +0 -152
- package/public/skills/superpowers/writing-plans/plan-document-reviewer-prompt.md +0 -49
- package/public/skills/superpowers/writing-skills/SKILL.md +0 -655
- package/public/skills/superpowers/writing-skills/anthropic-best-practices.md +0 -1150
- package/public/skills/superpowers/writing-skills/examples/CLAUDE_MD_TESTING.md +0 -189
- package/public/skills/superpowers/writing-skills/graphviz-conventions.dot +0 -172
- package/public/skills/superpowers/writing-skills/persuasion-principles.md +0 -187
- package/public/skills/superpowers/writing-skills/render-graphs.js +0 -168
- package/public/skills/superpowers/writing-skills/testing-skills-with-subagents.md +0 -384
- /package/dist/web/_next/static/{OoXAsPtrUWjC1l898FSvI → x4-CsKe6qUQyFDWVtfvUg}/_buildManifest.js +0 -0
- /package/dist/web/_next/static/{OoXAsPtrUWjC1l898FSvI → x4-CsKe6qUQyFDWVtfvUg}/_clientMiddlewareManifest.js +0 -0
- /package/dist/web/_next/static/{OoXAsPtrUWjC1l898FSvI → x4-CsKe6qUQyFDWVtfvUg}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import * as databaseStore from '../storage/database-store.js';
|
|
3
|
+
import * as llmStore from '../storage/llm-store.js';
|
|
4
|
+
const INDEX_BATCH_SIZE = 16;
|
|
5
|
+
const MAX_INDEX_TEXT_LENGTH = 24_000;
|
|
6
|
+
export class DatabaseVectorError extends Error {
|
|
7
|
+
debug;
|
|
8
|
+
constructor(message, debug) {
|
|
9
|
+
super(message);
|
|
10
|
+
this.name = 'DatabaseVectorError';
|
|
11
|
+
this.debug = debug;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
export async function indexDatabaseVectors(workspaceId, databaseId) {
|
|
15
|
+
const database = databaseStore.getDatabase(workspaceId, databaseId);
|
|
16
|
+
if (!database)
|
|
17
|
+
throw new Error(`Database not found: ${databaseId}`);
|
|
18
|
+
if (!database.embeddingModelId)
|
|
19
|
+
throw new Error('Embedding model is not bound to this database.');
|
|
20
|
+
const config = requireEmbeddingModelConfig(database.embeddingModelId);
|
|
21
|
+
const nodes = databaseStore.listNodes(workspaceId, databaseId).filter((node) => !node.isTrash);
|
|
22
|
+
const records = nodes
|
|
23
|
+
.map((node) => ({
|
|
24
|
+
node,
|
|
25
|
+
path: buildDatabaseNodePath(node, nodes),
|
|
26
|
+
text: normalizeIndexText(`${node.title}\n${stripHtml(node.content)}`),
|
|
27
|
+
}))
|
|
28
|
+
.filter((item) => item.text.length > 0);
|
|
29
|
+
let indexedCount = 0;
|
|
30
|
+
for (let index = 0; index < records.length; index += INDEX_BATCH_SIZE) {
|
|
31
|
+
const batch = records.slice(index, index + INDEX_BATCH_SIZE);
|
|
32
|
+
const batchDebug = {
|
|
33
|
+
batchStart: index,
|
|
34
|
+
batchSize: batch.length,
|
|
35
|
+
indexedCount,
|
|
36
|
+
};
|
|
37
|
+
console.info('[database-vector:index] embedding batch', {
|
|
38
|
+
workspaceId,
|
|
39
|
+
databaseId,
|
|
40
|
+
modelId: config.model.modelId,
|
|
41
|
+
providerName: config.provider.name,
|
|
42
|
+
...batchDebug,
|
|
43
|
+
inputLengths: batch.map((item) => item.text.length),
|
|
44
|
+
});
|
|
45
|
+
const embeddings = await embedTexts(config, batch.map((item) => item.text), batchDebug);
|
|
46
|
+
embeddings.forEach((embedding, offset) => {
|
|
47
|
+
const item = batch[offset];
|
|
48
|
+
databaseStore.upsertDatabaseEmbedding(workspaceId, databaseId, {
|
|
49
|
+
nodeId: item.node.id,
|
|
50
|
+
title: item.node.title,
|
|
51
|
+
path: item.path,
|
|
52
|
+
content: item.text,
|
|
53
|
+
contentHash: hashText(item.text),
|
|
54
|
+
embedding,
|
|
55
|
+
modelId: config.model.modelId,
|
|
56
|
+
agentId: config.model.id,
|
|
57
|
+
});
|
|
58
|
+
indexedCount++;
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
databaseStore.deleteStaleDatabaseEmbeddings(workspaceId, databaseId, records.map((item) => item.node.id));
|
|
62
|
+
return {
|
|
63
|
+
...databaseStore.getVectorStats(workspaceId, databaseId),
|
|
64
|
+
indexedCount,
|
|
65
|
+
skippedCount: nodes.length - records.length,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
export async function searchDatabaseVectors(workspaceId, databaseId, query, limit = 5) {
|
|
69
|
+
const database = databaseStore.getDatabase(workspaceId, databaseId);
|
|
70
|
+
if (!database)
|
|
71
|
+
throw new Error(`Database not found: ${databaseId}`);
|
|
72
|
+
if (!database.embeddingModelId)
|
|
73
|
+
throw new Error('Embedding model is not bound to this database.');
|
|
74
|
+
const cleanQuery = normalizeIndexText(query);
|
|
75
|
+
if (!cleanQuery)
|
|
76
|
+
throw new Error('query is required.');
|
|
77
|
+
const config = requireEmbeddingModelConfig(database.embeddingModelId);
|
|
78
|
+
const [queryEmbedding] = await embedTexts(config, [cleanQuery]);
|
|
79
|
+
return databaseStore.listDatabaseEmbeddings(workspaceId, databaseId)
|
|
80
|
+
.map((row) => ({
|
|
81
|
+
nodeId: row.nodeId,
|
|
82
|
+
title: row.title,
|
|
83
|
+
path: row.path,
|
|
84
|
+
content: row.content,
|
|
85
|
+
updatedAt: row.updatedAt,
|
|
86
|
+
score: cosineSimilarity(queryEmbedding, row.embedding),
|
|
87
|
+
}))
|
|
88
|
+
.sort((a, b) => b.score - a.score)
|
|
89
|
+
.slice(0, Math.max(1, Math.min(limit, 20)));
|
|
90
|
+
}
|
|
91
|
+
function requireEmbeddingModelConfig(modelId) {
|
|
92
|
+
const model = llmStore.getModel(modelId);
|
|
93
|
+
if (!model)
|
|
94
|
+
throw new Error(`Embedding model not found: ${modelId}`);
|
|
95
|
+
if (!model.embedding)
|
|
96
|
+
throw new Error(`Selected model is not marked as an embedding model: ${model.name}`);
|
|
97
|
+
const provider = llmStore.listProviders().find((item) => item.name === model.provider);
|
|
98
|
+
if (!provider)
|
|
99
|
+
throw new Error(`Provider not found for embedding model: ${model.provider}`);
|
|
100
|
+
if (!provider.apiBase || !provider.apiKey || !model.modelId) {
|
|
101
|
+
throw new Error(`Embedding provider is missing apiBase, apiKey, or modelId: ${provider.name}`);
|
|
102
|
+
}
|
|
103
|
+
return { model, provider };
|
|
104
|
+
}
|
|
105
|
+
async function embedTexts(config, input, extraDebug = {}) {
|
|
106
|
+
const requestUrl = getEmbeddingsUrl(config.provider.apiBase);
|
|
107
|
+
const requestDebug = {
|
|
108
|
+
stage: 'embedding_request',
|
|
109
|
+
providerName: config.provider.name,
|
|
110
|
+
modelId: config.model.modelId,
|
|
111
|
+
requestUrl,
|
|
112
|
+
inputCount: input.length,
|
|
113
|
+
inputLengths: input.map((item) => item.length),
|
|
114
|
+
...extraDebug,
|
|
115
|
+
};
|
|
116
|
+
console.info('[database-vector:embed] request', requestDebug);
|
|
117
|
+
const response = await fetch(requestUrl, {
|
|
118
|
+
method: 'POST',
|
|
119
|
+
headers: {
|
|
120
|
+
Authorization: `Bearer ${config.provider.apiKey}`,
|
|
121
|
+
'Content-Type': 'application/json',
|
|
122
|
+
},
|
|
123
|
+
body: JSON.stringify({
|
|
124
|
+
model: config.model.modelId,
|
|
125
|
+
input,
|
|
126
|
+
}),
|
|
127
|
+
});
|
|
128
|
+
const responseText = await response.text();
|
|
129
|
+
const responseDebugBase = {
|
|
130
|
+
...requestDebug,
|
|
131
|
+
stage: 'embedding_response',
|
|
132
|
+
status: response.status,
|
|
133
|
+
responseContentType: response.headers.get('content-type'),
|
|
134
|
+
};
|
|
135
|
+
if (!response.ok) {
|
|
136
|
+
const debug = {
|
|
137
|
+
...responseDebugBase,
|
|
138
|
+
responsePreview: responseText.slice(0, 1000),
|
|
139
|
+
};
|
|
140
|
+
console.warn('[database-vector:embed] failed response', debug);
|
|
141
|
+
throw new DatabaseVectorError(`Embedding request failed with status ${response.status}`, debug);
|
|
142
|
+
}
|
|
143
|
+
let data;
|
|
144
|
+
try {
|
|
145
|
+
data = JSON.parse(responseText);
|
|
146
|
+
}
|
|
147
|
+
catch {
|
|
148
|
+
const debug = {
|
|
149
|
+
...responseDebugBase,
|
|
150
|
+
stage: 'embedding_parse_json',
|
|
151
|
+
responsePreview: responseText.slice(0, 1000),
|
|
152
|
+
};
|
|
153
|
+
console.warn('[database-vector:embed] invalid json', debug);
|
|
154
|
+
throw new DatabaseVectorError('Embedding response is not valid JSON.', debug);
|
|
155
|
+
}
|
|
156
|
+
const responseData = isRecord(data) && Array.isArray(data.data) ? data.data : undefined;
|
|
157
|
+
const embeddings = responseData
|
|
158
|
+
?.map((item) => isRecord(item) ? item.embedding : undefined)
|
|
159
|
+
.filter((item) => Array.isArray(item) && item.every((value) => typeof value === 'number'));
|
|
160
|
+
const debug = {
|
|
161
|
+
...responseDebugBase,
|
|
162
|
+
responseDataCount: responseData?.length,
|
|
163
|
+
validEmbeddingCount: embeddings?.length ?? 0,
|
|
164
|
+
embeddingDimensions: embeddings?.map((embedding) => embedding.length).slice(0, 10),
|
|
165
|
+
responseKeys: isRecord(data) ? Object.keys(data) : undefined,
|
|
166
|
+
responsePreview: previewEmbeddingResponse(data),
|
|
167
|
+
};
|
|
168
|
+
console.info('[database-vector:embed] parsed response', debug);
|
|
169
|
+
if (!embeddings || embeddings.length !== input.length) {
|
|
170
|
+
throw new DatabaseVectorError(`Embedding response does not match input length. expected=${input.length}, data=${responseData?.length ?? 0}, validEmbeddings=${embeddings?.length ?? 0}`, debug);
|
|
171
|
+
}
|
|
172
|
+
return embeddings;
|
|
173
|
+
}
|
|
174
|
+
function isRecord(value) {
|
|
175
|
+
return Boolean(value && typeof value === 'object' && !Array.isArray(value));
|
|
176
|
+
}
|
|
177
|
+
function previewEmbeddingResponse(value) {
|
|
178
|
+
if (!isRecord(value))
|
|
179
|
+
return value;
|
|
180
|
+
const data = Array.isArray(value.data)
|
|
181
|
+
? value.data.slice(0, 3).map((item) => {
|
|
182
|
+
if (!isRecord(item))
|
|
183
|
+
return item;
|
|
184
|
+
const embedding = Array.isArray(item.embedding) ? item.embedding : undefined;
|
|
185
|
+
return {
|
|
186
|
+
...item,
|
|
187
|
+
embedding: embedding ? `[number[${embedding.length}]]` : item.embedding,
|
|
188
|
+
};
|
|
189
|
+
})
|
|
190
|
+
: value.data;
|
|
191
|
+
return {
|
|
192
|
+
...value,
|
|
193
|
+
data,
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
function getEmbeddingsUrl(apiBase) {
|
|
197
|
+
const base = apiBase.replace(/\/+$/, '');
|
|
198
|
+
if (base.endsWith('/embeddings'))
|
|
199
|
+
return base;
|
|
200
|
+
return `${base}/embeddings`;
|
|
201
|
+
}
|
|
202
|
+
function normalizeIndexText(text) {
|
|
203
|
+
return text.replace(/\s+/g, ' ').trim().slice(0, MAX_INDEX_TEXT_LENGTH);
|
|
204
|
+
}
|
|
205
|
+
function stripHtml(content) {
|
|
206
|
+
return content
|
|
207
|
+
.replace(/<style[\s\S]*?<\/style>/gi, ' ')
|
|
208
|
+
.replace(/<script[\s\S]*?<\/script>/gi, ' ')
|
|
209
|
+
.replace(/<[^>]+>/g, ' ');
|
|
210
|
+
}
|
|
211
|
+
function hashText(text) {
|
|
212
|
+
return createHash('sha256').update(text).digest('hex');
|
|
213
|
+
}
|
|
214
|
+
function cosineSimilarity(a, b) {
|
|
215
|
+
if (a.length !== b.length || a.length === 0)
|
|
216
|
+
return 0;
|
|
217
|
+
let dot = 0;
|
|
218
|
+
let ma = 0;
|
|
219
|
+
let mb = 0;
|
|
220
|
+
for (let index = 0; index < a.length; index++) {
|
|
221
|
+
dot += a[index] * b[index];
|
|
222
|
+
ma += a[index] * a[index];
|
|
223
|
+
mb += b[index] * b[index];
|
|
224
|
+
}
|
|
225
|
+
if (!ma || !mb)
|
|
226
|
+
return 0;
|
|
227
|
+
return dot / (Math.sqrt(ma) * Math.sqrt(mb));
|
|
228
|
+
}
|
|
229
|
+
function buildDatabaseNodePath(node, nodes) {
|
|
230
|
+
const byId = new Map(nodes.map((item) => [item.id, item]));
|
|
231
|
+
const parts = [node.title || node.id];
|
|
232
|
+
let parentId = node.parentId;
|
|
233
|
+
let guard = 0;
|
|
234
|
+
while (parentId && guard < 100) {
|
|
235
|
+
const parent = byId.get(parentId);
|
|
236
|
+
if (!parent)
|
|
237
|
+
break;
|
|
238
|
+
parts.unshift(parent.title || parent.id);
|
|
239
|
+
parentId = parent.parentId;
|
|
240
|
+
guard++;
|
|
241
|
+
}
|
|
242
|
+
return `/${parts.join('/')}`;
|
|
243
|
+
}
|
|
244
|
+
//# sourceMappingURL=database-vector.js.map
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
const MAX_ENTRIES = 1000;
|
|
2
|
+
const store = new Map();
|
|
3
|
+
function getList(workspaceId) {
|
|
4
|
+
let list = store.get(workspaceId);
|
|
5
|
+
if (!list) {
|
|
6
|
+
list = [];
|
|
7
|
+
store.set(workspaceId, list);
|
|
8
|
+
}
|
|
9
|
+
return list;
|
|
10
|
+
}
|
|
11
|
+
let counter = 0;
|
|
12
|
+
export function logGitOperation(workspaceId, operation, input, result, error, duration = 0) {
|
|
13
|
+
const list = getList(workspaceId);
|
|
14
|
+
const entry = {
|
|
15
|
+
id: `${Date.now()}-${++counter}`,
|
|
16
|
+
operation,
|
|
17
|
+
input,
|
|
18
|
+
output: truncateOutput(result),
|
|
19
|
+
error,
|
|
20
|
+
timestamp: new Date().toISOString(),
|
|
21
|
+
duration,
|
|
22
|
+
};
|
|
23
|
+
list.unshift(entry);
|
|
24
|
+
if (list.length > MAX_ENTRIES)
|
|
25
|
+
list.length = MAX_ENTRIES;
|
|
26
|
+
}
|
|
27
|
+
export function getGitOperations(workspaceId) {
|
|
28
|
+
return getList(workspaceId);
|
|
29
|
+
}
|
|
30
|
+
function truncateOutput(value) {
|
|
31
|
+
if (value === undefined || value === null)
|
|
32
|
+
return value;
|
|
33
|
+
if (typeof value === 'string')
|
|
34
|
+
return value.length > 5000 ? value.slice(0, 5000) + '...(truncated)' : value;
|
|
35
|
+
const s = JSON.stringify(value);
|
|
36
|
+
if (s && s.length > 5000)
|
|
37
|
+
return JSON.parse(s.slice(0, 5000) + '...(truncated)');
|
|
38
|
+
return value;
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=git-operation-log.js.map
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { WECHAT_BASE_URL, WECHAT_BOT_TYPE, WECHAT_QR_STATUS_TIMEOUT_MS, } from './notification-hub/types.js';
|
|
2
|
+
import { createAccount } from './robot-account.js';
|
|
3
|
+
const globalSessions = new Map();
|
|
4
|
+
export async function getGlobalWeChatQRCode() {
|
|
5
|
+
// cleanup old sessions
|
|
6
|
+
const now = Date.now();
|
|
7
|
+
for (const [key, s] of globalSessions) {
|
|
8
|
+
if (now - s.createdAt > 5 * 60_000)
|
|
9
|
+
globalSessions.delete(key);
|
|
10
|
+
}
|
|
11
|
+
const res = await fetch(`${WECHAT_BASE_URL}/ilink/bot/get_bot_qrcode?bot_type=${WECHAT_BOT_TYPE}`);
|
|
12
|
+
if (!res.ok)
|
|
13
|
+
throw new Error(`Failed to get WeChat QR code: ${res.status}`);
|
|
14
|
+
const qr = await res.json();
|
|
15
|
+
const sessionId = `global-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
16
|
+
globalSessions.set(sessionId, {
|
|
17
|
+
qrcode: qr.qrcode,
|
|
18
|
+
qrcodeImgContent: qr.qrcode_img_content,
|
|
19
|
+
createdAt: now,
|
|
20
|
+
});
|
|
21
|
+
return { status: 'wait', qrcodeImgContent: qr.qrcode_img_content, sessionId };
|
|
22
|
+
}
|
|
23
|
+
export async function pollGlobalWeChatQRCode(sessionId) {
|
|
24
|
+
if (!sessionId)
|
|
25
|
+
throw new Error('sessionId is required');
|
|
26
|
+
const session = globalSessions.get(sessionId);
|
|
27
|
+
if (!session)
|
|
28
|
+
throw new Error('Session not found or expired');
|
|
29
|
+
const status = await fetchQRStatus(session.qrcode);
|
|
30
|
+
if (status.status === 'confirmed') {
|
|
31
|
+
if (!status.bot_token || !status.ilink_bot_id) {
|
|
32
|
+
throw new Error('WeChat login confirmed but token or bot id is missing');
|
|
33
|
+
}
|
|
34
|
+
globalSessions.delete(sessionId);
|
|
35
|
+
const account = createAccount({
|
|
36
|
+
name: `微信 ${status.ilink_bot_id}`,
|
|
37
|
+
type: 'wechat',
|
|
38
|
+
wechat: {
|
|
39
|
+
token: status.bot_token,
|
|
40
|
+
baseUrl: status.baseurl || WECHAT_BASE_URL,
|
|
41
|
+
accountId: status.ilink_bot_id,
|
|
42
|
+
userId: status.ilink_user_id,
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
return { status: 'confirmed', account };
|
|
46
|
+
}
|
|
47
|
+
if (status.status === 'expired') {
|
|
48
|
+
globalSessions.delete(sessionId);
|
|
49
|
+
}
|
|
50
|
+
return { status: status.status, qrcodeImgContent: session.qrcodeImgContent, sessionId };
|
|
51
|
+
}
|
|
52
|
+
async function fetchQRStatus(qrcode) {
|
|
53
|
+
const controller = new AbortController();
|
|
54
|
+
const timer = setTimeout(() => controller.abort(), WECHAT_QR_STATUS_TIMEOUT_MS);
|
|
55
|
+
try {
|
|
56
|
+
const res = await fetch(`${WECHAT_BASE_URL}/ilink/bot/get_qrcode_status?qrcode=${encodeURIComponent(qrcode)}`, {
|
|
57
|
+
headers: { 'iLink-App-ClientVersion': '1' },
|
|
58
|
+
signal: controller.signal,
|
|
59
|
+
});
|
|
60
|
+
clearTimeout(timer);
|
|
61
|
+
if (!res.ok)
|
|
62
|
+
throw new Error(`Failed to poll QR status: ${res.status}`);
|
|
63
|
+
return await res.json();
|
|
64
|
+
}
|
|
65
|
+
catch (err) {
|
|
66
|
+
clearTimeout(timer);
|
|
67
|
+
if (err instanceof Error && err.name === 'AbortError')
|
|
68
|
+
return { status: 'wait' };
|
|
69
|
+
throw err;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=global-wechat-qr.js.map
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import { exec } from 'node:child_process';
|
|
2
2
|
import { listHooks } from '../storage/hook-store.js';
|
|
3
|
+
function logDebug(message, details) {
|
|
4
|
+
if (details) {
|
|
5
|
+
console.debug(`[HookEngine] ${message}`, details);
|
|
6
|
+
return;
|
|
7
|
+
}
|
|
8
|
+
console.debug(`[HookEngine] ${message}`);
|
|
9
|
+
}
|
|
3
10
|
function matchToolName(matcher, toolName) {
|
|
4
11
|
if (matcher === '*')
|
|
5
12
|
return true;
|
|
@@ -8,7 +15,12 @@ function matchToolName(matcher, toolName) {
|
|
|
8
15
|
const regex = new RegExp(matcher.slice(1, -1));
|
|
9
16
|
return regex.test(toolName);
|
|
10
17
|
}
|
|
11
|
-
catch {
|
|
18
|
+
catch (error) {
|
|
19
|
+
console.warn(`[HookEngine] invalid matcher regex, falling back to exact match`, {
|
|
20
|
+
matcher,
|
|
21
|
+
toolName,
|
|
22
|
+
error: error.message,
|
|
23
|
+
});
|
|
12
24
|
return matcher === toolName;
|
|
13
25
|
}
|
|
14
26
|
}
|
|
@@ -16,7 +28,8 @@ function matchToolName(matcher, toolName) {
|
|
|
16
28
|
}
|
|
17
29
|
function executeCommand(command, env, timeout) {
|
|
18
30
|
return new Promise((resolve) => {
|
|
19
|
-
|
|
31
|
+
const cappedTimeout = Math.min(timeout, 30000);
|
|
32
|
+
exec(command, { env: { ...process.env, ...env }, timeout: cappedTimeout }, (error) => {
|
|
20
33
|
if (error)
|
|
21
34
|
console.warn(`[HookEngine] command error: ${error.message}`);
|
|
22
35
|
resolve();
|
|
@@ -26,43 +39,101 @@ function executeCommand(command, env, timeout) {
|
|
|
26
39
|
async function executeWebhook(url, body, timeout) {
|
|
27
40
|
try {
|
|
28
41
|
const controller = new AbortController();
|
|
29
|
-
const
|
|
30
|
-
|
|
42
|
+
const cappedTimeout = Math.min(timeout, 30000);
|
|
43
|
+
const timer = setTimeout(() => controller.abort(), cappedTimeout);
|
|
44
|
+
const response = await fetch(url, {
|
|
31
45
|
method: 'POST',
|
|
32
46
|
headers: { 'Content-Type': 'application/json' },
|
|
33
47
|
body: JSON.stringify(body),
|
|
34
48
|
signal: controller.signal,
|
|
35
49
|
});
|
|
36
50
|
clearTimeout(timer);
|
|
51
|
+
if (!response.ok) {
|
|
52
|
+
console.warn(`[HookEngine] webhook non-2xx response`, {
|
|
53
|
+
url,
|
|
54
|
+
status: response.status,
|
|
55
|
+
statusText: response.statusText,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
37
58
|
}
|
|
38
59
|
catch (error) {
|
|
39
60
|
console.warn(`[HookEngine] webhook error: ${error.message}`);
|
|
40
61
|
}
|
|
41
62
|
}
|
|
42
|
-
async function executeRule(rule, phase,
|
|
63
|
+
async function executeRule(rule, phase, matcherValue, workspaceId, context, hookName) {
|
|
43
64
|
const timeout = rule.timeout ?? 10000;
|
|
65
|
+
const startedAt = Date.now();
|
|
66
|
+
logDebug('rule start', {
|
|
67
|
+
workspaceId,
|
|
68
|
+
phase,
|
|
69
|
+
hookName,
|
|
70
|
+
matcherValue,
|
|
71
|
+
matcher: rule.matcher,
|
|
72
|
+
type: rule.type,
|
|
73
|
+
timeout,
|
|
74
|
+
});
|
|
44
75
|
if (rule.type === 'command' && rule.command) {
|
|
45
76
|
await executeCommand(rule.command, {
|
|
46
|
-
|
|
77
|
+
HOOK_NAME: hookName ?? '',
|
|
78
|
+
HOOK_RULE_MATCHER: rule.matcher,
|
|
79
|
+
HOOK_RULE_TYPE: rule.type,
|
|
80
|
+
HOOK_RULE_TIMEOUT: String(timeout),
|
|
81
|
+
HOOK_EVENT_NAME: context.eventName ?? phase,
|
|
82
|
+
HOOK_EVENT_PAYLOAD: JSON.stringify(context.eventPayload ?? {}),
|
|
83
|
+
HOOK_MATCHER_VALUE: matcherValue,
|
|
84
|
+
HOOK_TOOL_NAME: matcherValue,
|
|
85
|
+
HOOK_TOOL_USE_ID: context.toolUseId ?? '',
|
|
47
86
|
HOOK_TOOL_INPUT: JSON.stringify(context.toolInput ?? {}),
|
|
48
87
|
HOOK_TOOL_RESULT: JSON.stringify(context.toolResult ?? ''),
|
|
49
88
|
HOOK_WORKSPACE_ID: workspaceId,
|
|
50
89
|
HOOK_PHASE: phase,
|
|
90
|
+
HOOK_TRIGGER_CHECKED_RULES: String(context.checkedRules ?? ''),
|
|
91
|
+
HOOK_TRIGGER_MATCHED_RULES: String(context.matchedRules ?? ''),
|
|
92
|
+
HOOK_TRIGGERED_AT: new Date().toISOString(),
|
|
51
93
|
}, timeout);
|
|
52
94
|
}
|
|
53
95
|
else if (rule.type === 'webhook' && rule.url) {
|
|
54
96
|
await executeWebhook(rule.url, {
|
|
55
97
|
event: phase,
|
|
56
|
-
toolName,
|
|
98
|
+
toolName: matcherValue,
|
|
99
|
+
matcherValue,
|
|
57
100
|
toolInput: context.toolInput,
|
|
58
101
|
toolResult: context.toolResult ?? undefined,
|
|
102
|
+
payload: context.eventPayload,
|
|
59
103
|
timestamp: new Date().toISOString(),
|
|
60
104
|
workspaceId,
|
|
61
105
|
}, timeout);
|
|
62
106
|
}
|
|
63
107
|
else if (rule.type === 'script') {
|
|
64
|
-
console.warn(`[HookEngine] script type not implemented, skipping rule
|
|
108
|
+
console.warn(`[HookEngine] script type not implemented, skipping rule`, {
|
|
109
|
+
workspaceId,
|
|
110
|
+
phase,
|
|
111
|
+
hookName,
|
|
112
|
+
matcherValue,
|
|
113
|
+
matcher: rule.matcher,
|
|
114
|
+
});
|
|
65
115
|
}
|
|
116
|
+
else {
|
|
117
|
+
console.warn(`[HookEngine] invalid rule configuration, skipping rule`, {
|
|
118
|
+
workspaceId,
|
|
119
|
+
phase,
|
|
120
|
+
hookName,
|
|
121
|
+
matcherValue,
|
|
122
|
+
matcher: rule.matcher,
|
|
123
|
+
type: rule.type,
|
|
124
|
+
hasCommand: Boolean(rule.command),
|
|
125
|
+
hasUrl: Boolean(rule.url),
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
logDebug('rule finished', {
|
|
129
|
+
workspaceId,
|
|
130
|
+
phase,
|
|
131
|
+
hookName,
|
|
132
|
+
matcherValue,
|
|
133
|
+
matcher: rule.matcher,
|
|
134
|
+
type: rule.type,
|
|
135
|
+
durationMs: Date.now() - startedAt,
|
|
136
|
+
});
|
|
66
137
|
}
|
|
67
138
|
export class HookEngine {
|
|
68
139
|
hooks = [];
|
|
@@ -72,6 +143,12 @@ export class HookEngine {
|
|
|
72
143
|
}
|
|
73
144
|
load() {
|
|
74
145
|
this.hooks = listHooks(this.workspaceId);
|
|
146
|
+
logDebug('loaded hooks', {
|
|
147
|
+
workspaceId: this.workspaceId,
|
|
148
|
+
totalHooks: this.hooks.length,
|
|
149
|
+
enabledHooks: this.hooks.filter(h => h.enabled).length,
|
|
150
|
+
hookNames: this.hooks.map(h => h.name),
|
|
151
|
+
});
|
|
75
152
|
}
|
|
76
153
|
reload() {
|
|
77
154
|
this.load();
|
|
@@ -79,40 +156,121 @@ export class HookEngine {
|
|
|
79
156
|
getHooks() {
|
|
80
157
|
return this.hooks;
|
|
81
158
|
}
|
|
82
|
-
async executeHooks(phase,
|
|
159
|
+
async executeHooks(phase, matcherValue, context) {
|
|
83
160
|
const enabledHooks = this.hooks.filter(h => h.enabled);
|
|
84
161
|
const promises = [];
|
|
162
|
+
const matchedRuleEntries = [];
|
|
163
|
+
let checkedRules = 0;
|
|
164
|
+
let matchedRules = 0;
|
|
165
|
+
logDebug('trigger received', {
|
|
166
|
+
workspaceId: this.workspaceId,
|
|
167
|
+
phase,
|
|
168
|
+
matcherValue,
|
|
169
|
+
totalHooks: this.hooks.length,
|
|
170
|
+
enabledHooks: enabledHooks.length,
|
|
171
|
+
hasToolInput: context.toolInput !== undefined,
|
|
172
|
+
hasToolResult: context.toolResult !== undefined,
|
|
173
|
+
});
|
|
85
174
|
for (const hook of enabledHooks) {
|
|
86
175
|
const rules = hook.hooks[phase];
|
|
87
176
|
if (!rules)
|
|
88
177
|
continue;
|
|
89
178
|
for (const rule of rules) {
|
|
90
|
-
|
|
91
|
-
|
|
179
|
+
checkedRules += 1;
|
|
180
|
+
if (matchToolName(rule.matcher, matcherValue)) {
|
|
181
|
+
matchedRules += 1;
|
|
182
|
+
logDebug('rule matched', {
|
|
183
|
+
workspaceId: this.workspaceId,
|
|
184
|
+
phase,
|
|
185
|
+
hookName: hook.name,
|
|
186
|
+
matcherValue,
|
|
187
|
+
matcher: rule.matcher,
|
|
188
|
+
type: rule.type,
|
|
189
|
+
});
|
|
190
|
+
matchedRuleEntries.push({ hookName: hook.name, rule });
|
|
92
191
|
}
|
|
93
192
|
}
|
|
94
193
|
}
|
|
95
|
-
|
|
194
|
+
for (const { hookName, rule } of matchedRuleEntries) {
|
|
195
|
+
promises.push(executeRule(rule, phase, matcherValue, this.workspaceId, {
|
|
196
|
+
...context,
|
|
197
|
+
checkedRules,
|
|
198
|
+
matchedRules,
|
|
199
|
+
}, hookName));
|
|
200
|
+
}
|
|
201
|
+
const results = await Promise.allSettled(promises);
|
|
202
|
+
const rejectedRules = results.filter(result => result.status === 'rejected').length;
|
|
203
|
+
logDebug('trigger finished', {
|
|
204
|
+
workspaceId: this.workspaceId,
|
|
205
|
+
phase,
|
|
206
|
+
matcherValue,
|
|
207
|
+
checkedRules,
|
|
208
|
+
matchedRules,
|
|
209
|
+
rejectedRules,
|
|
210
|
+
});
|
|
96
211
|
}
|
|
97
212
|
}
|
|
98
213
|
export function wrapOnEventWithHooks(onEvent, workspaceId, hooksEnabled) {
|
|
99
|
-
if (!hooksEnabled)
|
|
214
|
+
if (!hooksEnabled) {
|
|
215
|
+
logDebug('hooks disabled for workspace', { workspaceId });
|
|
100
216
|
return onEvent;
|
|
217
|
+
}
|
|
101
218
|
const engine = new HookEngine(workspaceId);
|
|
102
219
|
engine.load();
|
|
103
220
|
const toolNameById = new Map();
|
|
221
|
+
let lastToolUse = null;
|
|
104
222
|
return (event) => {
|
|
105
|
-
|
|
223
|
+
if (event.type !== 'hook_event')
|
|
224
|
+
onEvent(event);
|
|
106
225
|
if (event.type === 'tool_use') {
|
|
107
226
|
toolNameById.set(event.id, event.name);
|
|
108
|
-
|
|
227
|
+
lastToolUse = { id: event.id, name: event.name };
|
|
228
|
+
logDebug('tool_use event mapped', {
|
|
229
|
+
workspaceId,
|
|
230
|
+
toolUseId: event.id,
|
|
231
|
+
toolName: event.name,
|
|
232
|
+
});
|
|
233
|
+
engine.executeHooks('PreToolUse', event.name, { toolInput: event.input, toolUseId: event.id });
|
|
109
234
|
}
|
|
110
235
|
if (event.type === 'tool_result') {
|
|
111
|
-
const
|
|
236
|
+
const resolvedToolUseId = event.toolUseId || lastToolUse?.id;
|
|
237
|
+
const toolName = resolvedToolUseId ? (toolNameById.get(resolvedToolUseId) ?? '') : '';
|
|
112
238
|
if (toolName) {
|
|
113
|
-
|
|
239
|
+
logDebug('tool_result event resolved', {
|
|
240
|
+
workspaceId,
|
|
241
|
+
toolUseId: resolvedToolUseId,
|
|
242
|
+
originalToolUseId: event.toolUseId,
|
|
243
|
+
toolName,
|
|
244
|
+
});
|
|
245
|
+
engine.executeHooks('PostToolUse', toolName, { toolResult: event.result, toolUseId: resolvedToolUseId });
|
|
246
|
+
if (isToolFailureResult(event.result)) {
|
|
247
|
+
engine.executeHooks('PostToolUseFailure', toolName, { toolResult: event.result, toolUseId: resolvedToolUseId });
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
else {
|
|
251
|
+
logDebug('tool_result event skipped without matching tool_use', {
|
|
252
|
+
workspaceId,
|
|
253
|
+
toolUseId: event.toolUseId,
|
|
254
|
+
});
|
|
114
255
|
}
|
|
115
256
|
}
|
|
257
|
+
if (event.type === 'hook_event') {
|
|
258
|
+
logDebug('hook_event received', {
|
|
259
|
+
workspaceId,
|
|
260
|
+
event: event.event,
|
|
261
|
+
matcher: event.matcher ?? '*',
|
|
262
|
+
});
|
|
263
|
+
engine.executeHooks(event.event, event.matcher ?? '*', {
|
|
264
|
+
eventName: event.event,
|
|
265
|
+
eventPayload: event.payload,
|
|
266
|
+
});
|
|
267
|
+
}
|
|
116
268
|
};
|
|
117
269
|
}
|
|
270
|
+
function isToolFailureResult(result) {
|
|
271
|
+
if (!result || typeof result !== 'object')
|
|
272
|
+
return false;
|
|
273
|
+
const record = result;
|
|
274
|
+
return record.error !== undefined || record.is_error === true || record.success === false;
|
|
275
|
+
}
|
|
118
276
|
//# sourceMappingURL=hook-engine.js.map
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import * as store from '../storage/kanban-store.js';
|
|
2
|
+
export function getBoard(workspaceId) {
|
|
3
|
+
return store.getBoard(workspaceId);
|
|
4
|
+
}
|
|
5
|
+
export function ensureBoard(workspaceId) {
|
|
6
|
+
let board = store.getBoard(workspaceId);
|
|
7
|
+
if (!board) {
|
|
8
|
+
board = store.createBoard(workspaceId);
|
|
9
|
+
const defaultColumns = [
|
|
10
|
+
{ id: 'todo', title: 'To Do', color: 'sky', order: 0 },
|
|
11
|
+
{ id: 'progress', title: 'In Progress', color: 'amber', order: 1 },
|
|
12
|
+
{ id: 'done', title: 'Done', color: 'emerald', order: 2 },
|
|
13
|
+
{ id: 'archive', title: 'Archive', color: 'slate', order: 3 },
|
|
14
|
+
];
|
|
15
|
+
store.saveColumns(board.id, defaultColumns);
|
|
16
|
+
board = store.getBoard(workspaceId);
|
|
17
|
+
}
|
|
18
|
+
return board;
|
|
19
|
+
}
|
|
20
|
+
export function updateBoard(workspaceId, updates) {
|
|
21
|
+
return store.updateBoard(workspaceId, updates);
|
|
22
|
+
}
|
|
23
|
+
export function saveColumns(workspaceId, columns) {
|
|
24
|
+
const board = store.getBoard(workspaceId);
|
|
25
|
+
if (!board)
|
|
26
|
+
return null;
|
|
27
|
+
store.saveColumns(board.id, columns);
|
|
28
|
+
return store.getBoard(workspaceId);
|
|
29
|
+
}
|
|
30
|
+
export function saveTasks(workspaceId, tasks) {
|
|
31
|
+
const board = store.getBoard(workspaceId);
|
|
32
|
+
if (!board)
|
|
33
|
+
return null;
|
|
34
|
+
store.saveTasks(board.id, tasks);
|
|
35
|
+
return store.getBoard(workspaceId);
|
|
36
|
+
}
|
|
37
|
+
export function saveBoard(workspaceId, data) {
|
|
38
|
+
let board = store.getBoard(workspaceId);
|
|
39
|
+
if (!board)
|
|
40
|
+
board = store.createBoard(workspaceId);
|
|
41
|
+
if (data.title || data.layoutMode) {
|
|
42
|
+
store.updateBoard(workspaceId, { title: data.title, layoutMode: data.layoutMode });
|
|
43
|
+
}
|
|
44
|
+
if (data.columns)
|
|
45
|
+
store.saveColumns(board.id, data.columns);
|
|
46
|
+
if (data.tasks)
|
|
47
|
+
store.saveTasks(board.id, data.tasks);
|
|
48
|
+
return store.getBoard(workspaceId);
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=kanban.js.map
|