vibe-coding-master 0.3.0 → 0.3.1

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 (35) hide show
  1. package/README.md +9 -6
  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 +144 -59
  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/harness/codex-review.js +37 -6
  20. package/dist/shared/constants.js +15 -1
  21. package/dist/shared/types/app-settings.js +4 -3
  22. package/dist/shared/types/codex-hook.js +1 -0
  23. package/dist/shared/types/session.js +44 -0
  24. package/dist-frontend/assets/index-BavJjWQY.js +92 -0
  25. package/dist-frontend/assets/index-CR1EOe-w.css +32 -0
  26. package/dist-frontend/index.html +2 -2
  27. package/docs/ARCHITECTURE.md +1 -0
  28. package/docs/TESTING.md +82 -0
  29. package/docs/codex-review-gates.md +83 -45
  30. package/docs/gateway-design.md +5 -4
  31. package/docs/known-issues.md +1 -0
  32. package/docs/product-design.md +26 -10
  33. package/package.json +1 -1
  34. package/dist-frontend/assets/index-C9l94uxA.js +0 -92
  35. 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.
@@ -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
@@ -308,6 +312,8 @@ role. It should contain:
308
312
  ```text
309
313
  .ai/codex/AGENTS.md
310
314
  .ai/codex/config.toml
315
+ .ai/codex/.codex/config.toml
316
+ .ai/codex/.codex/hooks.json
311
317
  .ai/codex/prompts/architecture-plan-gate.md
312
318
  .ai/codex/prompts/validation-adequacy-gate.md
313
319
  .ai/codex/prompts/final-diff-gate.md
@@ -336,6 +342,22 @@ natively discover arbitrary `.ai/codex/config.toml` files the way it discovers
336
342
  so the VCM Codex adapter reads this file and maps supported keys to the Codex
337
343
  CLI invocation.
338
344
 
345
+ `.ai/codex/.codex/config.toml` and `.ai/codex/.codex/hooks.json` are the
346
+ Codex CLI project-level hook configuration. Because VCM starts Codex with
347
+ `.ai/codex` as the current Codex project, this nested `.codex` directory is
348
+ discovered by the interactive Codex CLI. The config enables hooks, and the
349
+ hooks post `UserPromptSubmit` and `Stop` events to VCM:
350
+
351
+ ```text
352
+ POST /api/hooks/codex-reviewer
353
+ POST /api/hooks/codex-reviewer/stop
354
+ ```
355
+
356
+ The hook payload records Codex's own session id, transcript path, cwd, and hook
357
+ event name. VCM stores those events on the `codex-reviewer` role session and in
358
+ the shared Round state, so a Codex review keeps the VCM flow running until the
359
+ Codex `Stop` event is observed and the normal settle timer completes.
360
+
339
361
  VCM should start Codex from `.ai/codex` so that `.ai/codex/AGENTS.md` is
340
362
  discovered naturally. Because the current session root is then `.ai/codex`, the
341
363
  permission profile must add the task repository as a profile-defined workspace
@@ -378,19 +400,25 @@ Implemented files:
378
400
 
379
401
  ```text
380
402
  src/shared/types/codex-review.ts
403
+ src/shared/types/codex-hook.ts
381
404
  src/backend/services/codex-review-service.ts
405
+ src/backend/services/codex-hook-service.ts
382
406
  src/backend/api/codex-review-routes.ts
407
+ src/backend/api/codex-hook-routes.ts
383
408
  ```
384
409
 
385
410
  Implemented API:
386
411
 
387
412
  ```text
388
413
  GET /api/tasks/:taskSlug/codex-review
414
+ PUT /api/tasks/:taskSlug/codex-review/settings
389
415
  POST /api/tasks/:taskSlug/codex-review/:gate/request
390
416
  POST /api/tasks/:taskSlug/codex-review/:gate/retry
391
417
  POST /api/tasks/:taskSlug/codex-review/:gate/skip
392
418
  POST /api/tasks/:taskSlug/codex-review/:gate/override
393
419
  GET /api/tasks/:taskSlug/codex-review/:gate/report
