Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
root = true

[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
indent_style = space
indent_size = 4
trim_trailing_whitespace = true

[*.{md,json,yml,yaml}]
indent_size = 2
27 changes: 27 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
APP_ENV=production
APP_DEBUG=false
LOG_CHANNEL=single

OPENAI_API_KEY=your-openai-key
OPENAI_MODEL=gpt-5-nano

MAIL_TRANSPORT=smtp
MAIL_FROM_ADDRESS=noreply@example.com
MAIL_FROM_NAME="ReplyPilot AI"

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_NAME=replypilot
DB_USER=replypilot
DB_PASS=changeme

INSTALL_TOKEN=

# Admin reply tone
REPLY_TONE=friendly

# Envato purchase validation
PURCHASE_VALIDATION_ENABLED=false
ENVATO_PERSONAL_TOKEN=
ENVATO_ENFORCE_ALLOWED_IDS=false
ENVATO_ALLOWED_ITEM_IDS=
35 changes: 35 additions & 0 deletions .env.mockmode
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
APP_ENV=local
APP_DEBUG=true
LOG_CHANNEL=single

OPENAI_API_KEY=MOCK_MODE
OPENAI_MODEL=gpt-5-nano

MAIL_TRANSPORT=file
MAIL_FROM_ADDRESS=noreply@example.test
MAIL_FROM_NAME="AI Reply Bot"

# SMTP Settings (for production)
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_USER=
SMTP_PASS=
SMTP_ENCRYPTION=tls

DB_CONNECTION=none

# Database (production)
DB_HOST=127.0.0.1
DB_NAME=replypilot
DB_USER=replypilot
DB_PASS=secret
INSTALL_TOKEN=

# Reply tone (admin controlled)
REPLY_TONE=friendly

# Envato purchase validation
PURCHASE_VALIDATION_ENABLED=false
ENVATO_PERSONAL_TOKEN=
ENVATO_ENFORCE_ALLOWED_IDS=false
ENVATO_ALLOWED_ITEM_IDS=
13 changes: 13 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Exclude dev/CI/editor junk from GitHub source zips
/.github/ export-ignore
/.vscode/ export-ignore
/.idea/ export-ignore
/docs/ export-ignore

# Exclude mocks and debug docs from distro
/app/**/**/*Mock.php export-ignore
/app/*/*Mock.php export-ignore
/docs/DEBUG.md export-ignore

# Keep these INCLUDED (don’t mark them export-ignore):
# README.md, LICENSE, SECURITY.md, CONTRIBUTING.md, CODE_OF_CONDUCT.md, .editorconfig
33 changes: 33 additions & 0 deletions .github/ISSUE_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
## Issue Type
<!-- Bug Report / Feature Request / Documentation / Question -->

## Priority
<!-- Low / Medium / High / Critical -->

## Description
<!-- Clear and concise description of the issue -->

## Steps to Reproduce
<!-- For bugs: steps to reproduce the behavior -->
1.
2.
3.

## Expected Behavior
<!-- What you expected to happen -->

## Actual Behavior
<!-- What actually happened -->

## Environment
- PHP Version:
- MySQL Version:
- Web Server:
- OS:
- Browser (if relevant):

## Version
- ReplyPilot AI Version:

## Additional Context
<!-- Add any other context, screenshots, or logs -->
39 changes: 39 additions & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
## Summary
<!-- Brief description of changes -->

## Related Issues
<!-- Link to related issues: Fixes #123, Closes #456 -->

## Type of Change
- [ ] Bug fix (non-breaking change)
- [ ] New feature (non-breaking change)
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
- [ ] Documentation update

## Changes Made
<!-- List of specific changes -->
-
-

## Testing
### Testing in Mock Mode
<!-- Describe mock mode testing performed -->

### Manual Testing
<!-- Steps taken to test changes -->

## Screenshots
<!-- If applicable, add screenshots -->

## Breaking Changes
<!-- List any breaking changes and migration steps -->

## Checklist
- [ ] My code follows the project's style guidelines
- [ ] I have performed a self-review of my code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [ ] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] Any dependent changes have been merged and published
10 changes: 10 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
name: ci
on: [push, pull_request]
jobs:
php-lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: PHP syntax check
run: |
find . -type f -name '*.php' -not -path './vendor/*' -print0 | xargs -0 -n1 php -l
146 changes: 146 additions & 0 deletions .github/workflows/replay-per-file.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
name: Replay per-file commits from commits.txt

on:
workflow_dispatch:
inputs:
source_branch:
description: Branch that currently has the correct final files (the Codex-created branch)
required: true
default: codex/extract-app-zip
default_branch:
description: Default branch (main or Main)
required: true
default: main

permissions:
contents: write # allow pushing new branch

jobs:
replay:
runs-on: ubuntu-latest
env:
LC_ALL: C.UTF-8
LANG: C.UTF-8
steps:
- name: Checkout repo (source branch)
uses: actions/checkout@v4
with:
ref: ${{ github.event.inputs.source_branch }}
fetch-depth: 0

