@penadidik/meo-agent 1.2.0

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.
@@ -0,0 +1,108 @@
1
+ 'use strict';
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+
6
+ class Reporter {
7
+ constructor(opts) {
8
+ this.json = opts.json || false;
9
+ this.quiet = opts.quiet || false;
10
+ this.url = null;
11
+ this.output = null;
12
+ this.startedAt = 0;
13
+ this.lastReport = 0;
14
+ this.totalBytes = 0;
15
+ this.receivedBytes = 0;
16
+ this.barWidth = 30;
17
+ }
18
+
19
+ _emit(event, data) {
20
+ if (this.json) {
21
+ process.stdout.write(JSON.stringify({ event, ...data, ts: Date.now() }) + '\n');
22
+ }
23
+ }
24
+
25
+ start(url, output) {
26
+ this.url = url;
27
+ this.output = output;
28
+ this.startedAt = Date.now();
29
+ this.lastReport = this.startedAt;
30
+ this.receivedBytes = 0;
31
+ this.totalBytes = 0;
32
+
33
+ if (!this.quiet && !this.json) {
34
+ process.stderr.write(`Downloading ${url}\n → ${output}\n`);
35
+ }
36
+ this._emit('start', { url, output });
37
+ }
38
+
39
+ setTotal(bytes) {
40
+ this.totalBytes = bytes;
41
+ }
42
+
43
+ progress(received) {
44
+ this.receivedBytes = received;
45
+ const now = Date.now();
46
+
47
+ if (this.json) {
48
+ this._emit('progress', {
49
+ received,
50
+ total: this.totalBytes,
51
+ percent: this.totalBytes ? Math.round((received / this.totalBytes) * 100) : null
52
+ });
53
+ return;
54
+ }
55
+
56
+ if (this.quiet) return;
57
+
58
+ if (now - this.lastReport < 100 && this.totalBytes) return;
59
+ this.lastReport = now;
60
+
61
+ const percent = this.totalBytes ? Math.min(100, Math.round((received / this.totalBytes) * 100)) : 0;
62
+ const filled = Math.round((percent / 100) * this.barWidth);
63
+ const empty = this.barWidth - filled;
64
+ const bar = '█'.repeat(filled) + '░'.repeat(empty);
65
+ const mbReceived = (received / 1024 / 1024).toFixed(2);
66
+ const mbTotal = this.totalBytes ? (this.totalBytes / 1024 / 1024).toFixed(2) : '?';
67
+
68
+ process.stderr.write(`\r [${bar}] ${percent}% ${mbReceived} / ${mbTotal} MB`);
69
+ }
70
+
71
+ finish({ statusCode, resumed }) {
72
+ const elapsed = ((Date.now() - this.startedAt) / 1000).toFixed(2);
73
+ const mb = (this.receivedBytes / 1024 / 1024).toFixed(2);
74
+
75
+ if (!this.json) {
76
+ if (!this.quiet && this.totalBytes) {
77
+ process.stderr.write('\n');
78
+ }
79
+ if (!this.quiet) {
80
+ process.stderr.write(`✓ Saved to ${this.output} (${mb} MB in ${elapsed}s${resumed ? ', resumed' : ''})\n`);
81
+ }
82
+ }
83
+
84
+ this._emit('finish', {
85
+ output: this.output,
86
+ url: this.url,
87
+ bytes: this.receivedBytes,
88
+ elapsed_sec: parseFloat(elapsed),
89
+ status: statusCode,
90
+ resumed: resumed || false
91
+ });
92
+ }
93
+
94
+ error(message, code) {
95
+ if (this.json) {
96
+ this._emit('error', { message, code: code || 'UNKNOWN' });
97
+ } else {
98
+ process.stderr.write(`✗ Error: ${message}\n`);
99
+ }
100
+ }
101
+
102
+ info(message) {
103
+ if (this.quiet || this.json) return;
104
+ process.stderr.write(`${message}\n`);
105
+ }
106
+ }
107
+
108
+ module.exports = Reporter;
package/package.json ADDED
@@ -0,0 +1,87 @@
1
+ {
2
+ "name": "@penadidik/meo-agent",
3
+ "version": "1.2.0",
4
+ "description": "The unified AI agent runtime from Meo Code Labs — bundles a wget-like CLI with --json/--output/--continue/--sha256/--mirror/doctor/plugins features, developer-kit (use case scaffolder), and generate-pr (PR description generator) into one cross-platform distribution.",
5
+ "main": "index.js",
6
+ "bin": {
7
+ "meo-agent": "./bin/meo-agent.js"
8
+ },
9
+ "scripts": {
10
+ "build": "pkg .",
11
+ "test": "node test/test.js"
12
+ },
13
+ "devDependencies": {
14
+ "@yao-pkg/pkg": "^5.16.1"
15
+ },
16
+ "pkg": {
17
+ "targets": [
18
+ "node18-win-x64",
19
+ "node18-macos-x64",
20
+ "node18-linux-x64"
21
+ ],
22
+ "outputPath": "dist",
23
+ "scripts": [
24
+ "index.js",
25
+ "bin/**/*.js",
26
+ "lib/**/*.js"
27
+ ]
28
+ },
29
+ "repository": {
30
+ "type": "git",
31
+ "url": "git+https://github.com/meocode-labs/meo-agent.git"
32
+ },
33
+ "bugs": {
34
+ "url": "https://github.com/meocode-labs/meo-agent/issues"
35
+ },
36
+ "homepage": "https://github.com/meocode-labs/meo-agent#readme",
37
+ "author": {
38
+ "name": "penadidik",
39
+ "email": "researcher@meocode.com",
40
+ "url": "https://github.com/penadidik"
41
+ },
42
+ "contributors": [
43
+ {
44
+ "name": "Meo Code Labs",
45
+ "url": "https://meocode.com"
46
+ }
47
+ ],
48
+ "funding": {
49
+ "type": "github",
50
+ "url": "https://github.com/sponsors/meocode-labs"
51
+ },
52
+ "license": "MIT",
53
+ "keywords": [
54
+ "meo-agent",
55
+ "meo-code-labs",
56
+ "meocode",
57
+ "wget",
58
+ "cli",
59
+ "downloader",
60
+ "http",
61
+ "https",
62
+ "developer-tools",
63
+ "ai-agents",
64
+ "ai-tooling",
65
+ "developer-kit",
66
+ "generate-pr",
67
+ "terminal",
68
+ "progress-bar",
69
+ "json",
70
+ "resume",
71
+ "doctor"
72
+ ],
73
+ "engines": {
74
+ "node": ">=18"
75
+ },
76
+ "files": [
77
+ "index.js",
78
+ "bin/",
79
+ "lib/",
80
+ "examples/",
81
+ "developer-kit/",
82
+ "pull_request/",
83
+ "README.md",
84
+ "LICENSE",
85
+ "CHANGELOG.md"
86
+ ]
87
+ }
@@ -0,0 +1,104 @@
1
+ # Auto-Generate Pull Request
2
+
3
+ Sistem untuk auto-generate Pull Request description/review dari git changes.
4
+
5
+ ## Cara Kerja (2 Fase)
6
+
7
+ 1. **Fase Metadata (script)** — `generate-pr.sh` otomatis mengisi: repo, branch,
8
+ daftar file, jumlah baris (+/-), diff stat, dan commits.
9
+ 2. **Fase Analisis (AI/manual)** — untuk type `lead`/`hod`, file hasil berisi
10
+ placeholder `<!-- REVIEW:* -->` dan tabel `TBD` yang diisi oleh reviewer
11
+ (via opencode command `/generate-pr` atau manual).
12
+
13
+ ## Struktur
14
+
15
+ ```
16
+ ~/Developer/agent_opencode/
17
+ └── pull_request/
18
+ ├── generate-pr.sh # Main script
19
+ ├── templates/
20
+ │ ├── basic.md
21
+ │ ├── lead-review.md
22
+ │ └── hod-review.md
23
+ ├── output/ # OUTPUT (per app)
24
+ │ └── <app_name>/
25
+ │ └── pull_request_<datetime>.md
26
+ └── README.md
27
+
28
+ ~/.config/opencode/command/generate-pr.md # opencode command
29
+ ```
30
+
31
+ ## Penggunaan
32
+
33
+ ### Via Script
34
+
35
+ ```bash
36
+ S=~/Developer/agent_opencode/pull_request/generate-pr.sh
37
+
38
+ # Basic (default), current branch
39
+ "$S"
40
+
41
+ # Tipe + branch + PR number
42
+ "$S" lead improvements/pickup-report/08062026
43
+ "$S" hod request/SCA-Ticketing/17062026 515
44
+ ```
45
+
46
+ Argumen:
47
+ 1. `type` : `basic` | `lead` | `hod` (default `basic`)
48
+ 2. `branch` : target branch (default: current branch)
49
+ 3. `pr_number` : nomor PR untuk URL (default: `TBD`)
50
+
51
+ ### Via opencode
52
+
53
+ Gunakan keyword:
54
+ - "generate pr" / "make pr description" → **basic**
55
+ - "as lead review ..." → **lead**
56
+ - "as hod review ..." → **hod**
57
+
58
+ ## Logika Pemilihan Diff (otomatis)
59
+
60
+ Script memilih sumber perubahan dengan prioritas:
61
+ 1. `origin/<branch>` vs base branch (jika ada perbedaan)
62
+ 2. `<branch>` lokal vs base branch
63
+ 3. Working tree (uncommitted changes) vs `HEAD`
64
+
65
+ Base branch dideteksi otomatis: `origin/master` → `origin/main` → `master` → `main`.
66
+
67
+ ## Output Naming
68
+
69
+ `pull_request_<datetime>.md` — jika sudah ada (detik sama), otomatis menambah
70
+ suffix `_1`, `_2`, dst untuk menghindari overwrite.
71
+
72
+ Output tersimpan di:
73
+ ```
74
+ ~/Developer/agent_opencode/pull_request/output/<app_name>/pull_request_<datetime>.md
75
+ ```
76
+
77
+ ## Variabel Template
78
+
79
+ | Variable | Keterangan |
80
+ |----------|------------|
81
+ | `{{REPO}}` | Nama repository |
82
+ | `{{BRANCH}}` | Branch |
83
+ | `{{PR_NUMBER}}` | Nomor PR (default TBD) |
84
+ | `{{AUTHOR}}` | git user.name |
85
+ | `{{DATE}}` / `{{DATETIME}}` | Tanggal / timestamp |
86
+ | `{{SUMMARY}}` | Ringkasan otomatis |
87
+ | `{{FILES_COUNT}}` | Jumlah file |
88
+ | `{{BACKEND_COUNT}}` | File `.php` |
89
+ | `{{FRONTEND_COUNT}}` | File `.js`/`.ts` |
90
+ | `{{BLADE_COUNT}}` | File `.blade.php` |
91
+ | `{{NEW_FILES}}` | File baru |
92
+ | `{{LINES_ADDED}}` / `{{LINES_REMOVED}}` | Total +/- baris |
93
+ | `{{COMMITS_COUNT}}` | Jumlah commit |
94
+ | `{{COMMITS}}` | Daftar commit |
95
+ | `{{DIFF_STAT}}` | Statistik diff |
96
+ | `{{FILES_MODIFIED}}` | Tabel markdown file (template basic) |
97
+
98
+ ## Setup
99
+
100
+ ```bash
101
+ chmod +x ~/Developer/agent_opencode/pull_request/generate-pr.sh
102
+ ```
103
+
104
+ opencode command sudah tersedia di `~/.config/opencode/command/generate-pr.md`.
@@ -0,0 +1,190 @@
1
+ #!/usr/bin/env bash
2
+ # generate-pr.sh
3
+ # Auto-generate Pull Request description/review from git changes.
4
+ #
5
+ # Usage:
6
+ # ./generate-pr.sh [type] [branch] [pr_number]
7
+ # type : basic | lead | hod (default: basic)
8
+ # branch : target branch (default: current branch)
9
+ # pr_number : PR number for the URL (default: TBD)
10
+ #
11
+ # Output:
12
+ # ~/Developer/office/ivosights/pull_request/<app_name>/pull_request_<datetime>.md
13
+
14
+ set -euo pipefail
15
+
16
+ # ---------------------------------------------------------------------------
17
+ # Helpers
18
+ # ---------------------------------------------------------------------------
19
+ die() { echo "❌ Error: $*" >&2; exit 1; }
20
+
21
+ # Ensure we are inside a git repository
22
+ git rev-parse --is-inside-work-tree >/dev/null 2>&1 || die "Not inside a git repository."
23
+
24
+ # ---------------------------------------------------------------------------
25
+ # Parameters
26
+ # ---------------------------------------------------------------------------
27
+ TYPE="${1:-basic}"
28
+ BRANCH="${2:-$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "HEAD")}"
29
+ PR_NUMBER="${3:-TBD}"
30
+
31
+ case "$TYPE" in
32
+ basic) TEMPLATE_NAME="basic" ;;
33
+ lead) TEMPLATE_NAME="lead-review" ;;
34
+ hod) TEMPLATE_NAME="hod-review" ;;
35
+ *) die "Invalid type '$TYPE'. Use: basic | lead | hod" ;;
36
+ esac
37
+
38
+ # ---------------------------------------------------------------------------
39
+ # Repo & meta info
40
+ # ---------------------------------------------------------------------------
41
+ REPO="$(basename "$(git rev-parse --show-toplevel)")"
42
+ APP_NAME="${REPO//-/_}"
43
+ DATETIME="$(date +"%Y%m%d_%H%M%S")"
44
+ DATE="$(date +"%Y-%m-%d")"
45
+ AUTHOR="$(git config user.name 2>/dev/null || echo "Unknown")"
46
+
47
+ # ---------------------------------------------------------------------------
48
+ # Determine base branch (master or main)
49
+ # ---------------------------------------------------------------------------
50
+ BASE_BRANCH=""
51
+ for candidate in origin/master origin/main master main; do
52
+ if git rev-parse --verify "$candidate" >/dev/null 2>&1; then
53
+ BASE_BRANCH="$candidate"
54
+ break
55
+ fi
56
+ done
57
+ [[ -n "$BASE_BRANCH" ]] || die "Could not resolve base branch (master/main)."
58
+
59
+ # ---------------------------------------------------------------------------
60
+ # Resolve the comparison target (the "head" side of the diff)
61
+ # Priority: origin/<branch> -> <branch> -> working tree (uncommitted)
62
+ # ---------------------------------------------------------------------------
63
+ COMPARE_MODE=""
64
+ HEAD_REF=""
65
+
66
+ if git rev-parse --verify "origin/$BRANCH" >/dev/null 2>&1 \
67
+ && [[ -n "$(git diff "$BASE_BRANCH".."origin/$BRANCH" --name-only 2>/dev/null)" ]]; then
68
+ HEAD_REF="origin/$BRANCH"
69
+ COMPARE_MODE="branch"
70
+ elif git rev-parse --verify "$BRANCH" >/dev/null 2>&1 \
71
+ && [[ -n "$(git diff "$BASE_BRANCH".."$BRANCH" --name-only 2>/dev/null)" ]]; then
72
+ HEAD_REF="$BRANCH"
73
+ COMPARE_MODE="branch"
74
+ elif [[ -n "$(git status --porcelain 2>/dev/null)" ]]; then
75
+ # Fall back to uncommitted working tree changes
76
+ COMPARE_MODE="working"
77
+ else
78
+ die "No changes found for branch '$BRANCH' vs '$BASE_BRANCH' and no uncommitted changes."
79
+ fi
80
+
81
+ # ---------------------------------------------------------------------------
82
+ # Gather diff data based on compare mode
83
+ # ---------------------------------------------------------------------------
84
+ if [[ "$COMPARE_MODE" == "branch" ]]; then
85
+ DIFF_RANGE="$BASE_BRANCH..$HEAD_REF"
86
+ DIFF_STAT="$(git diff "$DIFF_RANGE" --stat)"
87
+ NAME_ONLY="$(git diff "$DIFF_RANGE" --name-only)"
88
+ NEW_NAMES="$(git diff "$DIFF_RANGE" --name-only --diff-filter=A)"
89
+ NUMSTAT="$(git diff "$DIFF_RANGE" --numstat)"
90
+ COMMITS="$(git log "$DIFF_RANGE" --oneline)"
91
+ else
92
+ # working tree (staged + unstaged) vs HEAD
93
+ DIFF_STAT="$(git diff HEAD --stat)"
94
+ NAME_ONLY="$(git diff HEAD --name-only)"
95
+ NEW_NAMES="$(git ls-files --others --exclude-standard)"
96
+ NUMSTAT="$(git diff HEAD --numstat)"
97
+ COMMITS="(uncommitted working-tree changes)"
98
+ fi
99
+
100
+ # ---------------------------------------------------------------------------
101
+ # Counts
102
+ # ---------------------------------------------------------------------------
103
+ count_lines() { [[ -z "$1" ]] && echo 0 || echo "$1" | grep -c . ; }
104
+
105
+ FILES_COUNT="$(count_lines "$NAME_ONLY")"
106
+ BACKEND_COUNT="$(echo "$NAME_ONLY" | grep -cE '\.php$' || true)"
107
+ FRONTEND_COUNT="$(echo "$NAME_ONLY" | grep -cE '\.(js|ts)$' || true)"
108
+ BLADE_COUNT="$(echo "$NAME_ONLY" | grep -cE '\.blade\.php$' || true)"
109
+ NEW_FILES="$(count_lines "$NEW_NAMES")"
110
+ COMMITS_COUNT="$(count_lines "$COMMITS")"
111
+
112
+ LINES_ADDED="$(echo "$NUMSTAT" | awk '{sum+=$1} END {print sum+0}')"
113
+ LINES_REMOVED="$(echo "$NUMSTAT" | awk '{sum+=$2} END {print sum+0}')"
114
+
115
+ SUMMARY="Pull request from branch \`$BRANCH\` ($COMPARE_MODE mode) with $FILES_COUNT file(s) changed, +$LINES_ADDED/-$LINES_REMOVED lines."
116
+
117
+ # Build a markdown table of modified files
118
+ if [[ -n "$NAME_ONLY" ]]; then
119
+ FILES_MODIFIED="$(echo "$NAME_ONLY" | sed 's/.*/| `&` |/')"
120
+ FILES_MODIFIED="| File |"$'\n'"|------|"$'\n'"$FILES_MODIFIED"
121
+ else
122
+ FILES_MODIFIED="_No files_"
123
+ fi
124
+
125
+ # ---------------------------------------------------------------------------
126
+ # Template resolution
127
+ # ---------------------------------------------------------------------------
128
+ TEMPLATE_DIR="$HOME/Developer/agent_opencode/pull_request/templates"
129
+ TEMPLATE_FILE="$TEMPLATE_DIR/$TEMPLATE_NAME.md"
130
+ [[ -f "$TEMPLATE_FILE" ]] || die "Template not found: $TEMPLATE_FILE"
131
+
132
+ # ---------------------------------------------------------------------------
133
+ # Output path (avoid collisions)
134
+ # ---------------------------------------------------------------------------
135
+ OUTPUT_DIR="$HOME/Developer/agent_opencode/pull_request/output/$APP_NAME"
136
+ mkdir -p "$OUTPUT_DIR"
137
+ OUTPUT_FILE="$OUTPUT_DIR/pull_request_${DATETIME}.md"
138
+ counter=1
139
+ while [[ -e "$OUTPUT_FILE" ]]; do
140
+ OUTPUT_FILE="$OUTPUT_DIR/pull_request_${DATETIME}_${counter}.md"
141
+ counter=$((counter + 1))
142
+ done
143
+
144
+ # ---------------------------------------------------------------------------
145
+ # Render template (multiline-safe via awk placeholder replacement)
146
+ # ---------------------------------------------------------------------------
147
+ render() {
148
+ local content
149
+ content="$(cat "$TEMPLATE_FILE")"
150
+
151
+ # Single-line replacements use awk gsub with literal strings.
152
+ # Multiline values are injected via environment + awk to stay safe.
153
+ REPO="$REPO" BRANCH="$BRANCH" PR_NUMBER="$PR_NUMBER" AUTHOR="$AUTHOR" \
154
+ DATE="$DATE" DATETIME="$DATETIME" SUMMARY="$SUMMARY" \
155
+ FILES_COUNT="$FILES_COUNT" BACKEND_COUNT="$BACKEND_COUNT" \
156
+ FRONTEND_COUNT="$FRONTEND_COUNT" BLADE_COUNT="$BLADE_COUNT" \
157
+ NEW_FILES="$NEW_FILES" LINES_ADDED="$LINES_ADDED" \
158
+ LINES_REMOVED="$LINES_REMOVED" COMMITS_COUNT="$COMMITS_COUNT" \
159
+ DIFF_STAT="$DIFF_STAT" COMMITS="$COMMITS" FILES_MODIFIED="$FILES_MODIFIED" \
160
+ awk '
161
+ BEGIN {
162
+ # Map placeholder -> env var name
163
+ n = split("REPO BRANCH PR_NUMBER AUTHOR DATE DATETIME SUMMARY FILES_COUNT BACKEND_COUNT FRONTEND_COUNT BLADE_COUNT NEW_FILES LINES_ADDED LINES_REMOVED COMMITS_COUNT DIFF_STAT COMMITS FILES_MODIFIED", keys, " ")
164
+ }
165
+ {
166
+ line = $0
167
+ for (i = 1; i <= n; i++) {
168
+ ph = "{{" keys[i] "}}"
169
+ val = ENVIRON[keys[i]]
170
+ # replace all occurrences without regex interpretation
171
+ while ((idx = index(line, ph)) > 0) {
172
+ line = substr(line, 1, idx-1) val substr(line, idx + length(ph))
173
+ }
174
+ }
175
+ print line
176
+ }' <<< "$content"
177
+ }
178
+
179
+ render > "$OUTPUT_FILE"
180
+
181
+ # ---------------------------------------------------------------------------
182
+ # Report
183
+ # ---------------------------------------------------------------------------
184
+ echo "✅ Pull Request generated successfully!"
185
+ echo "📁 Output : $OUTPUT_FILE"
186
+ echo "📋 Type : $TYPE ($TEMPLATE_NAME)"
187
+ echo "🌿 Branch : $BRANCH [base: $BASE_BRANCH, mode: $COMPARE_MODE]"
188
+ echo "📊 Files : $FILES_COUNT (PHP: $BACKEND_COUNT, JS/TS: $FRONTEND_COUNT, Blade: $BLADE_COUNT, New: $NEW_FILES)"
189
+ echo "➕ Lines : +$LINES_ADDED / -$LINES_REMOVED"
190
+ echo "🔢 Commits: $COMMITS_COUNT"
@@ -0,0 +1,41 @@
1
+ ## Pull Request Description
2
+
3
+ **Repository:** {{REPO}}
4
+ **PR URL:** https://github.com/ivosights/{{REPO}}/pull/{{PR_NUMBER}}
5
+ **Branch:** `{{BRANCH}}`
6
+ **Author:** {{AUTHOR}}
7
+ **Date:** {{DATE}}
8
+
9
+ ---
10
+
11
+ ### Summary
12
+
13
+ {{SUMMARY}}
14
+
15
+ ### Scope
16
+ - **Files changed:** {{FILES_COUNT}} (PHP: {{BACKEND_COUNT}}, JS/TS: {{FRONTEND_COUNT}}, Blade: {{BLADE_COUNT}})
17
+ - **New files:** {{NEW_FILES}}
18
+ - **Lines:** +{{LINES_ADDED}} / -{{LINES_REMOVED}}
19
+
20
+ ### Files Modified
21
+
22
+ {{FILES_MODIFIED}}
23
+
24
+ ### What This PR Does
25
+
26
+ <!-- Describe the purpose / behaviour change of this PR -->
27
+ _..._
28
+
29
+ ---
30
+
31
+ ### Diff Summary
32
+
33
+ ```
34
+ {{DIFF_STAT}}
35
+ ```
36
+
37
+ ### Commits
38
+
39
+ ```
40
+ {{COMMITS}}
41
+ ```
@@ -0,0 +1,101 @@
1
+ # HOD Code Review
2
+
3
+ **Repository:** {{REPO}}
4
+ **PR URL:** https://github.com/ivosights/{{REPO}}/pull/{{PR_NUMBER}}
5
+ **Branch:** `{{BRANCH}}`
6
+ **Reviewed By:** Head of Department (HOD)
7
+ **Review Date:** {{DATE}}
8
+
9
+ ---
10
+
11
+ ## Executive Summary
12
+
13
+ {{SUMMARY}}
14
+
15
+ > _HOD verdict & qualitative analysis to be completed by reviewer (opencode `/generate-pr hod` or manual)._
16
+
17
+ ---
18
+
19
+ ## Scope of Changes
20
+
21
+ | Metric | Value |
22
+ |--------|-------|
23
+ | Files Modified | {{FILES_COUNT}} files |
24
+ | Lines Added | +{{LINES_ADDED}} |
25
+ | Lines Removed | -{{LINES_REMOVED}} |
26
+ | New Files | {{NEW_FILES}} |
27
+ | Commits | {{COMMITS_COUNT}} |
28
+
29
+ ### Files Breakdown
30
+ - **Backend (PHP):** {{BACKEND_COUNT}} files
31
+ - **Frontend (JS/TS):** {{FRONTEND_COUNT}} files
32
+ - **Blade Templates:** {{BLADE_COUNT}} files
33
+
34
+ ---
35
+
36
+ ## 🟥 Critical Issues (Must Fix)
37
+
38
+ <!-- REVIEW:CRITICAL -->
39
+ _List blocking issues here (security, broken logic, debug code, undefined vars)._
40
+
41
+ ---
42
+
43
+ ## 🟧 High Priority Issues
44
+
45
+ <!-- REVIEW:HIGH -->
46
+ _List high-priority concerns (breaking changes, missing tests, interface changes)._
47
+
48
+ ---
49
+
50
+ ## 🟨 Medium / Minor Issues
51
+
52
+ <!-- REVIEW:MEDIUM -->
53
+ _List code-quality, duplication, and style concerns._
54
+
55
+ ---
56
+
57
+ ## Required Actions Before Approval
58
+
59
+ | Priority | Action | Owner |
60
+ |----------|--------|-------|
61
+ | 🔴 CRITICAL | _..._ | _..._ |
62
+ | 🟧 HIGH | _..._ | _..._ |
63
+ | 🟨 MEDIUM | _..._ | _..._ |
64
+
65
+ ---
66
+
67
+ ## Risk Assessment
68
+
69
+ | Area | Risk Level | Notes |
70
+ |------|-----------|-------|
71
+ | **Security** | _TBD_ | _..._ |
72
+ | **Performance** | _TBD_ | _..._ |
73
+ | **Data Integrity** | _TBD_ | _..._ |
74
+ | **Backward Compat** | _TBD_ | _..._ |
75
+ | **Testing** | _TBD_ | _..._ |
76
+
77
+ ---
78
+
79
+ ## Final Verdict
80
+
81
+ ### ⬜ TBD — APPROVE / REQUEST CHANGES
82
+
83
+ **Reason:** _..._
84
+
85
+ **Recommended Next Steps:**
86
+ 1. _..._
87
+ 2. _..._
88
+ 3. _..._
89
+
90
+ ---
91
+
92
+ ## Files Changed Summary
93
+
94
+ ```
95
+ {{DIFF_STAT}}
96
+ ```
97
+
98
+ ### Commits
99
+ ```
100
+ {{COMMITS}}
101
+ ```