420
+ POST /api/hooks/codex-reviewer
421
+ POST /api/hooks/codex-reviewer/stop
394
422
  ```
395
423
 
396
424
  Provider implementations should be swappable:
@@ -410,52 +438,60 @@ When a review starts, VCM keeps the task flow running in a Codex review stage.
410
438
  When the provider finishes, VCM emits a Codex review callback to PM with gate,
411
439
  status, decision, report path, and any failure or exception metadata.
412
440
 
413
- The Codex CLI provider starts Codex with `.ai/codex` as the active Codex
414
- reviewer context. Current implementation shape:
441
+ The Codex CLI provider uses the long-lived embedded terminal session, not
442
+ `codex exec`, because VCM needs Codex `UserPromptSubmit` and `Stop` hook events
443
+ and the user may continue discussing the review after the report is written.
444
+ Current implementation shape for a fresh terminal:
415
445
 
416
446
  ```bash
417
- codex exec \
447
+ codex \
418
448
  --cd <taskRepoRoot>/.ai/codex \
419
449
  --add-dir <taskRepoRoot>/.ai/vcm/codex-reviews \
420
450
  --sandbox workspace-write \
421
451
  --ask-for-approval never \
422
- --skip-git-repo-check \
423
- --output-last-message <taskRepoRoot>/.ai/vcm/codex-reviews/logs/<request-id>.last-message.txt \
452
+ --dangerously-bypass-hook-trust \
424
453
  --model <model-from-.ai/codex/config.toml> \
425
- "<gate prompt>"
454
+ --config model_reasoning_effort="<effort-from-.ai/codex/config.toml>"
426
455
  ```
427
456
 
428
457
  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.
458
+ its normal `AGENTS.md` discovery path and `.ai/codex/.codex/hooks.json` through
459
+ the Codex project hook path. VCM sends the gate prompt into this terminal,
460
+ validates the report path, request id, and decision before marking a gate
461
+ completed, then callbacks PM. `--ask-for-approval never` and the VCM-owned hook
462
+ trust bypass prevent Codex from pausing at permission or hook trust prompts;
463
+ execution failures are recorded as `failed` so the user can retry, skip, or
464
+ override.
433
465
 
434
466
  ## 10. UI Shape
435
467
 
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
- ```
468
+ Add a `Codex Review Gates` group to the left sidebar. It is visible for the
469
+ connected active task and contains three independent toggles:
470
+
471
+ - Architecture Plan
472
+ - Validation Adequacy
473
+ - Final Diff
474
+
475
+ All three toggles default to `off`. Turning on any gate writes it into
476
+ `.ai/codex/config.toml` under `[vcm.codex_review].required_gates` and sets
477
+ `enabled = true`. Turning all gates off writes `enabled = false` and
478
+ `required_gates = []`.
479
+
480
+ The task workspace must not show a separate Codex Review Gates panel. The UI
481
+ does not expose manual `Run`, `Run Again`, `Retry`, `Skip`, or `Override`
482
+ buttons for gates; PM triggers reviews through the `vcm-codex-review-gate`
483
+ skill, and VCM handles execution failures through its managed retry / skip /
484
+ override path.
485
+
486
+ When at least one gate toggle is on, or when the task already has a saved Codex
487
+ Reviewer session, the task workspace role tabs include a fifth role, `Codex
488
+ Reviewer`. It uses the same embedded terminal surface as the Claude Code roles,
489
+ but starts Codex CLI from `.ai/codex`, uses Codex model and effort selectors,
490
+ and is not part of PM message routing, auto orchestration, or translation. The
491
+ saved launch template still stores the four Claude Code role settings; when a
492
+ Codex gate is enabled and no task sessions exist yet, One-click start launches
493
+ those four Claude Code roles plus `codex-reviewer` with the Codex Reviewer
494
+ defaults.
459
495
 
460
496
  ## 11. Project-Manager Rules
461
497
 
@@ -484,16 +520,18 @@ Rules:
484
520
 
485
521
  The first implementation is intentionally small:
486
522
 
487
- 1. Add `.ai/codex/AGENTS.md` and `.ai/codex/config.toml` as VCM-managed Codex
488
- reviewer runtime files.
523
+ 1. Add `.ai/codex/AGENTS.md`, `.ai/codex/config.toml`, and
524
+ `.ai/codex/.codex/*` as VCM-managed Codex reviewer runtime files.
489
525
  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.