- name: Fetch default branch
run: |
git fetch origin "${{ github.event.inputs.default_branch }}:${{ github.event.inputs.default_branch }}" --prune

- name: Compute merge base
id: base
run: |
BASE=$(git merge-base "origin/${{ github.event.inputs.source_branch }}" "origin/${{ github.event.inputs.default_branch }}" || git merge-base "${{ github.event.inputs.source_branch }}" "origin/${{ github.event.inputs.default_branch }}")
echo "base=$BASE" >> $GITHUB_OUTPUT

- name: Snapshot current tree from source branch
run: |
mkdir -p /tmp/snap
git archive --format=tar "origin/${{ github.event.inputs.source_branch }}" | tar -x -C /tmp/snap

- name: Create replay branch from merge base
id: replay
run: |
BR="codex/replay-$(date -u +%Y%m%d-%H%M)"
git checkout -B "$BR" "${{ steps.base.outputs.base }}"
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
echo "branch=$BR" >> $GITHUB_OUTPUT

- name: Build commit plan from commits.txt
id: plan
run: |
python3 - << 'PY'
import sys, os, json, pathlib
snap = pathlib.Path("/tmp/snap")
ct = (snap/"commits.txt")
mappings = []
if ct.exists():
data = ct.read_text(encoding="utf-8").splitlines()
seps = ["—","–","->",":","|"] # EM DASH first
idx = 0
last_idx = {}
parsed = []
for line in data:
s=line.strip()
if not s or s.startswith("#"):
idx+=1; continue
left=None; right=None; sep_used=None
for sep in seps:
if sep in s:
parts=s.split(sep,1)
left=parts[0].strip(); right=parts[1].strip(); sep_used=sep; break
if left is None or right is None or not left:
idx+=1; continue
parsed.append((left,right,idx))
last_idx[left]=idx
idx+=1
# Keep only last occurrence, preserve order by that last index
keep = {}
for pth,msg,i in parsed:
if last_idx.get(pth)==i:
keep[pth]=(msg,i)
plan = sorted([(pth,msg_i[0],msg_i[1]) for pth,msg_i in keep.items()], key=lambda t:t[2])
# write plan file: path|||message
out = snap.parent/"plan.txt"
with out.open("w", encoding="utf-8") as f:
for pth,msg,_i in plan:
f.write(f"{pth}|||{msg}\n")
else:
# no commits.txt; create empty plan
(snap.parent/"plan.txt").write_text("", encoding="utf-8")
PY

- name: Replay commits from commits.txt
run: |
set -euo pipefail
touch /tmp/already.txt /tmp/skipped.txt
PLAN="/tmp/plan.txt"
[ -f "$PLAN" ] || PLAN="/tmp/plan.txt"; # created by previous step
# If plan.txt wasn’t created, create it now (empty)
[ -f "$PLAN" ] || : > "$PLAN"

while IFS= read -r line; do
[ -n "$line" ] || continue
path="${line%%|||*}"
msg="${line#*|||}"
if [ -f "/tmp/snap/$path" ]; then
mkdir -p "$(dirname -- "$path")"
cp -f "/tmp/snap/$path" "$path"
git add -- "$path"
git commit -m "$msg"
echo "$path" >> /tmp/already.txt
else
echo "$path" >> /tmp/skipped.txt
fi
done < /tmp/plan.txt

- name: Commit remaining files (not in commits.txt)
run: |
set -euo pipefail
cd /tmp/snap
# list all files including dotfiles (exclude .git if present)
find . -type f ! -path './.git/*' -print0 | xargs -0 -I{} realpath --relative-to=/tmp/snap "{}" | sort -u > /tmp/all.txt
cd -
sort -u /tmp/already.txt > /tmp/already.sorted || true
comm -23 /tmp/all.txt /tmp/already.sorted > /tmp/remaining.txt || true

while IFS= read -r path; do
[ -n "$path" ] || continue
mkdir -p "$(dirname -- "$path")"
cp -f "/tmp/snap/$path" "$path"
git add -- "$path"
# short, conventional subject
base="$(basename -- "$path")"
git commit -m "Add ${base} (${path})"
done < /tmp/remaining.txt

- name: Push replay branch
run: |
git push -u origin "${{ steps.replay.outputs.branch }}"
echo "compare=https://github.com/${{ github.repository }}/compare/${{ github.event.inputs.default_branch }}...${{ steps.replay.outputs.branch }}" >> $GITHUB_OUTPUT
11 changes: 8 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
# Ignore vendor and environment files
/vendor/
# Ignore environment files
/.env
/.env.testing
/.DS_Store

# Ignore logs and cache
logs/
*.log
/storage/
/vendor/

# Ignore test output
/phpunit.xml
Expand All @@ -16,3 +17,7 @@ logs/
.idea/
.vscode/
Thumbs.db
*.swp
*.swo
*~
.*.swp
Loading