reviw 0.17.1 → 0.17.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.ja.md +8 -8
- package/README.md +8 -8
- package/cli.cjs +156 -19
- package/package.json +1 -1
package/README.ja.md
CHANGED
|
@@ -177,7 +177,7 @@ plugin/
|
|
|
177
177
|
|
|
178
178
|
| 種類 | 名前 | 説明 |
|
|
179
179
|
|------|------|------|
|
|
180
|
-
| **コマンド** | `/reviw:do` | タスク開始 - worktree作成、計画、todo登録 |
|
|
180
|
+
| **コマンド** | `/reviw:do` | タスク開始 - gwqでworktree作成、計画、todo登録 |
|
|
181
181
|
| **コマンド** | `/reviw:done` | 完了チェックリスト - 7レビューエージェント実行、エビデンス収集、レビュー開始 |
|
|
182
182
|
| **エージェント** | `report-builder` | ユーザーレビュー用レポート準備 |
|
|
183
183
|
| **エージェント** | `review-code-quality` | コード品質: 可読性、DRY、型安全性、エラーハンドリング |
|
|
@@ -201,22 +201,22 @@ plugin/
|
|
|
201
201
|
適切な環境セットアップで新しいタスクを開始します。
|
|
202
202
|
|
|
203
203
|
**処理内容:**
|
|
204
|
-
1.
|
|
204
|
+
1. gwqを使用して分離開発用のgit worktreeを作成(`feature/<name>`、`fix/<name>`など)
|
|
205
205
|
2. エビデンス用の`.artifacts/<feature>/`ディレクトリをセットアップ
|
|
206
206
|
3. 計画とTODOチェックリスト付きの`REPORT.md`を作成
|
|
207
207
|
4. 進捗追跡用にTodoWriteにtodoを登録
|
|
208
208
|
|
|
209
209
|
**作成されるディレクトリ構成:**
|
|
210
210
|
```
|
|
211
|
-
.
|
|
211
|
+
<worktree>/ # 例: ~/src/github.com/owner/myrepo-feature-auth/
|
|
212
212
|
└── .artifacts/
|
|
213
|
-
└── <feature>/
|
|
214
|
-
├── REPORT.md
|
|
215
|
-
├── images/
|
|
216
|
-
└── videos/
|
|
213
|
+
└── <feature>/ # 例: auth(feature/authから)
|
|
214
|
+
├── REPORT.md # 計画、進捗、エビデンスリンク
|
|
215
|
+
├── images/ # スクリーンショット
|
|
216
|
+
└── videos/ # 動画録画
|
|
217
217
|
```
|
|
218
218
|
|
|
219
|
-
**タスク再開:** セッション開始時またはコンテキスト圧縮後、コマンドは既存のworktree
|
|
219
|
+
**タスク再開:** セッション開始時またはコンテキスト圧縮後、コマンドは既存のworktreeを確認(`gwq list`)し、`REPORT.md`から再開します。
|
|
220
220
|
|
|
221
221
|
#### `/reviw:done`
|
|
222
222
|
|
package/README.md
CHANGED
|
@@ -180,7 +180,7 @@ plugin/
|
|
|
180
180
|
|
|
181
181
|
| Type | Name | Description |
|
|
182
182
|
|------|------|-------------|
|
|
183
|
-
| **Command** | `/reviw:do` | Start a task - create worktree, plan, register todos |
|
|
183
|
+
| **Command** | `/reviw:do` | Start a task - create worktree with gwq, plan, register todos |
|
|
184
184
|
| **Command** | `/reviw:done` | Complete checklist - run 7 review agents, collect evidence, start review |
|
|
185
185
|
| **Agent** | `report-builder` | Prepare reports and evidence for user review |
|
|
186
186
|
| **Agent** | `review-code-quality` | Code quality: readability, DRY, type safety, error handling |
|
|
@@ -204,22 +204,22 @@ plugin/
|
|
|
204
204
|
Starts a new task with proper environment setup.
|
|
205
205
|
|
|
206
206
|
**What it does:**
|
|
207
|
-
1. Creates a git worktree for isolated development (`feature/<name>`, `fix/<name>`, etc.)
|
|
207
|
+
1. Creates a git worktree using gwq for isolated development (`feature/<name>`, `fix/<name>`, etc.)
|
|
208
208
|
2. Sets up `.artifacts/<feature>/` directory for evidence
|
|
209
209
|
3. Creates `REPORT.md` with plan and TODO checklist
|
|
210
210
|
4. Registers todos in TodoWrite for progress tracking
|
|
211
211
|
|
|
212
212
|
**Directory structure created:**
|
|
213
213
|
```
|
|
214
|
-
.
|
|
214
|
+
<worktree>/ # e.g., ~/src/github.com/owner/myrepo-feature-auth/
|
|
215
215
|
└── .artifacts/
|
|
216
|
-
└── <feature>/
|
|
217
|
-
├── REPORT.md
|
|
218
|
-
├── images/
|
|
219
|
-
└── videos/
|
|
216
|
+
└── <feature>/ # e.g., auth (from feature/auth)
|
|
217
|
+
├── REPORT.md # Plan, progress, evidence links
|
|
218
|
+
├── images/ # Screenshots
|
|
219
|
+
└── videos/ # Video recordings
|
|
220
220
|
```
|
|
221
221
|
|
|
222
|
-
**Task resumption:** When a session starts or after context compaction, the command checks for existing worktrees and resumes from `REPORT.md`.
|
|
222
|
+
**Task resumption:** When a session starts or after context compaction, the command checks for existing worktrees (via `gwq list`) and resumes from `REPORT.md`.
|
|
223
223
|
|
|
224
224
|
#### `/reviw:done`
|
|
225
225
|
|
package/cli.cjs
CHANGED
|
@@ -126,6 +126,13 @@ function sanitizeHtml(html) {
|
|
|
126
126
|
}
|
|
127
127
|
|
|
128
128
|
marked.use({
|
|
129
|
+
hooks: {
|
|
130
|
+
// テーブルをスクロールラッパーで囲む(後処理)
|
|
131
|
+
postprocess: function(html) {
|
|
132
|
+
return html.replace(/<table>/g, '<div class="table-scroll-container"><span class="scroll-hint">← scroll →</span><div class="table-scroll-wrapper"><table>')
|
|
133
|
+
.replace(/<\/table>/g, '</table></div></div>');
|
|
134
|
+
}
|
|
135
|
+
},
|
|
129
136
|
renderer: {
|
|
130
137
|
// 生HTMLブロックをサニタイズ
|
|
131
138
|
html: function(token) {
|
|
@@ -2730,7 +2737,7 @@ function htmlTemplate(dataRows, cols, projectRoot, relativePath, mode, previewHt
|
|
|
2730
2737
|
flex: 1;
|
|
2731
2738
|
min-width: 0;
|
|
2732
2739
|
overflow-y: auto;
|
|
2733
|
-
overflow-x:
|
|
2740
|
+
overflow-x: auto;
|
|
2734
2741
|
overscroll-behavior: contain;
|
|
2735
2742
|
}
|
|
2736
2743
|
.md-left .md-preview {
|
|
@@ -2772,8 +2779,6 @@ function htmlTemplate(dataRows, cols, projectRoot, relativePath, mode, previewHt
|
|
|
2772
2779
|
display: block;
|
|
2773
2780
|
width: 100%;
|
|
2774
2781
|
height: auto;
|
|
2775
|
-
min-width: 120px;
|
|
2776
|
-
max-width: 250px;
|
|
2777
2782
|
}
|
|
2778
2783
|
.md-preview code { background: rgba(255,255,255,0.08); padding: 2px 4px; border-radius: 4px; }
|
|
2779
2784
|
.md-preview pre {
|
|
@@ -2899,12 +2904,38 @@ function htmlTemplate(dataRows, cols, projectRoot, relativePath, mode, previewHt
|
|
|
2899
2904
|
[data-theme="light"] .frontmatter-table tbody th {
|
|
2900
2905
|
color: #7c3aed;
|
|
2901
2906
|
}
|
|
2907
|
+
/* Table scroll container and indicator */
|
|
2908
|
+
.table-scroll-container {
|
|
2909
|
+
position: relative;
|
|
2910
|
+
margin: 16px 0;
|
|
2911
|
+
}
|
|
2912
|
+
.table-scroll-wrapper {
|
|
2913
|
+
overflow-x: auto;
|
|
2914
|
+
border-radius: 8px;
|
|
2915
|
+
}
|
|
2916
|
+
.scroll-hint {
|
|
2917
|
+
text-align: right;
|
|
2918
|
+
font-size: 12px;
|
|
2919
|
+
color: var(--accent);
|
|
2920
|
+
padding: 4px 8px;
|
|
2921
|
+
margin-bottom: 4px;
|
|
2922
|
+
opacity: 0;
|
|
2923
|
+
visibility: hidden;
|
|
2924
|
+
transition: opacity 200ms ease;
|
|
2925
|
+
}
|
|
2926
|
+
.table-scroll-container.can-scroll .scroll-hint {
|
|
2927
|
+
opacity: 0.8;
|
|
2928
|
+
visibility: visible;
|
|
2929
|
+
}
|
|
2930
|
+
.table-scroll-container.scrolled-end .scroll-hint {
|
|
2931
|
+
opacity: 0;
|
|
2932
|
+
visibility: hidden;
|
|
2933
|
+
}
|
|
2902
2934
|
/* Markdown tables in preview */
|
|
2903
2935
|
.md-preview table:not(.frontmatter-table table) {
|
|
2904
|
-
width: 100%;
|
|
2936
|
+
min-width: 100%;
|
|
2937
|
+
width: max-content;
|
|
2905
2938
|
border-collapse: collapse;
|
|
2906
|
-
table-layout: fixed;
|
|
2907
|
-
margin: 16px 0;
|
|
2908
2939
|
border: 1px solid var(--border);
|
|
2909
2940
|
border-radius: 8px;
|
|
2910
2941
|
}
|
|
@@ -2916,17 +2947,12 @@ function htmlTemplate(dataRows, cols, projectRoot, relativePath, mode, previewHt
|
|
|
2916
2947
|
vertical-align: top;
|
|
2917
2948
|
word-break: break-word;
|
|
2918
2949
|
overflow-wrap: anywhere;
|
|
2950
|
+
width: auto;
|
|
2919
2951
|
}
|
|
2920
|
-
|
|
2921
|
-
.md-preview table:not(.frontmatter-table table)
|
|
2922
|
-
|
|
2923
|
-
|
|
2924
|
-
}
|
|
2925
|
-
.md-preview table:not(.frontmatter-table table) th:last-child,
|
|
2926
|
-
.md-preview table:not(.frontmatter-table table) td:last-child {
|
|
2927
|
-
width: 180px;
|
|
2928
|
-
min-width: 180px;
|
|
2929
|
-
max-width: 180px;
|
|
2952
|
+
/* Force equal column widths when colgroup is not specified */
|
|
2953
|
+
.md-preview table:not(.frontmatter-table table) colgroup ~ * th,
|
|
2954
|
+
.md-preview table:not(.frontmatter-table table) colgroup ~ * td {
|
|
2955
|
+
width: auto;
|
|
2930
2956
|
}
|
|
2931
2957
|
.md-preview table:not(.frontmatter-table table) td:has(video),
|
|
2932
2958
|
.md-preview table:not(.frontmatter-table table) td:has(img) {
|
|
@@ -4036,6 +4062,48 @@ function htmlTemplate(dataRows, cols, projectRoot, relativePath, mode, previewHt
|
|
|
4036
4062
|
themeToggle.addEventListener('click', toggleTheme);
|
|
4037
4063
|
})();
|
|
4038
4064
|
|
|
4065
|
+
// --- Table Scroll Indicator ---
|
|
4066
|
+
(function initTableScrollIndicators() {
|
|
4067
|
+
function updateScrollIndicator(wrapper) {
|
|
4068
|
+
const container = wrapper.closest('.table-scroll-container');
|
|
4069
|
+
if (!container) return;
|
|
4070
|
+
|
|
4071
|
+
const canScroll = wrapper.scrollWidth > wrapper.clientWidth;
|
|
4072
|
+
const isAtEnd = wrapper.scrollLeft + wrapper.clientWidth >= wrapper.scrollWidth - 5;
|
|
4073
|
+
|
|
4074
|
+
container.classList.toggle('can-scroll', canScroll && !isAtEnd);
|
|
4075
|
+
container.classList.toggle('scrolled-end', isAtEnd);
|
|
4076
|
+
}
|
|
4077
|
+
|
|
4078
|
+
function initWrapper(wrapper) {
|
|
4079
|
+
updateScrollIndicator(wrapper);
|
|
4080
|
+
wrapper.addEventListener('scroll', () => updateScrollIndicator(wrapper));
|
|
4081
|
+
}
|
|
4082
|
+
|
|
4083
|
+
// Initialize existing wrappers
|
|
4084
|
+
document.querySelectorAll('.table-scroll-wrapper').forEach(initWrapper);
|
|
4085
|
+
|
|
4086
|
+
// Watch for dynamically added wrappers
|
|
4087
|
+
const observer = new MutationObserver((mutations) => {
|
|
4088
|
+
mutations.forEach((mutation) => {
|
|
4089
|
+
mutation.addedNodes.forEach((node) => {
|
|
4090
|
+
if (node.nodeType === 1) {
|
|
4091
|
+
if (node.classList?.contains('table-scroll-wrapper')) {
|
|
4092
|
+
initWrapper(node);
|
|
4093
|
+
}
|
|
4094
|
+
node.querySelectorAll?.('.table-scroll-wrapper').forEach(initWrapper);
|
|
4095
|
+
}
|
|
4096
|
+
});
|
|
4097
|
+
});
|
|
4098
|
+
});
|
|
4099
|
+
observer.observe(document.body, { childList: true, subtree: true });
|
|
4100
|
+
|
|
4101
|
+
// Update on resize
|
|
4102
|
+
window.addEventListener('resize', () => {
|
|
4103
|
+
document.querySelectorAll('.table-scroll-wrapper').forEach(updateScrollIndicator);
|
|
4104
|
+
});
|
|
4105
|
+
})();
|
|
4106
|
+
|
|
4039
4107
|
// --- History Management ---
|
|
4040
4108
|
// History is now server-side (file-based), HISTORY_DATA is provided by server
|
|
4041
4109
|
|
|
@@ -5828,13 +5896,82 @@ function htmlTemplate(dataRows, cols, projectRoot, relativePath, mode, previewHt
|
|
|
5828
5896
|
fsContent.style.cursor = 'grab';
|
|
5829
5897
|
});
|
|
5830
5898
|
|
|
5831
|
-
//
|
|
5899
|
+
// Trackpad/Mouse wheel handling
|
|
5900
|
+
// - ctrlKey true (pinch gesture on trackpad) → zoom
|
|
5901
|
+
// - ctrlKey false (two-finger scroll) → pan
|
|
5832
5902
|
fsContent.addEventListener('wheel', (e) => {
|
|
5833
5903
|
e.preventDefault();
|
|
5834
|
-
|
|
5835
|
-
|
|
5904
|
+
if (e.ctrlKey) {
|
|
5905
|
+
// Pinch zoom on trackpad (or Ctrl+wheel on mouse)
|
|
5906
|
+
const factor = e.deltaY > 0 ? 0.9 : 1.1;
|
|
5907
|
+
zoomAt(factor, e.clientX, e.clientY);
|
|
5908
|
+
} else {
|
|
5909
|
+
// Two-finger scroll → pan
|
|
5910
|
+
panX -= e.deltaX;
|
|
5911
|
+
panY -= e.deltaY;
|
|
5912
|
+
updateTransform();
|
|
5913
|
+
}
|
|
5914
|
+
}, { passive: false });
|
|
5915
|
+
|
|
5916
|
+
// Touch support for pinch-to-zoom and two-finger pan
|
|
5917
|
+
let lastTouchDistance = 0;
|
|
5918
|
+
let lastTouchCenter = { x: 0, y: 0 };
|
|
5919
|
+
let touchStartPanX = 0;
|
|
5920
|
+
let touchStartPanY = 0;
|
|
5921
|
+
|
|
5922
|
+
function getTouchDistance(touches) {
|
|
5923
|
+
const dx = touches[0].clientX - touches[1].clientX;
|
|
5924
|
+
const dy = touches[0].clientY - touches[1].clientY;
|
|
5925
|
+
return Math.sqrt(dx * dx + dy * dy);
|
|
5926
|
+
}
|
|
5927
|
+
|
|
5928
|
+
function getTouchCenter(touches) {
|
|
5929
|
+
return {
|
|
5930
|
+
x: (touches[0].clientX + touches[1].clientX) / 2,
|
|
5931
|
+
y: (touches[0].clientY + touches[1].clientY) / 2
|
|
5932
|
+
};
|
|
5933
|
+
}
|
|
5934
|
+
|
|
5935
|
+
fsContent.addEventListener('touchstart', (e) => {
|
|
5936
|
+
if (e.touches.length === 2) {
|
|
5937
|
+
e.preventDefault();
|
|
5938
|
+
lastTouchDistance = getTouchDistance(e.touches);
|
|
5939
|
+
lastTouchCenter = getTouchCenter(e.touches);
|
|
5940
|
+
touchStartPanX = panX;
|
|
5941
|
+
touchStartPanY = panY;
|
|
5942
|
+
}
|
|
5943
|
+
}, { passive: false });
|
|
5944
|
+
|
|
5945
|
+
fsContent.addEventListener('touchmove', (e) => {
|
|
5946
|
+
if (e.touches.length === 2) {
|
|
5947
|
+
e.preventDefault();
|
|
5948
|
+
const currentDistance = getTouchDistance(e.touches);
|
|
5949
|
+
const currentCenter = getTouchCenter(e.touches);
|
|
5950
|
+
|
|
5951
|
+
// Pinch zoom
|
|
5952
|
+
if (lastTouchDistance > 0) {
|
|
5953
|
+
const scale = currentDistance / lastTouchDistance;
|
|
5954
|
+
if (Math.abs(scale - 1) > 0.01) {
|
|
5955
|
+
zoomAt(scale, currentCenter.x, currentCenter.y);
|
|
5956
|
+
lastTouchDistance = currentDistance;
|
|
5957
|
+
}
|
|
5958
|
+
}
|
|
5959
|
+
|
|
5960
|
+
// Two-finger pan
|
|
5961
|
+
const dx = currentCenter.x - lastTouchCenter.x;
|
|
5962
|
+
const dy = currentCenter.y - lastTouchCenter.y;
|
|
5963
|
+
panX += dx;
|
|
5964
|
+
panY += dy;
|
|
5965
|
+
updateTransform();
|
|
5966
|
+
|
|
5967
|
+
lastTouchCenter = currentCenter;
|
|
5968
|
+
}
|
|
5836
5969
|
}, { passive: false });
|
|
5837
5970
|
|
|
5971
|
+
fsContent.addEventListener('touchend', () => {
|
|
5972
|
+
lastTouchDistance = 0;
|
|
5973
|
+
});
|
|
5974
|
+
|
|
5838
5975
|
// ESC to close
|
|
5839
5976
|
document.addEventListener('keydown', (e) => {
|
|
5840
5977
|
if (e.key === 'Escape' && fsOverlay.classList.contains('visible')) {
|