526
+ 3. Add backend APIs to configure, request, run, retry, skip, override, list,
527
+ and read gate reports.
528
+ 4. Add sidebar toggles for the three gate enablement options.
493
529
  5. Add project-manager and final-acceptance harness rules that require checking
494
530
  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.
531
+ 6. Add Codex hook endpoints so the fifth role participates in VCM session and
532
+ Round state.
533
+ 7. Keep gate triggering PM-driven at first.
534
+ 8. Do not automatically route roles from Codex findings in the first version.
497
535
 
498
536
  Later versions can add automatic PM routing, provider selection, stricter
499
537
  provider-level read/write policies where supported by Codex CLI, and risk-based
@@ -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
@@ -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/`,
@@ -279,7 +288,7 @@ Sections:
279
288
  - `New Task`
280
289
  - `Tasks`
281
290
 
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.
291
+ 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
292
 
284
293
  `Repository Path` layout:
285
294
 
@@ -392,13 +401,13 @@ The split should stay close to 50/50 width. Both panes expand vertically to fill
392
401
 
393
402
  ## 8. Flow Pause Detection
394
403
 
395
- VCM detects flow pauses from Claude Code hook events, not from terminal silence, message history, or pending route files.
404
+ 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
405
 
397
406
  Backend role state:
398
407
 
399
408
  - VCM terminal submit: role becomes `running`.
400
409
  - `Stop`: role becomes `idle` and records `lastTurnEndedAt`.
401
- - The role tab and flow pause state both react to Claude Code hook events.
410
+ - The role tab and flow pause state both react to Claude Code and Codex Reviewer hook events.
402
411
 
403
412
  Task-level Round state:
404
413
 
@@ -409,8 +418,8 @@ Task-level Round state:
409
418
  - If no new prompt is accepted before the deadline, the Round becomes `stopped`.
410
419
  - The stop transition is timer-driven from the `Stop` event. Round-state reads do not end a Round.
411
420
  - 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.
421
+ - 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.
422
+ - 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
423
 
415
424
  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
425
 
@@ -550,11 +559,11 @@ Default route policy:
550
559
  - Peer routes such as `coder-reviewer.md` may exist for explicit task designs, but VCM still serializes delivery per target role.
551
560
  - `user` talks to `project-manager` through the normal active terminal or translation composer, not through a route file.
552
561
 
553
- Stop-triggered scan:
562
+ Claude Stop-triggered scan:
554
563
 
555
564
  - VCM injects Claude Code `UserPromptSubmit`, `Stop`, and `PermissionRequest` hooks into `.claude/settings.json`.
556
565
  - 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.
566
+ - When a Claude Code role stops, VCM marks that role idle, then scans pending route files.
558
567
  - 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
568
  - VCM reads only stable, non-empty files and ignores blank files.
560
569
  - VCM delivers at most one message to a target role per scan.
@@ -590,11 +599,18 @@ VCM Harness injects Claude Code hooks into `.claude/settings.json`:
590
599
 
591
600
  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
601
 
602
+ VCM Harness also injects Codex Reviewer hooks into `.ai/codex/.codex/hooks.json`:
603
+
604
+ - `UserPromptSubmit`: posts directly to `/api/hooks/codex-reviewer`, marks the fifth role running, and starts or continues the shared Round state
605
+ - `Stop`: posts directly to `/api/hooks/codex-reviewer/stop`, marks the fifth role idle, and lets the Round settle normally
606
+
607
+ Codex Reviewer hooks do not dispatch route files. PM receives Codex review completion through the Codex Review Gate callback managed by VCM.
608
+
593
609
  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
610
 
595
611
  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
612
 
597
- There is no `vcmctl` in the target design. Hook entrypoints are direct HTTP from Claude Code hooks to the local VCM backend.
613
+ 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
614
 
599
615
  ## 13. Translation
600
616
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vibe-coding-master",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "description": "Local GUI session cockpit for Claude Code role sessions.",
5
5
  "type": "module",
6
6
  "files": [