vibe-coding-master 0.3.0 → 0.3.2

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.
Files changed (44) hide show
  1. package/README.md +10 -7
  2. package/dist/backend/adapters/claude-adapter.js +4 -1
  3. package/dist/backend/api/codex-hook-routes.js +9 -0
  4. package/dist/backend/api/codex-review-routes.js +4 -0
  5. package/dist/backend/api/translation-routes.js +2 -2
  6. package/dist/backend/cli/install-vcm-harness.js +14 -1
  7. package/dist/backend/gateway/gateway-service.js +4 -3
  8. package/dist/backend/server.js +10 -0
  9. package/dist/backend/services/app-settings-service.js +12 -4
  10. package/dist/backend/services/artifact-service.js +2 -1
  11. package/dist/backend/services/claude-hook-service.js +3 -3
  12. package/dist/backend/services/codex-hook-service.js +87 -0
  13. package/dist/backend/services/codex-review-service.js +145 -60
  14. package/dist/backend/services/harness-service.js +28 -1
  15. package/dist/backend/services/message-service.js +8 -7
  16. package/dist/backend/services/project-service.js +2 -2
  17. package/dist/backend/services/round-service.js +29 -25
  18. package/dist/backend/services/session-service.js +141 -12
  19. package/dist/backend/templates/handoff.js +10 -0
  20. package/dist/backend/templates/harness/architect-agent.js +8 -4
  21. package/dist/backend/templates/harness/claude-root.js +1 -1
  22. package/dist/backend/templates/harness/coder-agent.js +1 -1
  23. package/dist/backend/templates/harness/codex-review.js +41 -6
  24. package/dist/backend/templates/harness/reviewer-agent.js +1 -0
  25. package/dist/shared/constants.js +15 -1
  26. package/dist/shared/types/app-settings.js +4 -3
  27. package/dist/shared/types/codex-hook.js +1 -0
  28. package/dist/shared/types/session.js +44 -0
  29. package/dist/shared/validation/artifact-check.js +1 -0
  30. package/dist-frontend/assets/index-BavJjWQY.js +92 -0
  31. package/dist-frontend/assets/index-CR1EOe-w.css +32 -0
  32. package/dist-frontend/index.html +2 -2
  33. package/docs/ARCHITECTURE.md +1 -0
  34. package/docs/TESTING.md +82 -0
  35. package/docs/cc-best-practices.md +1 -0
  36. package/docs/codex-review-gates.md +88 -45
  37. package/docs/full-harness-baseline.md +1 -1
  38. package/docs/gateway-design.md +5 -4
  39. package/docs/known-issues.md +1 -0
  40. package/docs/product-design.md +28 -11
  41. package/docs/vcm-cc-best-practices.md +15 -5
  42. package/package.json +1 -1
  43. package/dist-frontend/assets/index-C9l94uxA.js +0 -92
  44. package/dist-frontend/assets/index-D6jWo6Jd.css +0 -32
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Copyright (c) 2014 The xterm.js authors. All rights reserved.
3
+ * Copyright (c) 2012-2013, Christopher Jeffrey (MIT License)
4
+ * https://github.com/chjj/term.js
5
+ * @license MIT
6
+ *
7
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ * of this software and associated documentation files (the "Software"), to deal
9
+ * in the Software without restriction, including without limitation the rights
10
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ * copies of the Software, and to permit persons to whom the Software is
12
+ * furnished to do so, subject to the following conditions:
13
+ *
14
+ * The above copyright notice and this permission notice shall be included in
15
+ * all copies or substantial portions of the Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23
+ * THE SOFTWARE.
24
+ *
25
+ * Originally forked from (with the author's permission):
26
+ * Fabrice Bellard's javascript vt100 for jslinux:
27
+ * http://bellard.org/jslinux/
28
+ * Copyright (c) 2011 Fabrice Bellard
29
+ * The original design remains. The terminal itself
30
+ * has been extended to include xterm CSI codes, among
31
+ * other features.
32
+ */.xterm{cursor:text;position:relative;user-select:none;-ms-user-select:none;-webkit-user-select:none}.xterm.focus,.xterm:focus{outline:none}.xterm .xterm-helpers{position:absolute;top:0;z-index:5}.xterm .xterm-helper-textarea{padding:0;border:0;margin:0;position:absolute;opacity:0;left:-9999em;top:0;width:0;height:0;z-index:-5;white-space:nowrap;overflow:hidden;resize:none}.xterm .composition-view{background:#000;color:#fff;display:none;position:absolute;white-space:nowrap;z-index:1}.xterm .composition-view.active{display:block}.xterm .xterm-viewport{background-color:#000;overflow-y:scroll;cursor:default;position:absolute;right:0;left:0;top:0;bottom:0}.xterm .xterm-screen{position:relative}.xterm .xterm-screen canvas{position:absolute;left:0;top:0}.xterm .xterm-scroll-area{visibility:hidden}.xterm-char-measure-element{display:inline-block;visibility:hidden;position:absolute;top:0;left:-9999em;line-height:normal}.xterm.enable-mouse-events{cursor:default}.xterm.xterm-cursor-pointer,.xterm .xterm-cursor-pointer{cursor:pointer}.xterm.column-select.focus{cursor:crosshair}.xterm .xterm-accessibility:not(.debug),.xterm .xterm-message{position:absolute;left:0;top:0;bottom:0;right:0;z-index:10;color:transparent;pointer-events:none}.xterm .xterm-accessibility-tree:not(.debug) *::selection{color:transparent}.xterm .xterm-accessibility-tree{-webkit-user-select:text;user-select:text;white-space:pre}.xterm .live-region{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}.xterm-dim{opacity:1!important}.xterm-underline-1{text-decoration:underline}.xterm-underline-2{text-decoration:double underline}.xterm-underline-3{text-decoration:wavy underline}.xterm-underline-4{text-decoration:dotted underline}.xterm-underline-5{text-decoration:dashed underline}.xterm-overline{text-decoration:overline}.xterm-overline.xterm-underline-1{text-decoration:overline underline}.xterm-overline.xterm-underline-2{text-decoration:overline double underline}.xterm-overline.xterm-underline-3{text-decoration:overline wavy underline}.xterm-overline.xterm-underline-4{text-decoration:overline dotted underline}.xterm-overline.xterm-underline-5{text-decoration:overline dashed underline}.xterm-strikethrough{text-decoration:line-through}.xterm-screen .xterm-decoration-container .xterm-decoration{z-index:6;position:absolute}.xterm-screen .xterm-decoration-container .xterm-decoration.xterm-decoration-top-layer{z-index:7}.xterm-decoration-overview-ruler{z-index:8;position:absolute;top:0;right:0;pointer-events:none}.xterm-decoration-top{z-index:2;position:relative}:root{color-scheme:light;font-family:Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif;background:#f5f2ea;color:#1c2024;line-height:1.5}html,body,#root{height:100%}*{box-sizing:border-box}body{margin:0;min-width:320px;min-height:100vh;background:#f5f2ea}button,input,select,textarea{font:inherit}button{border:1px solid #9ba6ad;background:#f8f7f2;color:#1d252b;border-radius:6px;min-height:34px;padding:6px 10px;cursor:pointer}button:hover:not(:disabled){background:#eef4f2;border-color:#607d74}button:disabled{cursor:not-allowed;opacity:.55}.danger-button{border-color:#b84a45;background:#fff1ee;color:#8d211d;font-weight:750}.danger-button:hover:not(:disabled){border-color:#8d211d;background:#ffe2dc}input,select,textarea:not(.xterm-helper-textarea){width:100%;border:1px solid #b9b0a1;border-radius:6px;background:#fffdf8;color:#202326;padding:8px 10px}textarea:not(.xterm-helper-textarea){min-height:240px;resize:vertical;font-family:Menlo,Monaco,Consolas,monospace;font-size:12px}h1,h2,p{margin-top:0}h1{margin-bottom:4px;font-size:26px;line-height:1.15}h2{margin-bottom:10px;font-size:14px;letter-spacing:0}.app-shell{display:grid;grid-template-columns:minmax(280px,320px) minmax(0,1fr);height:100vh;min-height:0;overflow:hidden}.app-shell.is-sidebar-collapsed{grid-template-columns:46px minmax(0,1fr)}.app-sidebar{position:relative;display:flex;flex-direction:column;min-width:0;border-right:1px solid #d3c9b8;background:#fbfaf6;padding:14px;overflow:auto}.app-shell.is-sidebar-collapsed .app-sidebar{overflow:hidden;padding:8px}.sidebar-toggle{position:absolute;top:10px;right:10px;z-index:2;display:grid;place-items:center;width:28px;min-height:28px;padding:0;background:#fffdf8}.sidebar-toggle:before{width:8px;height:8px;border-color:currentColor;border-style:solid;border-width:0 2px 2px 0;content:"";transform:translate(2px) rotate(135deg)}.app-shell.is-sidebar-collapsed .sidebar-toggle{left:9px;right:auto}.app-shell.is-sidebar-collapsed .sidebar-toggle:before{transform:translate(-2px) rotate(-45deg)}.sidebar-content{display:flex;flex:1;min-width:0;min-height:0}.project-dashboard{display:flex;flex:1;flex-direction:column;width:100%;min-height:100%}.app-shell.is-sidebar-collapsed .sidebar-content{width:0;opacity:0;pointer-events:none}.app-main{min-width:0;height:100%;padding:14px 16px;overflow:auto}.brand-header{display:flex;gap:12px;align-items:baseline;margin-bottom:10px;padding-right:34px}.brand-header strong{font-size:18px}.brand-header span,.muted{color:#667071;font-size:13px}.sidebar-section{margin-bottom:8px;border:1px solid #e0d6c7;border-radius:8px;background:#fffdfa;overflow:hidden}.sidebar-section-toggle{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:8px;align-items:center;width:100%;min-height:34px;border:0;border-radius:0;background:transparent;color:#1c2024;font-size:13px;font-weight:750;text-align:left}.sidebar-section-toggle:hover{background:#f5f1e8}.sidebar-section-toggle[aria-expanded=true]{border-bottom:1px solid #ece5d9}.sidebar-section-chevron{width:8px;height:8px;border-color:currentColor;border-style:solid;border-width:0 2px 2px 0;transform:rotate(45deg)}.sidebar-section-toggle[aria-expanded=true] .sidebar-section-chevron{transform:rotate(-135deg)}.sidebar-section-content{padding:8px}.repo-connect,.project-summary,.gateway-panel,.harness-panel,.task-create{margin:0}.inline-form{display:grid;grid-template-columns:minmax(0,1fr);gap:8px}.inline-form.has-recent-paths{grid-template-columns:minmax(0,1fr) auto}.inline-form>input{grid-column:1 / -1}.inline-form>button{justify-self:end}.inline-form.has-recent-paths>button{justify-self:auto}.repo-recent-select{min-width:0;max-width:none}.project-summary dl{display:grid;gap:8px;margin:0}.project-summary div{min-width:0}.project-summary dt{color:#6c6255;font-size:12px}.project-summary dd{margin:0;overflow-wrap:anywhere;font-size:13px}.connected-repo-actions{display:flex;align-items:center;gap:8px;margin-top:10px}.connected-repo-actions button{min-height:30px}.gateway-actions{display:grid;gap:8px;margin-top:10px}.gateway-actions button{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:8px;align-items:center;width:100%;text-align:left}.gateway-actions .settings-toggle.is-active{border-color:#2f6f73;background:#e8f1ef}.gateway-qr{display:grid;gap:6px;margin-top:10px}.gateway-qr img{width:100%;max-width:180px;border:1px solid #d3c9b8;border-radius:6px;background:#fff;padding:6px}.gateway-qr code{overflow-wrap:anywhere;font-size:11px}.warnings,.error-banner{border:1px solid #c87b54;background:#fff4ed;color:#6f3218;border-radius:6px;padding:10px 12px}.flow-pause-alert-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:100;display:grid;place-items:center;background:#1f242b85;padding:20px}.flow-pause-alert{display:grid;gap:12px;width:min(460px,100%);border:1px solid #2f6f73;border-radius:8px;background:#e8f4f2;color:#123f43;box-shadow:0 28px 72px #1f242b47;padding:22px}.flow-pause-alert-kicker{margin:0;color:#2f6f73;font-size:12px;font-weight:700;text-transform:uppercase}.flow-pause-alert h2{margin:0;font-size:24px;line-height:1.15}.flow-pause-alert p{margin:0;font-size:14px;line-height:1.5}.flow-pause-alert-hint{color:#49666a}.flow-pause-alert button{justify-self:end;min-width:110px;border:1px solid #2f6f73;background:#2f6f73;color:#fffdf8}.flow-pause-alert button:hover{background:#245c60}.warnings{margin:12px 0 0;padding-left:26px;font-size:13px}.harness-panel{display:grid;gap:10px}.harness-stage{display:grid;gap:8px}.harness-panel-header{display:flex;justify-content:space-between;gap:8px;align-items:center}.harness-panel-header h2,.harness-panel-header p,.harness-result p{margin-bottom:0}.harness-actions{display:flex;flex-wrap:wrap;gap:6px;justify-content:flex-end}.harness-file-list-title{margin:0;font-size:12px}.harness-file-list{display:grid;gap:6px;margin:0;padding:0;list-style:none}.harness-file-list li{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:8px;align-items:center;border:1px solid #ece5d9;border-radius:6px;padding:6px 8px;background:#fffdfa}.harness-file-list span{overflow:hidden;font-size:12px;font-weight:650;text-overflow:ellipsis;white-space:nowrap}.harness-changes,.harness-result{border:1px solid #e0d6c7;border-radius:6px;padding:8px;background:#f8f7f2;font-size:12px}.harness-changes h3{margin:0 0 4px;font-size:12px}.harness-changes ul,.harness-result ul{margin:0;padding-left:18px}.harness-bootstrap-session{display:grid;gap:8px;border:1px solid #e0d6c7;border-radius:6px;padding:8px;background:#f8f7f2;font-size:12px}.harness-bootstrap-session>div:first-child{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:8px;align-items:center}.harness-bootstrap-session span:first-child{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.harness-bootstrap-modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:80;display:grid;grid-template-columns:minmax(0,1fr);grid-template-rows:minmax(0,1fr);background:#1f242b94;padding:14px}.harness-bootstrap-modal-surface{min-width:0;min-height:0;display:grid;grid-template-rows:auto minmax(0,1fr);gap:10px;border:1px solid #b9b0a1;border-radius:8px;background:#fffdf8;box-shadow:0 22px 64px #1f242b47;padding:10px}.harness-bootstrap-modal-header{display:flex;gap:12px;align-items:center;justify-content:space-between;min-width:0}.harness-bootstrap-modal-header p{max-width:min(720px,70vw);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.harness-bootstrap-modal-actions{display:flex;flex-wrap:wrap;gap:8px;align-items:center;justify-content:flex-end}.harness-bootstrap-terminal{min-width:0;min-height:0;display:grid}.task-create form{display:grid;gap:8px}.task-create-preview{display:grid;gap:2px;border:1px solid #e0d6c7;border-radius:6px;background:#f8f7f2;padding:6px 8px}.task-create-option{display:flex;align-items:center;gap:8px;color:#1f242b;font-size:13px;font-weight:700}.task-create-option input{width:16px;height:16px;margin:0}.task-create-preview span{color:#255f3d;font-size:12px;font-weight:700}.task-create-preview small{overflow:hidden;color:#687273;font-size:11px;text-overflow:ellipsis;white-space:nowrap}.task-nav{display:grid;gap:8px}.task-nav-item{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:8px;align-items:center;text-align:left}.task-nav-item.is-active,.role-tab.is-active{border-color:#2f6f73;background:#e8f1ef}.sidebar-settings{display:grid;gap:8px}.sidebar-settings button{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:8px;align-items:center;width:100%;text-align:left}.sidebar-settings .settings-toggle.is-active{border-color:#2f6f73;background:#e8f1ef}.sidebar-settings .theme-mode-toggle span:last-child{font-weight:750}.settings-select-row{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:8px;align-items:center;width:100%;font-size:13px;color:#5f6a6c}.settings-select-row select{min-height:30px;border:1px solid #b9b0a1;border-radius:6px;background:#fffdf8;color:#202326}.task-status-dock{display:grid;gap:10px;margin-top:auto;border-top:1px solid #d3c9b8;padding-top:10px}.task-status-dock-title,.current-round-title{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:8px;align-items:center}.task-status-dock-title strong{overflow:hidden;font-size:13px;line-height:1.25;text-overflow:ellipsis;white-space:nowrap}.task-status-stats{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:6px;margin:0}.task-status-stats div,.current-round-status{min-width:0;border:1px solid #e0d6c7;border-radius:6px;background:#fffdfa}.task-status-stats div{padding:6px 7px}.task-status-stats dt{color:#6c6255;font-size:10px;font-weight:700;text-transform:uppercase}.task-status-stats dd{margin:0;overflow:hidden;color:#1f242b;font-size:12px;font-weight:750;text-overflow:ellipsis;white-space:nowrap}.current-round-status{display:grid;gap:8px;padding:8px}.current-round-title span:first-child{color:#3a4647;font-size:12px;font-weight:750}.workspace-header{display:grid;grid-template-columns:minmax(120px,max-content) minmax(420px,1fr) auto;gap:10px;align-items:center;margin-bottom:6px}.workspace-title-line{display:flex;min-width:0}.workspace-title-line h1{margin-bottom:0;font-size:18px;line-height:1.15}.workspace-header-actions{display:flex;gap:8px;align-items:center;justify-content:flex-end;min-width:max-content}.role-tabs{display:grid;grid-template-columns:repeat(auto-fit,minmax(120px,1fr));gap:6px;margin-bottom:8px;min-width:0}.workspace-header .role-tabs{margin-bottom:0}.role-tab{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:6px;align-items:center;min-height:30px;padding:4px 8px;text-align:left}.workspace-grid{display:grid;grid-template-columns:minmax(0,1fr);flex:1;gap:10px;align-items:stretch;min-height:0}.workspace-main{min-width:0;min-height:0;display:flex;flex-direction:column;gap:8px}.role-console-stack{min-width:0;min-height:0;flex:1;display:flex;flex-direction:column}.role-console-panel{min-width:0;min-height:0;flex:1;display:none}.role-console-panel.is-active{display:flex;flex-direction:column}.session-console,.message-panel,.event-log,.empty-workspace{border:1px solid #d6d0c6;border-radius:8px;background:#fffdf8;padding:10px}.task-workspace{display:flex;flex-direction:column;gap:8px;height:100%;min-height:0}.session-console{display:grid;grid-template-rows:auto minmax(0,1fr);gap:8px;flex:1;height:100%;min-height:0}.session-console-top{display:flex;gap:10px;align-items:center;justify-content:space-between}.session-console-actions{display:flex;flex-wrap:wrap;gap:8px;align-items:center;justify-content:flex-end}.session-controls{display:flex;flex-wrap:wrap;gap:8px;align-items:center;justify-content:flex-start;margin:0 0 8px}.session-option-field{display:grid;grid-template-columns:auto minmax(180px,260px);gap:8px;align-items:center;width:fit-content;max-width:100%}.model-field{grid-template-columns:auto minmax(190px,260px)}.effort-field{grid-template-columns:auto minmax(120px,160px)}.session-option-field span{color:#5f6a6c;font-size:13px;font-weight:650}.session-option-field small{display:block;color:#7b8587;font-size:11px;font-weight:500;line-height:1.2}.session-option-field select{width:100%;min-height:30px;border:1px solid #b9b0a1;border-radius:6px;background:#fffdf8;color:#202326;padding:4px 8px}.session-toolbar{display:flex;flex-wrap:wrap;gap:6px;margin-left:auto;justify-content:flex-end}.session-toolbar button{min-height:30px;padding:4px 9px}.translation-toggle{display:inline-flex;align-items:center;justify-content:center;min-height:28px;border:1px solid #b5bec4;border-radius:6px;background:#fffefa;color:#4f5558;font-size:12px;font-weight:650;padding:3px 10px;white-space:nowrap}.translation-toggle.is-active{border-color:#2f7e84;background:#e8f4f2;color:#145e64}.translation-settings-grid input[type=checkbox]{width:auto}.session-console-body{display:grid;grid-template-columns:minmax(0,1fr);min-width:0;min-height:0;height:100%}.session-console-body.has-translation{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:10px;align-items:stretch}.terminal-pane,.translation-pane{display:grid;min-width:0;min-height:0;height:100%}.terminal-frame,.terminal-empty{width:100%;height:100%;min-height:0;border-radius:6px;overflow:hidden;background:#111316}.terminal-empty{display:grid;place-items:center;align-content:center;gap:8px;color:#d6d0c6;border:1px solid #292d31}.translation-panel{display:grid;grid-template-rows:auto minmax(0,1fr) auto;gap:8px;height:100%;min-height:0;border:1px solid #292d31;border-radius:6px;background:#0d1117;color:#d6deeb;padding:8px;min-width:0;width:100%;overflow:hidden;font-family:Menlo,Monaco,Consolas,monospace}.translation-panel-header{display:grid;gap:3px}.translation-panel-titlebar,.translation-panel-actions,.translation-status-row{display:flex;flex-wrap:wrap;gap:6px;align-items:center;justify-content:space-between}.translation-panel-header h2,.translation-panel-header p{margin-bottom:0}.translation-panel-titlebar h2{font-size:16px}.translation-panel-header p,.translation-composer span{color:#8b949e;font-size:12px}.translation-panel-actions button{border-color:#3a4149;background:#161b22;color:#d6deeb;min-height:26px;padding:2px 8px;font-size:12px}.translation-panel-actions button:hover:not(:disabled),.translation-composer-actions button:hover:not(:disabled){border-color:#58a6ff;background:#1f2937}.translation-panel-actions .auto-send-toggle.is-active{border-color:#56d364;background:#12261a;color:#d6deeb}.translation-panel-actions{justify-content:flex-end}.translation-status-row{flex-wrap:nowrap}.translation-status-row p:last-child{flex:0 0 auto;text-align:right}.translation-entry-list{display:grid;align-content:start;gap:8px;min-height:0;min-width:0;overflow-x:hidden;overflow-y:auto;scrollbar-color:#4b5563 #0d1117}.translation-entry{border:0;border-radius:0;background:transparent;min-width:0;max-width:100%;padding:0}.translation-conversation-boundary{display:grid;grid-template-columns:minmax(18px,1fr) auto auto auto minmax(18px,1fr);gap:8px;align-items:center;color:#8b949e;font-family:Menlo,Monaco,Consolas,monospace;font-size:12px;line-height:1.4;white-space:nowrap}.translation-boundary-dash{min-width:0;border-top:1px dashed #3a4149}.translation-entry.is-user-input{border-top:4px solid #3a4149;margin-top:14px;padding-top:14px}.translation-entry.is-user-input:first-child{margin-top:0}.translation-entry pre{box-sizing:border-box;margin:0;max-height:none;max-width:100%;min-width:0;overflow:visible;white-space:pre-wrap;overflow-wrap:anywhere;font-family:Menlo,Monaco,Consolas,monospace;font-size:12px;line-height:1.45;color:#d6deeb}.translation-markdown{max-width:100%;min-width:0;color:#d6deeb;font-size:12px;line-height:1.55;overflow-wrap:anywhere}.translation-markdown>:first-child{margin-top:0}.translation-markdown>:last-child{margin-bottom:0}.translation-markdown p,.translation-markdown ul,.translation-markdown ol,.translation-markdown blockquote,.translation-markdown pre,.translation-markdown table{margin:0 0 8px}.translation-markdown h1,.translation-markdown h2,.translation-markdown h3,.translation-markdown h4,.translation-markdown h5,.translation-markdown h6{margin:10px 0 6px;color:#f0f6fc;font-weight:700;line-height:1.25}.translation-markdown h1{font-size:17px}.translation-markdown h2{font-size:15px}.translation-markdown h3,.translation-markdown h4,.translation-markdown h5,.translation-markdown h6{font-size:13px}.translation-markdown ul,.translation-markdown ol{padding-left:22px}.translation-markdown li{margin:2px 0}.translation-markdown .task-list-item{list-style:none}.translation-markdown input[type=checkbox]{width:13px;height:13px;margin:0 6px 0 0;accent-color:#56d364}.translation-markdown blockquote{border-left:3px solid #3a4149;color:#b7c0ca;padding-left:10px}.translation-markdown a{color:#79c0ff}.translation-markdown code{border-radius:4px;background:#161b22;color:#f0f6fc;padding:1px 4px;font-family:Menlo,Monaco,Consolas,monospace;font-size:.95em}.translation-markdown pre{overflow-x:auto;border:1px solid #292d31;border-radius:6px;background:#111316;padding:8px;white-space:pre}.translation-markdown pre code{background:transparent;padding:0}.translation-markdown table{display:block;max-width:100%;overflow-x:auto;border-collapse:collapse}.translation-markdown img{max-width:100%;border-radius:4px}.translation-markdown th,.translation-markdown td{border:1px solid #30363d;padding:4px 6px;text-align:left;vertical-align:top}.translation-markdown hr{border:0;border-top:1px solid #292d31;margin:10px 0}.translation-entry.is-tool-output pre{display:block;overflow:hidden;color:#7d8590;text-overflow:ellipsis;white-space:nowrap;width:100%}.translation-entry-note{margin:2px 0 0;color:#6e7681;font-size:10px;line-height:1.35}.translation-entry-note.is-error{color:#a3715f}.translation-composer{display:grid;gap:6px;border-top:1px solid #292d31;padding-top:8px}.translation-composer-row{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:8px;align-items:stretch}.translation-composer textarea{width:100%;min-height:38px;max-height:88px;border-color:#3a4149;background:#0d1117;color:#d6deeb;font-family:inherit;font-size:12px;line-height:1.35;resize:vertical}.translation-composer textarea::placeholder{color:#7d8590}.translation-composer textarea::selection{background:#8b949e59;color:#fff}.translation-composer textarea:focus,.translation-composer textarea:focus-visible{border-color:#4b5563;outline:none;box-shadow:none}.translation-composer-actions{display:grid;align-content:start;gap:6px;min-width:104px}.translation-composer-actions button{border-color:#3a4149;background:#161b22;color:#d6deeb;width:100%;min-height:38px;padding:4px 9px;font-size:12px}.translation-panel .muted{color:#8b949e}.translation-panel .error-banner{border-color:#da7b72;background:#2d1518;color:#ffdcd7}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:20;display:grid;place-items:center;background:#181c1f61;padding:18px}.translation-settings-modal{display:grid;gap:12px;width:min(980px,100%);max-height:min(760px,92vh);overflow:auto;border:1px solid #d6d0c6;border-radius:8px;background:#fffdf8;padding:14px}.gateway-qr-modal{display:grid;grid-template-rows:auto minmax(0,1fr) auto;gap:14px;width:min(520px,100%);max-height:min(720px,92vh);overflow:auto;border:1px solid #d6d0c6;border-radius:8px;background:#fffdf8;padding:16px}.message-modal,.event-modal{display:grid;grid-template-rows:auto minmax(0,1fr);gap:12px;width:min(980px,100%);max-height:min(760px,92vh);overflow:hidden;border:1px solid #d6d0c6;border-radius:8px;background:#fffdf8;padding:14px}.translation-settings-modal header,.gateway-qr-modal header,.message-modal header,.event-modal header,.translation-settings-modal footer,.gateway-qr-modal footer{display:flex;gap:8px;align-items:center;justify-content:space-between}.gateway-qr-modal h2,.gateway-qr-modal p{margin-bottom:0}.gateway-qr-modal-body{display:grid;gap:14px;justify-items:center}.gateway-qr-code-frame{display:grid;place-items:center;width:min(360px,100%);aspect-ratio:1;border:1px solid #d6d0c6;border-radius:8px;background:#fff;padding:18px}.gateway-qr-code-frame img{display:block;width:100%;height:auto}.gateway-qr-placeholder{color:#667071;text-align:center}.gateway-qr-meta{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px;width:100%;margin:0}.gateway-qr-meta div{min-width:0;border:1px solid #ece5d9;border-radius:6px;padding:8px}.gateway-qr-meta dt{color:#6c6255;font-size:11px;font-weight:700;text-transform:uppercase}.gateway-qr-meta dd{margin:0;overflow-wrap:anywhere;font-size:13px}.translation-prompt-settings{display:grid;gap:10px;border-top:1px solid #ece5d9;padding-top:12px}.translation-prompt-settings header{display:flex;gap:10px;align-items:end;justify-content:space-between}.translation-prompt-settings h3,.translation-prompt-settings p{margin-bottom:0}.translation-prompt-settings h3{font-size:13px}.translation-prompt-settings textarea{min-height:120px;max-height:260px;font-family:Menlo,Monaco,Consolas,monospace;font-size:12px}.translation-prompt-stack{display:grid;gap:10px}.translation-prompt-stack label{display:grid;gap:4px}.translation-prompt-stack span{color:#4f5558;font-size:12px;font-weight:650}.translation-settings-modal h2,.message-modal h2,.message-modal p,.event-modal h2,.event-modal p,.translation-settings-modal p{margin-bottom:0}.translation-settings-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px}.translation-settings-grid label{display:grid;gap:4px}.translation-settings-grid span{color:#4f5558;font-size:12px;font-weight:650}.translation-settings-grid select,.translation-prompt-settings select{min-height:34px;border:1px solid #b9b0a1;border-radius:6px;background:#fffdf8;color:#202326;padding:6px 10px}.translation-test-result{border-radius:6px;padding:8px;font-size:13px}.translation-test-result.is-ok{border:1px solid #6ea77e;background:#e6f3e9;color:#245334}.translation-test-result.is-error{border:1px solid #c46e5f;background:#fae9e6;color:#6f2b21}.message-panel{display:grid;gap:8px}.message-modal .message-panel,.event-modal .event-log{min-height:0;overflow:auto;border:0;background:transparent;padding:0}.message-panel-header{display:flex;justify-content:space-between;gap:12px;align-items:center}.message-panel-header h2,.message-panel-header p{margin-bottom:0}.message-controls,.message-mode-toggle,.modal-actions,.message-actions{display:flex;flex-wrap:wrap;gap:8px;align-items:center}.message-mode-toggle{color:#4f5558;font-size:13px;font-weight:650}.message-mode-toggle input{width:auto}.message-list{display:grid;gap:8px;margin:0;padding:0;list-style:none}.message-item{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:10px;align-items:start;border:1px solid #ece5d9;border-radius:6px;padding:8px;background:#fffdfa}.message-meta{display:flex;flex-wrap:wrap;gap:8px;align-items:center;margin-bottom:4px}.message-meta time,.message-meta span:not(.status-badge),.message-reason,.message-path{color:#667071;font-size:12px}.message-sequence{min-width:32px;color:#1f242b;font-weight:800}.message-actions button{min-height:30px;padding:4px 10px}.message-item p{display:-webkit-box;margin-bottom:4px;overflow:hidden;-webkit-box-orient:vertical;-webkit-line-clamp:2}.message-reason,.message-path{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.event-log ol{margin:0;padding-left:22px;font-size:13px}.event-log{max-height:92px;overflow:auto}.event-log h2{margin-bottom:4px;font-size:13px}.event-log p{margin-bottom:0}.event-log li{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.status-badge{display:inline-flex;align-items:center;justify-content:center;min-width:66px;min-height:20px;border-radius:999px;padding:2px 8px;border:1px solid #c7c1b8;background:#f2eee7;color:#4f5558;font-size:11px;white-space:nowrap}.status-active,.status-running,.status-ok{border-color:#6ea77e;background:#e6f3e9;color:#245334}.status-created,.status-idle,.status-disabled{border-color:#9aa3a8;background:#edf0f1;color:#465056}.status-blocked,.status-crashed,.status-missing,.status-empty{border-color:#c46e5f;background:#fae9e6;color:#6f2b21}.status-waiting,.status-starting,.status-incomplete{border-color:#c4a34e;background:#f7efcf;color:#604e16}.status-exited,.status-done,.status-stopped,.status-resumable,.status-skipped,.status-overridden,.status-not_required{border-color:#7b98b8;background:#e9f0f8;color:#2e4e70}.status-queued,.status-translating,.status-ready,.status-create,.status-insert,.status-update{border-color:#c4a34e;background:#f7efcf;color:#604e16}.status-rejected,.status-failed,.status-delivery_failed,.status-response_ready_missing_result,.status-cancelled,.status-blocked{border-color:#c46e5f;background:#fae9e6;color:#6f2b21}.status-pending{border-color:#c7c1b8;background:#f2eee7;color:#4f5558}.status-translated,.status-preserved{border-color:#7b98b8;background:#e9f0f8;color:#2e4e70}.empty-workspace{max-width:680px}@media(max-width:980px){.app-shell,.workspace-grid{grid-template-columns:1fr}.app-sidebar{border-right:0;border-bottom:1px solid #d3c9b8}.role-tabs{grid-template-columns:repeat(2,minmax(0,1fr))}.session-console-body.has-translation,.translation-settings-grid{grid-template-columns:1fr}}@media(max-width:560px){.app-main,.app-sidebar{padding:12px}.workspace-header,.inline-form,.inline-form.has-recent-paths{grid-template-columns:1fr;display:grid}.role-tabs{grid-template-columns:1fr}.terminal-frame,.terminal-empty{min-height:300px;height:54vh}.session-option-field{grid-template-columns:1fr;width:100%}}.harness-bootstrap-terminal .terminal-frame{height:100%;min-height:0}:root[data-theme=dark]{color-scheme:dark;background:#0d1117;color:#e6edf3}:root[data-theme=dark] body,:root[data-theme=dark] .app-main{background:#0d1117;color:#e6edf3}:root[data-theme=dark] button{border-color:#3d4652;background:#161b22;color:#e6edf3}:root[data-theme=dark] button:hover:not(:disabled){border-color:#58a6ff;background:#1f2937}:root[data-theme=dark] input,:root[data-theme=dark] select,:root[data-theme=dark] textarea:not(.xterm-helper-textarea){border-color:#3d4652;background:#0d1117;color:#e6edf3}:root[data-theme=dark] input::placeholder,:root[data-theme=dark] textarea::placeholder{color:#7d8590}:root[data-theme=dark] .danger-button{border-color:#da7b72;background:#2d1518;color:#ffdcd7}:root[data-theme=dark] .danger-button:hover:not(:disabled){border-color:#ffa198;background:#3d1f23}:root[data-theme=dark] .app-sidebar{border-color:#30363d;background:#0f141b}:root[data-theme=dark] .sidebar-toggle{background:#161b22}:root[data-theme=dark] .brand-header span,:root[data-theme=dark] .muted,:root[data-theme=dark] .message-meta time,:root[data-theme=dark] .message-meta span:not(.status-badge),:root[data-theme=dark] .message-reason,:root[data-theme=dark] .message-path{color:#8b949e}:root[data-theme=dark] .sidebar-section,:root[data-theme=dark] .session-console,:root[data-theme=dark] .message-panel,:root[data-theme=dark] .event-log,:root[data-theme=dark] .empty-workspace,:root[data-theme=dark] .translation-settings-modal,:root[data-theme=dark] .gateway-qr-modal,:root[data-theme=dark] .message-modal,:root[data-theme=dark] .event-modal{border-color:#30363d;background:#11161d}:root[data-theme=dark] .gateway-qr-code-frame,:root[data-theme=dark] .gateway-qr-meta div{border-color:#30363d;background:#0d1117}:root[data-theme=dark] .gateway-qr-code-frame{background:#f6f8fa}:root[data-theme=dark] .gateway-qr-meta dt,:root[data-theme=dark] .gateway-qr-placeholder{color:#8b949e}:root[data-theme=dark] .sidebar-section-toggle{color:#e6edf3}:root[data-theme=dark] .sidebar-section-toggle:hover{background:#161b22}:root[data-theme=dark] .sidebar-section-toggle[aria-expanded=true],:root[data-theme=dark] .translation-prompt-settings{border-color:#30363d}:root[data-theme=dark] .project-summary dt,:root[data-theme=dark] .session-option-field span,:root[data-theme=dark] .translation-settings-grid span,:root[data-theme=dark] .translation-prompt-stack span,:root[data-theme=dark] .message-mode-toggle{color:#b7c0ca}:root[data-theme=dark] .session-option-field small,:root[data-theme=dark] .task-create-preview small{color:#8b949e}:root[data-theme=dark] .warnings,:root[data-theme=dark] .error-banner{border-color:#da7b72;background:#2d1518;color:#ffdcd7}:root[data-theme=dark] .flow-pause-alert-backdrop{background:#010409b8}:root[data-theme=dark] .flow-pause-alert{border-color:#56d4dd;background:#10262b;color:#d6fbff;box-shadow:0 28px 72px #0104099e}:root[data-theme=dark] .flow-pause-alert-kicker,:root[data-theme=dark] .flow-pause-alert-hint{color:#9debf2}:root[data-theme=dark] .flow-pause-alert button{border-color:#56d4dd;background:#56d4dd;color:#061114}:root[data-theme=dark] .flow-pause-alert button:hover{background:#84f3fa}:root[data-theme=dark] .harness-file-list li,:root[data-theme=dark] .harness-changes,:root[data-theme=dark] .harness-result,:root[data-theme=dark] .harness-bootstrap-session,:root[data-theme=dark] .gateway-qr img,:root[data-theme=dark] .task-create-preview,:root[data-theme=dark] .task-status-stats div,:root[data-theme=dark] .current-round-status,:root[data-theme=dark] .message-item{border-color:#30363d;background:#0d1117}:root[data-theme=dark] .harness-bootstrap-modal{background:#010409b8}:root[data-theme=dark] .harness-bootstrap-modal-surface{border-color:#30363d;background:#0d1117;box-shadow:0 22px 64px #0104099e}:root[data-theme=dark] .task-create-option{color:#e6edf3}:root[data-theme=dark] .task-status-dock{border-color:#30363d}:root[data-theme=dark] .task-create-preview span{color:#7ee787}:root[data-theme=dark] .task-status-stats dt{color:#8b949e}:root[data-theme=dark] .task-status-stats dd,:root[data-theme=dark] .current-round-title span:first-child{color:#e6edf3}:root[data-theme=dark] .message-sequence{color:#f0f6fc}:root[data-theme=dark] .task-nav-item.is-active,:root[data-theme=dark] .role-tab.is-active,:root[data-theme=dark] .sidebar-settings .settings-toggle.is-active,:root[data-theme=dark] .gateway-actions .settings-toggle.is-active,:root[data-theme=dark] .translation-toggle.is-active{border-color:#56d4dd;background:#10262b;color:#d6fbff}:root[data-theme=dark] .translation-toggle{border-color:#3d4652;background:#161b22;color:#b7c0ca}:root[data-theme=dark] .session-option-field select,:root[data-theme=dark] .settings-select-row select,:root[data-theme=dark] .translation-settings-grid select,:root[data-theme=dark] .translation-prompt-settings select{border-color:#3d4652;background:#0d1117;color:#e6edf3}:root[data-theme=dark] .settings-select-row{color:#b7c0ca}:root[data-theme=dark] .terminal-empty{border-color:#30363d}:root[data-theme=dark] .modal-backdrop{background:#010409b8}:root[data-theme=dark] .message-modal .message-panel,:root[data-theme=dark] .event-modal .event-log{background:transparent}:root[data-theme=dark] .status-badge{border-color:#3d4652;background:#161b22;color:#d6deeb}:root[data-theme=dark] .translation-test-result.is-ok,:root[data-theme=dark] .status-active,:root[data-theme=dark] .status-running,:root[data-theme=dark] .status-ok{border-color:#3fb950;background:#12261a;color:#aff5b4}:root[data-theme=dark] .status-created,:root[data-theme=dark] .status-idle,:root[data-theme=dark] .status-disabled{border-color:#69717d;background:#20262f;color:#d6deeb}:root[data-theme=dark] .translation-test-result.is-error,:root[data-theme=dark] .status-blocked,:root[data-theme=dark] .status-crashed,:root[data-theme=dark] .status-missing,:root[data-theme=dark] .status-empty,:root[data-theme=dark] .status-rejected,:root[data-theme=dark] .status-failed,:root[data-theme=dark] .status-delivery_failed,:root[data-theme=dark] .status-response_ready_missing_result,:root[data-theme=dark] .status-cancelled{border-color:#f85149;background:#2d1518;color:#ffdcd7}:root[data-theme=dark] .status-waiting,:root[data-theme=dark] .status-starting,:root[data-theme=dark] .status-incomplete,:root[data-theme=dark] .status-queued,:root[data-theme=dark] .status-translating,:root[data-theme=dark] .status-ready,:root[data-theme=dark] .status-create,:root[data-theme=dark] .status-insert,:root[data-theme=dark] .status-update{border-color:#d29922;background:#2d2208;color:#f8e3a1}:root[data-theme=dark] .status-exited,:root[data-theme=dark] .status-done,:root[data-theme=dark] .status-stopped,:root[data-theme=dark] .status-resumable,:root[data-theme=dark] .status-skipped,:root[data-theme=dark] .status-overridden,:root[data-theme=dark] .status-not_required,:root[data-theme=dark] .status-translated,:root[data-theme=dark] .status-preserved{border-color:#388bfd;background:#10223a;color:#c9e2ff}:root[data-theme=dark] .status-pending{border-color:#3d4652;background:#161b22;color:#d6deeb}
@@ -4,8 +4,8 @@
4
4
  <meta charset="UTF-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
6
  <title>VibeCodingMaster</title>
7
- <script type="module" crossorigin src="/assets/index-C9l94uxA.js"></script>
8
- <link rel="stylesheet" crossorigin href="/assets/index-D6jWo6Jd.css">
7
+ <script type="module" crossorigin src="/assets/index-BavJjWQY.js"></script>
8
+ <link rel="stylesheet" crossorigin href="/assets/index-CR1EOe-w.css">
9
9
  </head>
10
10
  <body>
11
11
  <div id="root"></div>
@@ -0,0 +1 @@
1
+ # Architecture
@@ -0,0 +1,82 @@
1
+ # Testing
2
+
3
+ Validation strategy for `vibe-coding-master` (TypeScript/Node app). Reviewer-owned.
4
+
5
+ ## Validation Levels & Commands
6
+
7
+ | Level | Scope | Command |
8
+ | --- | --- | --- |
9
+ | L0 | format / typecheck | `npm run typecheck` (`tsc -p tsconfig.json --noEmit && tsc -p tsconfig.node.json --noEmit`) |
10
+ | L1/L2 | unit + module/integration tests | `npm run test` (vitest, runs `tests/unit/**` and `tests/integration/**`) |
11
+ | L3 | smoke / E2E (browser) | `npm run e2e` (Playwright) |
12
+ | L4 | full regression / release | `npm run prepack` (build + `verify:package`) + full `npm run test` + `npm run e2e` |
13
+
14
+ Targeted run: `npx vitest run <path/to/test.ts>`.
15
+
16
+ ### Test environment note
17
+
18
+ `vitest.config.ts` runs in `environment: "node"` (no jsdom). Frontend tests are
19
+ therefore either pure-helper tests or component tests rendered with
20
+ `react-dom/server` `renderToStaticMarkup` (static HTML assertions), not DOM/event
21
+ tests. Component modules that load browser globals at import time (e.g. the
22
+ xterm-backed `terminal/xterm-view`) must be stubbed with `vi.mock` before the
23
+ component under test is imported.
24
+
25
+ ## Required prerequisite: build before full `npm run test`
26
+
27
+ `tests/unit/backend/harness-templates-sync.test.ts` spawns the real harness
28
+ installer (`scripts/install-vcm-harness.mjs`), which runs the compiled CLI at
29
+ `dist/backend/cli/install-vcm-harness.js`, falling back to the TypeScript source
30
+ only when the `tsx` binary is present. In a clean checkout with no `dist/` and no
31
+ `node_modules/.bin/tsx`, the installer exits with
32
+ `compiled CLI not found. Run npm run build first.` and this single test fails.
33
+
34
+ **Run `npm run build` before a full `npm run test`** (or before final acceptance).
35
+ All other unit tests run without a build. This is a documented prerequisite, not a
36
+ product defect or known issue.
37
+
38
+ ## Final-validation cleanup
39
+
40
+ `npm run build` first runs `npm run clean` (`scripts/clean-build.mjs`), removing
41
+ `dist/` and `dist-frontend/`. Final acceptance therefore runs from a clean state via:
42
+
43
+ ```
44
+ npm run build && npm run test
45
+ ```
46
+
47
+ Do not treat any pre-cleanup test result as final acceptance evidence.
48
+
49
+ ## Harness "Fixed install" three-state UI cases
50
+
51
+ Backend derivation — `tests/unit/backend/harness-service.test.ts`:
52
+
53
+ | ID | Scenario | Proves |
54
+ | --- | --- | --- |
55
+ | B1 | fresh repo, all harness files missing | `initialized === false`, `needsApply === true` |
56
+ | B2 | after `applyHarness` | `initialized === true`, `needsApply === false` |
57
+ | B3 | pre-existing non-VCM `CLAUDE.md` (action `insert`) | `initialized === false` |
58
+ | B4 | pre-existing `.claude/settings.json` without VCM hooks (action `update`) | `initialized === false` |
59
+ | B5 | drifted managed block (version 0) | `initialized === true`, `needsApply === true` |
60
+
61
+ Frontend render — `tests/unit/frontend/harness-panel.test.ts`
62
+ (entry: `HarnessPanel`, rendered via `renderToStaticMarkup`, `xterm-view` mocked):
63
+
64
+ | ID | State | Entry / input | Key assertions |
65
+ | --- | --- | --- | --- |
66
+ | F1 | A — not initialized | `initialized:false, needsApply:true` | subtitle "Not initialized"; only `Initialize` button; no Refresh/Update; no "Files to update" list |
67
+ | F2 | B — has updates | `initialized:true, needsApply:true, plannedChanges:[..]` | subtitle "N pending updates"; "Files to update" list with paths; `Update` + `Refresh`; no `Initialize` |
68
+ | F3 | C — up to date | `initialized:true, needsApply:false` | subtitle "Up to date"; `Refresh` only; no `Update`/`Initialize`; no list |
69
+ | F4 | busy | each state with `busy:true` | every fixed-install action button rendered `disabled` |
70
+
71
+ Run: `npx vitest run tests/unit/backend/harness-service.test.ts tests/unit/frontend/harness-panel.test.ts`.
72
+
73
+ ## Known testing gaps
74
+
75
+ - No DOM/interaction (click) tests for the frontend: the node test environment uses
76
+ static-markup rendering, so button `onClick` wiring is verified by code review and
77
+ by the backend status-reload behavior, not by simulated events. A jsdom +
78
+ `@testing-library/react` setup would be needed for true interaction coverage and is
79
+ not currently configured.
80
+ - No L3 Playwright smoke was run for this task (UI conditional-rendering change with
81
+ full backend + frontend unit coverage). Reserve E2E for release-level or
82
+ cross-cutting flow changes.
@@ -904,6 +904,7 @@ Handoff artifact schemas:
904
904
  ## Architecture Summary
905
905
  ## Task Classification
906
906
  ## Required Role Route
907
+ ## Scaffold Manifest
907
908
  ## Modules / Files
908
909
  ## File Responsibilities
909
910
  ## Public Surface Contract
@@ -1,6 +1,6 @@
1
1
  # Codex Review Gates
2
2
 
3
- Last updated: 2026-06-13
3
+ Last updated: 2026-06-14
4
4
 
5
5
  This document defines the Codex Review Gates feature for VCM.
6
6
 
@@ -41,7 +41,7 @@ The product outcome is higher task accuracy through earlier detection of:
41
41
 
42
42
  The first version should not:
43
43
 
44
- - require the fifth role to be an always-running embedded terminal
44
+ - require every task to start Codex Reviewer manually
45
45
  - let Codex edit repository files directly
46
46
  - automatically accept, reject, route, or replan a task
47
47
  - replace human approval for high-risk decisions
@@ -85,9 +85,12 @@ review state and asks VCM to start a review when the gate is enabled, required,
85
85
  and not already approved for the current input.
86
86
 
87
87
  VCM owns execution. When review starts, the VCM flow remains running and enters
88
- a Codex review stage. VCM runs Codex CLI / adapter, records state, validates the
89
- report shape, and calls PM back when review finishes. PM then reads the report
90
- and continues or routes by gate type.
88
+ a Codex review stage. VCM ensures the long-lived `codex-reviewer` embedded
89
+ terminal session is running, sends the gate prompt into that session, records
90
+ state, validates the report shape, and calls PM back when review finishes. PM
91
+ then reads the report and continues or routes by gate type. The same Codex
92
+ Reviewer terminal remains available after the gate so the user or PM can
93
+ continue discussing, challenging, or confirming the review result in context.
91
94
  Codex execution failure is VCM/tool failure, not `request_changes`; VCM offers
92
95
  retry, skip, or override and records the chosen exception state.
93
96
 
@@ -97,6 +100,7 @@ PM reaches gate trigger
97
100
  -> skill checks VCM Codex gate state
98
101
  -> skill requests VCM start review
99
102
  -> VCM state = codex-review:running
103
+ -> VCM sends gate prompt to Codex Reviewer terminal
100
104
  -> Codex Reviewer writes report
101
105
  -> VCM records completed / failed / skipped / overridden
102
106
  -> VCM emits Codex review callback to PM
@@ -119,6 +123,7 @@ Recommended inputs:
119
123
  - original user request
120
124
  - project-manager route message or durable task plan when present
121
125
  - architecture plan
126
+ - Scaffold Manifest and any architect-created scaffold diff
122
127
  - relevant durable architecture docs
123
128
  - `docs/TESTING.md` when the plan depends on validation strategy
124
129
  - changed file list when architect created scaffolding
@@ -128,6 +133,8 @@ Codex should review whether:
128
133
  - the plan matches the user request
129
134
  - the architecture boundaries are clear and compatible with the existing repo
130
135
  - file responsibilities and public contracts are specific enough for coder
136
+ - the Scaffold Manifest carries task-specific context and coder guidance instead
137
+ of putting that information in source-code comments
131
138
  - the plan avoids unnecessary scope expansion
132
139
  - risks, dependencies, migrations, permissions, data, and error paths are named
133
140
  - acceptance and validation evidence can be produced
@@ -211,6 +218,8 @@ Codex should review whether:
211
218
  - the final diff satisfies the user request
212
219
  - the implementation contains correctness bugs or behavior regressions
213
220
  - the code follows existing project conventions
221
+ - source and test comments contain no task-specific process notes, phase notes,
222
+ current-task rationale, or coder instructions
214
223
  - tests and implementation remain aligned
215
224
  - durable docs and generated artifacts are consistent with the diff
216
225
  - files outside the expected scope are explained
@@ -308,6 +317,8 @@ role. It should contain:
308
317
  ```text
309
318
  .ai/codex/AGENTS.md
310
319
  .ai/codex/config.toml
320
+ .ai/codex/.codex/config.toml
321
+ .ai/codex/.codex/hooks.json
311
322
  .ai/codex/prompts/architecture-plan-gate.md
312
323
  .ai/codex/prompts/validation-adequacy-gate.md
313
324
  .ai/codex/prompts/final-diff-gate.md
@@ -336,6 +347,22 @@ natively discover arbitrary `.ai/codex/config.toml` files the way it discovers
336
347
  so the VCM Codex adapter reads this file and maps supported keys to the Codex
337
348
  CLI invocation.
338
349
 
350
+ `.ai/codex/.codex/config.toml` and `.ai/codex/.codex/hooks.json` are the
351
+ Codex CLI project-level hook configuration. Because VCM starts Codex with
352
+ `.ai/codex` as the current Codex project, this nested `.codex` directory is
353
+ discovered by the interactive Codex CLI. The config enables hooks, and the
354
+ hooks post `UserPromptSubmit` and `Stop` events to VCM:
355
+
356
+ ```text
357
+ POST /api/hooks/codex-reviewer
358
+ POST /api/hooks/codex-reviewer/stop
359
+ ```
360
+
361
+ The hook payload records Codex's own session id, transcript path, cwd, and hook
362
+ event name. VCM stores those events on the `codex-reviewer` role session and in
363
+ the shared Round state, so a Codex review keeps the VCM flow running until the
364
+ Codex `Stop` event is observed and the normal settle timer completes.
365
+
339
366
  VCM should start Codex from `.ai/codex` so that `.ai/codex/AGENTS.md` is
340
367
  discovered naturally. Because the current session root is then `.ai/codex`, the
341
368
  permission profile must add the task repository as a profile-defined workspace
@@ -378,19 +405,25 @@ Implemented files:
378
405
 
379
406
  ```text
380
407
  src/shared/types/codex-review.ts
408
+ src/shared/types/codex-hook.ts
381
409
  src/backend/services/codex-review-service.ts
410
+ src/backend/services/codex-hook-service.ts
382
411
  src/backend/api/codex-review-routes.ts
412
+ src/backend/api/codex-hook-routes.ts
383
413
  ```
384
414
 
385
415
  Implemented API:
386
416
 
387
417
  ```text
388
418
  GET /api/tasks/:taskSlug/codex-review
419
+ PUT /api/tasks/:taskSlug/codex-review/settings
389
420
  POST /api/tasks/:taskSlug/codex-review/:gate/request
390
421
  POST /api/tasks/:taskSlug/codex-review/:gate/retry
391
422
  POST /api/tasks/:taskSlug/codex-review/:gate/skip
392
423
  POST /api/tasks/:taskSlug/codex-review/:gate/override
393
424
  GET /api/tasks/:taskSlug/codex-review/:gate/report
425
+ POST /api/hooks/codex-reviewer
426
+ POST /api/hooks/codex-reviewer/stop
394
427
  ```
395
428
 
396
429
  Provider implementations should be swappable:
@@ -410,52 +443,60 @@ When a review starts, VCM keeps the task flow running in a Codex review stage.
410
443
  When the provider finishes, VCM emits a Codex review callback to PM with gate,
411
444
  status, decision, report path, and any failure or exception metadata.
412
445
 
413
- The Codex CLI provider starts Codex with `.ai/codex` as the active Codex
414
- reviewer context. Current implementation shape:
446
+ The Codex CLI provider uses the long-lived embedded terminal session, not
447
+ `codex exec`, because VCM needs Codex `UserPromptSubmit` and `Stop` hook events
448
+ and the user may continue discussing the review after the report is written.
449
+ Current implementation shape for a fresh terminal:
415
450
 
416
451
  ```bash
417
- codex exec \
452
+ codex \
418
453
  --cd <taskRepoRoot>/.ai/codex \
419
454
  --add-dir <taskRepoRoot>/.ai/vcm/codex-reviews \
420
455
  --sandbox workspace-write \
421
456
  --ask-for-approval never \
422
- --skip-git-repo-check \
423
- --output-last-message <taskRepoRoot>/.ai/vcm/codex-reviews/logs/<request-id>.last-message.txt \
457
+ --dangerously-bypass-hook-trust \
424
458
  --model <model-from-.ai/codex/config.toml> \
425
- "<gate prompt>"
459
+ --config model_reasoning_effort="<effort-from-.ai/codex/config.toml>"
426
460
  ```
427
461
 
428
462
  Starting from `.ai/codex` causes Codex to load `.ai/codex/AGENTS.md` through
429
- its normal `AGENTS.md` discovery path. VCM validates the report path, request
430
- id, and decision before marking a gate completed. `--ask-for-approval never`
431
- prevents interactive permission prompts; execution failures are recorded as
432
- `failed` so the user can retry, skip, or override.
463
+ its normal `AGENTS.md` discovery path and `.ai/codex/.codex/hooks.json` through
464
+ the Codex project hook path. VCM sends the gate prompt into this terminal,
465
+ validates the report path, request id, and decision before marking a gate
466
+ completed, then callbacks PM. `--ask-for-approval never` and the VCM-owned hook
467
+ trust bypass prevent Codex from pausing at permission or hook trust prompts;
468
+ execution failures are recorded as `failed` so the user can retry, skip, or
469
+ override.
433
470
 
434
471
  ## 10. UI Shape
435
472
 
436
- Add a `Review Gates` panel to the task workspace or sidebar task details.
437
-
438
- Display one row per gate:
439
-
440
- ```text
441
- Architecture Plan pending | running | approve | request_changes
442
- Validation Adequacy pending | running | approve | request_changes
443
- Final Diff pending | running | approve | request_changes
444
- ```
445
-
446
- Each row should expose:
447
-
448
- - `Run`
449
- - `Run Again`
450
- - `Retry` on failed gates
451
- - `Skip` on failed gates
452
- - `Override` on failed gates
453
-
454
- The task header or sidebar dock can show a compact summary:
455
-
456
- ```text
457
- Codex Gates: 2/3 approved, 1 changes requested
458
- ```
473
+ Add a `Codex Review Gates` group to the left sidebar. It is visible for the
474
+ connected active task and contains three independent toggles:
475
+
476
+ - Architecture Plan
477
+ - Validation Adequacy
478
+ - Final Diff
479
+
480
+ All three toggles default to `off`. Turning on any gate writes it into
481
+ `.ai/codex/config.toml` under `[vcm.codex_review].required_gates` and sets
482
+ `enabled = true`. Turning all gates off writes `enabled = false` and
483
+ `required_gates = []`.
484
+
485
+ The task workspace must not show a separate Codex Review Gates panel. The UI
486
+ does not expose manual `Run`, `Run Again`, `Retry`, `Skip`, or `Override`
487
+ buttons for gates; PM triggers reviews through the `vcm-codex-review-gate`
488
+ skill, and VCM handles execution failures through its managed retry / skip /
489
+ override path.
490
+
491
+ When at least one gate toggle is on, or when the task already has a saved Codex
492
+ Reviewer session, the task workspace role tabs include a fifth role, `Codex
493
+ Reviewer`. It uses the same embedded terminal surface as the Claude Code roles,
494
+ but starts Codex CLI from `.ai/codex`, uses Codex model and effort selectors,
495
+ and is not part of PM message routing, auto orchestration, or translation. The
496
+ saved launch template still stores the four Claude Code role settings; when a
497
+ Codex gate is enabled and no task sessions exist yet, One-click start launches
498
+ those four Claude Code roles plus `codex-reviewer` with the Codex Reviewer
499
+ defaults.
459
500
 
460
501
  ## 11. Project-Manager Rules
461
502
 
@@ -484,16 +525,18 @@ Rules:
484
525
 
485
526
  The first implementation is intentionally small:
486
527
 
487
- 1. Add `.ai/codex/AGENTS.md` and `.ai/codex/config.toml` as VCM-managed Codex
488
- reviewer runtime files.
528
+ 1. Add `.ai/codex/AGENTS.md`, `.ai/codex/config.toml`, and
529
+ `.ai/codex/.codex/*` as VCM-managed Codex reviewer runtime files.
489
530
  2. Add `vcm-codex-review-gate` as the PM-facing skill / protocol entry.
490
- 3. Add backend APIs to request, run, retry, skip, override, list, and read gate
491
- reports.
492
- 4. Add manual UI controls for retry, skip, and override on failed gates.
531
+ 3. Add backend APIs to configure, request, run, retry, skip, override, list,
532
+ and read gate reports.
533
+ 4. Add sidebar toggles for the three gate enablement options.
493
534
  5. Add project-manager and final-acceptance harness rules that require checking
494
535
  Codex gate reports for complex tasks.
495
- 6. Keep gate triggering PM-driven at first.
496
- 7. Do not automatically route roles from Codex findings in the first version.
536
+ 6. Add Codex hook endpoints so the fifth role participates in VCM session and
537
+ Round state.
538
+ 7. Keep gate triggering PM-driven at first.
539
+ 8. Do not automatically route roles from Codex findings in the first version.
497
540
 
498
541
  Later versions can add automatic PM routing, provider selection, stricter
499
542
  provider-level read/write policies where supported by Codex CLI, and risk-based
@@ -81,7 +81,7 @@ These entries match the current `example/rust-layered/.ai/vcm-harness-manifest.j
81
81
  | Claude settings | `.claude/settings.json` | json-merge | Long-term | VCM owns hook entries matching VCM command markers. |
82
82
  | Agent directory | `.claude/agents/` | VCM-created directory | Long-term | Contains the four core VCM role agents. |
83
83
  | Core agent | `.claude/agents/project-manager.md` | managed-block | Long-term | Project-manager role rules. |
84
- | Core agent | `.claude/agents/architect.md` | managed-block | Long-term | Architect role rules: plan document, code scaffolding, Debug Mode, docs sync. |
84
+ | Core agent | `.claude/agents/architect.md` | managed-block | Long-term | Architect role rules: plan document, Scaffold Manifest, code scaffolding, Debug Mode, docs sync. |
85
85
  | Core agent | `.claude/agents/coder.md` | managed-block | Long-term | Coder role rules: scaffold implementation, coding standards, baseline unit checks. |
86
86
  | Core agent | `.claude/agents/reviewer.md` | managed-block | Long-term | Reviewer role rules: independent validation, TESTING.md strategy, integration/E2E case lists. |
87
87
  | Skill directory | `.claude/skills/` | VCM-created directory | Conditional long-term | Keep while repo-local VCM skills are installed. |
@@ -163,7 +163,8 @@ Task lifecycle commands:
163
163
  selects it as the mobile current task, applies the saved launch template, and
164
164
  starts the four role sessions (`project-manager`, `architect`, `coder`,
165
165
  `reviewer`) through the same one-click-start path as the desktop UI. The saved
166
- template controls permission mode, model, auto orchestration, and translation.
166
+ template controls permission mode, model, effort, auto orchestration, and
167
+ translation.
167
168
  If no template has been saved, VCM uses the default launch template.
168
169
  - `/close-task` starts a destructive confirmation flow for the current task.
169
170
  Gateway replies with the exact confirmation command.
@@ -249,7 +250,7 @@ Rules:
249
250
  -> load saved launch template from app preferences
250
251
  -> set orchestration from template
251
252
  -> set gateway/desktop translation state from template
252
- -> start four role sessions with template permission/model
253
+ -> start four role sessions with template permission/model/effort
253
254
  -> switch mobile current role to project-manager
254
255
  -> reply with task slug, branch, worktree, template summary, and session status
255
256
  ```
@@ -584,8 +585,8 @@ Service dependencies:
584
585
  Task cleanup.
585
586
  - `SessionService`: PM session state, Claude session metadata, and role session
586
587
  start for launch-template initialization.
587
- - `AppSettingsService`: saved launch template with permission mode, model, auto
588
- orchestration, and translation defaults.
588
+ - `AppSettingsService`: saved launch template with permission mode, model,
589
+ effort, auto orchestration, and translation defaults.
589
590
  - `MessageService` / orchestration state service: set the newly created task to
590
591
  template auto/manual orchestration mode.
591
592
  - `TerminalRuntime`: controlled PM terminal submission.
@@ -0,0 +1 @@
1
+ # Known Issues
@@ -75,7 +75,7 @@ Recommended flow:
75
75
 
76
76
  ```text
77
77
  project-manager
78
- -> architect architecture plan and code scaffolding
78
+ -> architect architecture plan, Scaffold Manifest, and code scaffolding
79
79
  -> coder implementation and baseline unit checks
80
80
  -> reviewer independent validation
81
81
  -> architect docs sync / architecture drift check
@@ -101,8 +101,17 @@ final task diff
101
101
 
102
102
  Each gate returns `approve` or `request_changes`. PM triggers gates through the
103
103
  `vcm-codex-review-gate` skill at the three workflow points; VCM owns the Codex
104
- Review switch, gate state, Codex CLI / adapter execution, and PM callback after
105
- review completes. Codex writes reports under `.ai/vcm/codex-reviews/`.
104
+ Review sidebar toggles, gate state, Codex CLI / adapter execution, and PM
105
+ callback after review completes. Codex writes reports under
106
+ `.ai/vcm/codex-reviews/`. All three gate toggles default to off.
107
+ When any gate is on, or when a Codex Reviewer session already exists, the task
108
+ workspace shows `Codex Reviewer` as a fifth terminal role with Codex model and
109
+ effort selection. VCM sends gate prompts into this long-lived terminal session
110
+ so the review can be challenged or clarified afterward; the role remains
111
+ outside PM routing and Claude Code auto orchestration. Codex Reviewer
112
+ `UserPromptSubmit` and `Stop` hooks post back to VCM from
113
+ `.ai/codex/.codex/hooks.json`, so the fifth role participates in session and
114
+ Round state while a gate is running.
106
115
  Architecture-plan findings return to architect, validation-adequacy findings
107
116
  return to reviewer, and final-diff findings go to architect first for
108
117
  assessment. Codex reviewer role configuration lives under `.ai/codex/`,
@@ -210,6 +219,7 @@ The project manager must not become the architect, coder, reviewer, or debugger
210
219
  The architect owns:
211
220
 
212
221
  - architecture plan
222
+ - Scaffold Manifest for task-specific file context and coder guidance
213
223
  - module boundaries
214
224
  - file responsibilities
215
225
  - cross-file callable surfaces and contract comments
@@ -279,7 +289,7 @@ Sections:
279
289
  - `New Task`
280
290
  - `Tasks`
281
291
 
282
- The connected active task also has a bottom status dock. It is not a collapsible sidebar section. It stays at the bottom of the sidebar and shows the active VCM Session title, task status, Session start time, total elapsed time, total Round count, and Claude Code active runtime. When the current Round is running, it also shows the Current Round start time, total elapsed time, Claude Code active runtime, and Turn count.
292
+ The connected active task also has a bottom status dock. It is not a collapsible sidebar section. It stays at the bottom of the sidebar and shows the active VCM Session title, task status, Session start time, total elapsed time, total Round count, and role active runtime. When the current Round is running, it also shows the Current Round start time, total elapsed time, role active runtime, and Turn count.
283
293
 
284
294
  `Repository Path` layout:
285
295
 
@@ -392,13 +402,13 @@ The split should stay close to 50/50 width. Both panes expand vertically to fill
392
402
 
393
403
  ## 8. Flow Pause Detection
394
404
 
395
- VCM detects flow pauses from Claude Code hook events, not from terminal silence, message history, or pending route files.
405
+ VCM detects flow pauses from role hook events, not from terminal silence, message history, or pending route files. Claude Code roles report through `.claude/settings.json`; Codex Reviewer reports through `.ai/codex/.codex/hooks.json`.
396
406
 
397
407
  Backend role state:
398
408
 
399
409
  - VCM terminal submit: role becomes `running`.
400
410
  - `Stop`: role becomes `idle` and records `lastTurnEndedAt`.
401
- - The role tab and flow pause state both react to Claude Code hook events.
411
+ - The role tab and flow pause state both react to Claude Code and Codex Reviewer hook events.
402
412
 
403
413
  Task-level Round state:
404
414
 
@@ -409,8 +419,8 @@ Task-level Round state:
409
419
  - If no new prompt is accepted before the deadline, the Round becomes `stopped`.
410
420
  - The stop transition is timer-driven from the `Stop` event. Round-state reads do not end a Round.
411
421
  - Before stopping, VCM checks `.ai/vcm/handoffs/messages`; if a pending route message exists and can be delivered, VCM retries delivery and extends the stop window instead of alerting.
412
- - The same Round state stores total Round count, Turn count, completed Turn count, and Claude Code active runtime. Active runtime is measured only between `UserPromptSubmit` and `Stop`, not during the stop window.
413
- - The Current Round dock shows both wall-clock Round duration and Claude Code active runtime. `Total` is `now - Round.startedAt`; `CC runtime` is the accumulated active runtime across Turns in that Round; `Turn count` is the number of accepted prompts in the Round.
422
+ - The same Round state stores total Round count, Turn count, completed Turn count, and role active runtime. Active runtime is measured only between `UserPromptSubmit` and `Stop`, not during the stop window.
423
+ - The Current Round dock shows both wall-clock Round duration and role active runtime. `Total` is `now - Round.startedAt`; `Role runtime` is the accumulated active runtime across Turns in that Round; `Turn count` is the number of accepted prompts in the Round.
414
424
 
415
425
  The frontend polls this task-level Round state and deduplicates each stopped Round so the same stopped state does not alert on every poll. Flow duration is measured from the first `UserPromptSubmit` to `stoppedAt`, falling back to the last `Stop` when needed. Runs under 2 minutes trigger the weak 3-chime reminder at 1.4 second intervals. Runs at or above 2 minutes trigger the strong alert dialog and repeating sound until confirmation.
416
426
 
@@ -550,11 +560,11 @@ Default route policy:
550
560
  - Peer routes such as `coder-reviewer.md` may exist for explicit task designs, but VCM still serializes delivery per target role.
551
561
  - `user` talks to `project-manager` through the normal active terminal or translation composer, not through a route file.
552
562
 
553
- Stop-triggered scan:
563
+ Claude Stop-triggered scan:
554
564
 
555
565
  - VCM injects Claude Code `UserPromptSubmit`, `Stop`, and `PermissionRequest` hooks into `.claude/settings.json`.
556
566
  - The hooks do not call `vcmctl`; they POST directly to the local VCM backend.
557
- - When any role stops, VCM marks that role idle, then scans pending route files.
567
+ - When a Claude Code role stops, VCM marks that role idle, then scans pending route files.
558
568
  - VCM scans the stopped role's outgoing files and also any pending files targeting newly idle roles, so messages that were blocked by a busy target can be delivered after that target stops.
559
569
  - VCM reads only stable, non-empty files and ignores blank files.
560
570
  - VCM delivers at most one message to a target role per scan.
@@ -590,11 +600,18 @@ VCM Harness injects Claude Code hooks into `.claude/settings.json`:
590
600
 
591
601
  VCM uses `UserPromptSubmit` as the Claude Code acceptance signal. A successful PTY write only proves VCM delivered text to the embedded terminal; `UserPromptSubmit` proves Claude Code accepted the prompt.
592
602
 
603
+ VCM Harness also injects Codex Reviewer hooks into `.ai/codex/.codex/hooks.json`:
604
+
605
+ - `UserPromptSubmit`: posts directly to `/api/hooks/codex-reviewer`, marks the fifth role running, and starts or continues the shared Round state
606
+ - `Stop`: posts directly to `/api/hooks/codex-reviewer/stop`, marks the fifth role idle, and lets the Round settle normally
607
+
608
+ Codex Reviewer hooks do not dispatch route files. PM receives Codex review completion through the Codex Review Gate callback managed by VCM.
609
+
593
610
  The injected role rules require asynchronous file messaging: after writing or updating a route file, the role must end the current Claude Code turn and wait for VCM to deliver a later reply. Roles should use `.claude/skills/vcm-route-message/SKILL.md` to author route files. Roles must not poll files, start shell loops, keep the turn open waiting for another role to answer, paste directly into another role terminal, or use Claude Code Task/Subagent for VCM role delegation.
594
611
 
595
612
  Roles must not run background Bash; a `PreToolUse` hook (`.ai/tools/vcm-bash-guard`) denies `run_in_background`, `nohup`, `setsid`, `disown`, and trailing `&`. The only sanctioned long-running mechanism is `.ai/tools/run-long-check` plus `.ai/tools/watch-job` through `vcm-long-running-validation`: the detached job worker enforces the 60 minute ceiling and a supervision lease that kills unwatched jobs, `watch-job` renews the lease in foreground windows of up to 8 minutes (exit `125` means call it again in the same turn), and the VCM backend blocks a role's turn-end while one of its validation jobs is still running.
596
613
 
597
- There is no `vcmctl` in the target design. Hook entrypoints are direct HTTP from Claude Code hooks to the local VCM backend.
614
+ There is no `vcmctl` in the target design. Hook entrypoints are direct HTTP from Claude Code and Codex Reviewer hooks to the local VCM backend.
598
615
 
599
616
  ## 13. Translation
600
617