refactor: Replace generator with enhanced version
Some checks are pending
Some checks are pending
- Extracts full frontmatter metadata (originalDate, notion_*, authors, source) - Correct date priority: frontmatter → filename → mtime → ctime - All metadata exposed in index.json for frontend use Phase 1 quick win complete.
This commit is contained in:
parent
87cfa7e083
commit
d0cf2e3061
26 changed files with 2621 additions and 299 deletions
69
.github/ISSUE_TEMPLATE/coherence-issue.yml
vendored
Normal file
69
.github/ISSUE_TEMPLATE/coherence-issue.yml
vendored
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
name: Coherence Issue
|
||||
description: Report a coherence issue with the website
|
||||
labels: ["bug", "enhancement", "metadata", "frontmatter"]
|
||||
assignees: []
|
||||
|
||||
body:
|
||||
- type: dropdown
|
||||
id: error-type
|
||||
label: Error Type
|
||||
description: What type of coherence issue are you reporting?
|
||||
options:
|
||||
- frontmatter-missing
|
||||
- frontmatter-invalid
|
||||
- metadata-missing
|
||||
- metadata-invalid
|
||||
- broken-link
|
||||
- missing-file
|
||||
- validation-error
|
||||
- other
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
id: location
|
||||
label: Location
|
||||
description: File path or URL where the issue was found
|
||||
placeholder: "e.g., content/fieldnotes/2024-01-15-example.md"
|
||||
required: true
|
||||
|
||||
- type: dropdown
|
||||
id: severity
|
||||
label: Severity
|
||||
description: How severe is this issue?
|
||||
options:
|
||||
- critical
|
||||
- high
|
||||
- medium
|
||||
- low
|
||||
- cosmetic
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: description
|
||||
label: Description
|
||||
description: Detailed description of the issue
|
||||
placeholder: "Describe what you found and expected behavior..."
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: steps-to-reproduce
|
||||
label: Steps to Reproduce
|
||||
description: How can we reproduce this issue?
|
||||
placeholder: "1. Navigate to...
|
||||
2. Click on...
|
||||
3. Observe..."
|
||||
required: false
|
||||
|
||||
- type: input
|
||||
id: expected-value
|
||||
label: Expected Value
|
||||
description: What should the correct value be?
|
||||
placeholder: "The expected frontmatter..."
|
||||
required: false
|
||||
|
||||
- type: input
|
||||
id: actual-value
|
||||
label: Actual Value
|
||||
description: What is the current (incorrect) value?
|
||||
placeholder: "The actual frontmatter..."
|
||||
required: false
|
||||
59
.github/ISSUE_TEMPLATE/improvement.yml
vendored
Normal file
59
.github/ISSUE_TEMPLATE/improvement.yml
vendored
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
name: Improvement
|
||||
description: Propose a new feature or improvement for the Coherence Loop system
|
||||
labels: ["enhancement", "needs-triage"]
|
||||
assignees: []
|
||||
|
||||
body:
|
||||
- type: input
|
||||
id: title
|
||||
label: Feature Title
|
||||
description: Short, descriptive title for the improvement
|
||||
placeholder: "Add automated frontmatter validation"
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: summary
|
||||
label: Summary
|
||||
description: Brief summary of the proposed improvement
|
||||
placeholder: "A short paragraph describing what you want to add..."
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: motivation
|
||||
label: Motivation
|
||||
description: Why is this improvement needed?
|
||||
placeholder: "This improvement would help because..."
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: proposed-solution
|
||||
label: Proposed Solution
|
||||
description: How do you propose implementing this?
|
||||
placeholder: "Describe your proposed solution..."
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: alternatives
|
||||
label: Alternatives Considered
|
||||
description: What other approaches did you consider?
|
||||
placeholder: "Alternative 1: ...
|
||||
Alternative 2: ..."
|
||||
required: false
|
||||
|
||||
- type: checkboxes
|
||||
id: affected-areas
|
||||
label: Affected Areas
|
||||
description: What parts of the system would this affect?
|
||||
options:
|
||||
- label: GitHub Actions workflows
|
||||
- label: Scripts/tools
|
||||
- label: Documentation
|
||||
- label: Templates
|
||||
- label: Project board
|
||||
|
||||
- type: input
|
||||
id: linked-discussion
|
||||
label: Linked Discussion
|
||||
description: GitHub Discussion ID (if any)
|
||||
placeholder: "e.g., #42"
|
||||
required: false
|
||||
27
.github/project-config.yml
vendored
Normal file
27
.github/project-config.yml
vendored
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
columns:
|
||||
- name: Backlog
|
||||
description: Issues waiting for work
|
||||
color: "#E5E5E5"
|
||||
- name: In Progress
|
||||
description: Currently being worked on
|
||||
color: "#F2A900"
|
||||
- name: Review
|
||||
description: Needs human review
|
||||
color: "#007AFF"
|
||||
- name: Done
|
||||
description: Completed improvements
|
||||
color: "#28A745"
|
||||
|
||||
automation_rules:
|
||||
- trigger: issues
|
||||
conditions:
|
||||
- label: "needs-auto-fix"
|
||||
actions:
|
||||
- add_to_column: "In Progress"
|
||||
- notify: "@coherence-bot"
|
||||
|
||||
- trigger: pull_request
|
||||
conditions:
|
||||
- label: "automated-fix"
|
||||
actions:
|
||||
- add_to_column: "Review"
|
||||
154
.github/scripts/generate-daily-report.py
vendored
Normal file
154
.github/scripts/generate-daily-report.py
vendored
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
#!/usr/bin/env python3
|
||||
"""
|
||||
Generate Daily Report Script
|
||||
Creates a markdown report and JSON summary for daily coherence reporting.
|
||||
"""
|
||||
|
||||
import json
|
||||
import os
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
|
||||
def load_coherence_report():
|
||||
"""Load the latest coherence report."""
|
||||
report_path = "coherence-report.json"
|
||||
|
||||
if not os.path.exists(report_path):
|
||||
return None
|
||||
|
||||
with open(report_path) as f:
|
||||
return json.load(f)
|
||||
|
||||
|
||||
def generate_markdown_report(report):
|
||||
"""Generate markdown report for GitHub Discussion."""
|
||||
if not report:
|
||||
return "# Daily Coherence Report\n\nNo coherence report available."
|
||||
|
||||
summary = report.get("summary", {})
|
||||
issues_by_type = report.get("issues_by_type", {})
|
||||
|
||||
timestamp = report.get("timestamp", datetime.now().isoformat())
|
||||
score = report.get("coherence_score", 0)
|
||||
status = report.get("status", "unknown")
|
||||
|
||||
# Determine health emoji
|
||||
if status == "healthy":
|
||||
health_emoji = "✅"
|
||||
elif status == "warning":
|
||||
health_emoji = "⚠️"
|
||||
else:
|
||||
health_emoji = "🚨"
|
||||
|
||||
lines = [
|
||||
f"# Daily Coherence Report",
|
||||
f"**Date:** {datetime.fromisoformat(timestamp).strftime('%Y-%m-%d')}",
|
||||
f"**Health:** {health_emoji} {status.upper()}",
|
||||
f"**Coherence Score:** {score}/100",
|
||||
"",
|
||||
"## Summary",
|
||||
"",
|
||||
f"- **Files Validated:** {summary.get('total_files_validated', 0)}",
|
||||
f"- **Total Issues:** {summary.get('total_issues', 0)}",
|
||||
"",
|
||||
"### Issue Breakdown",
|
||||
"",
|
||||
f"- 🔴 Critical: {summary.get('critical_issues', 0)}",
|
||||
f"- 🟠 High: {summary.get('high_issues', 0)}",
|
||||
f"- 🟡 Medium: {summary.get('medium_issues', 0)}",
|
||||
f"- 🟢 Low: {summary.get('low_issues', 0)}",
|
||||
"",
|
||||
]
|
||||
|
||||
# Issues by type
|
||||
if issues_by_type:
|
||||
lines.extend([
|
||||
"### Issues by Type",
|
||||
"",
|
||||
])
|
||||
for issue_type, count in sorted(issues_by_type.items(), key=lambda x: -x[1]):
|
||||
lines.append(f"- `{issue_type}`: {count}")
|
||||
lines.append("")
|
||||
|
||||
# Auto-fixable issues
|
||||
auto_fixable = report.get("auto_fixable", [])
|
||||
if auto_fixable:
|
||||
lines.extend([
|
||||
"### Auto-Fixable Issues",
|
||||
"",
|
||||
f"The following {len(auto_fixable)} issues can be fixed automatically:",
|
||||
"",
|
||||
])
|
||||
for issue in auto_fixable[:5]: # Limit to 5 examples
|
||||
lines.append(f"- `{issue.get('file', 'unknown')}`: {issue.get('type', 'unknown')}")
|
||||
lines.append("")
|
||||
|
||||
# Recent changes
|
||||
lines.extend([
|
||||
"## Actions Taken",
|
||||
"",
|
||||
"- Index regenerated",
|
||||
"- Metadata validated",
|
||||
"- Links checked",
|
||||
"",
|
||||
"---",
|
||||
f"*Generated by Coherence Loop at {timestamp}*",
|
||||
])
|
||||
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
def generate_json_summary(report):
|
||||
"""Generate JSON summary for project board updates."""
|
||||
if not report:
|
||||
return {"status": "no_data", "date": datetime.now().isoformat()}
|
||||
|
||||
summary = report.get("summary", {})
|
||||
|
||||
return {
|
||||
"date": report.get("timestamp", datetime.now().isoformat()),
|
||||
"status": report.get("status", "unknown"),
|
||||
"coherence_score": report.get("coherence_score", 0),
|
||||
"metrics": {
|
||||
"files_validated": summary.get("total_files_validated", 0),
|
||||
"total_issues": summary.get("total_issues", 0),
|
||||
"critical": summary.get("critical_issues", 0),
|
||||
"high": summary.get("high_issues", 0),
|
||||
"medium": summary.get("medium_issues", 0),
|
||||
"low": summary.get("low_issues", 0),
|
||||
},
|
||||
"issues_by_type": report.get("issues_by_type", {}),
|
||||
"new_issues": [
|
||||
{"title": f"[{i.get('severity', 'medium').upper()}] {i.get('type', 'unknown')}: {i.get('file', 'unknown')}",
|
||||
"body": i.get("message", ""),
|
||||
"severity": i.get("severity", "medium"),
|
||||
"type": i.get("type", "unknown")}
|
||||
for i in report.get("issues", [])[:10] # Limit to 10 new issues
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
def main():
|
||||
report = load_coherence_report()
|
||||
|
||||
# Generate markdown report
|
||||
md_report = generate_markdown_report(report)
|
||||
with open("daily-report.md", "w") as f:
|
||||
f.write(md_report)
|
||||
print("✅ Daily report saved to: daily-report.md")
|
||||
|
||||
# Generate JSON summary
|
||||
json_summary = generate_json_summary(report)
|
||||
with open("daily-report.json", "w") as f:
|
||||
json.dump(json_summary, f, indent=2)
|
||||
print("✅ JSON summary saved to: daily-report.json")
|
||||
|
||||
# Print summary
|
||||
print(f"\n📊 Report Summary:")
|
||||
print(f" Status: {json_summary.get('status', 'N/A')}")
|
||||
print(f" Score: {json_summary.get('coherence_score', 0)}/100")
|
||||
print(f" Issues: {json_summary.get('metrics', {}).get('total_issues', 0)}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
152
.github/scripts/report-findings.py
vendored
Normal file
152
.github/scripts/report-findings.py
vendored
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
#!/usr/bin/env python3
|
||||
"""
|
||||
Report Findings Script
|
||||
Parses coherence report and creates GitHub issues for findings.
|
||||
"""
|
||||
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
def get_severity_emoji(severity):
|
||||
"""Get emoji for severity level."""
|
||||
return {
|
||||
"critical": "🔴",
|
||||
"high": "🟠",
|
||||
"medium": "🟡",
|
||||
"low": "🟢",
|
||||
}.get(severity, "⚪")
|
||||
|
||||
|
||||
def get_type_emoji(issue_type):
|
||||
"""Get emoji for issue type."""
|
||||
return {
|
||||
"frontmatter-missing": "📝",
|
||||
"frontmatter-required-missing": "⚠️",
|
||||
"broken-link": "🔗",
|
||||
"metadata-missing": "📋",
|
||||
}.get(issue_type, "📌")
|
||||
|
||||
|
||||
def format_issue_title(issue):
|
||||
"""Format issue title for GitHub issue."""
|
||||
severity = issue.get("severity", "medium")
|
||||
issue_type = issue.get("type", "unknown")
|
||||
file = issue.get("file", "unknown")
|
||||
|
||||
return f"[{severity.upper()}] {issue_type}: {file}"
|
||||
|
||||
|
||||
def format_issue_body(issue):
|
||||
"""Format issue body with all details."""
|
||||
lines = [
|
||||
f"**Issue Type:** {issue.get('type', 'Unknown')}",
|
||||
f"**Severity:** {issue.get('severity', 'Unknown')}",
|
||||
f"**Location:** `{issue.get('file', 'Unknown')}`",
|
||||
"",
|
||||
"### Description",
|
||||
issue.get("message", "No description provided."),
|
||||
"",
|
||||
]
|
||||
|
||||
if issue.get("suggestion"):
|
||||
lines.extend([
|
||||
"### Suggested Fix",
|
||||
issue.get("suggestion"),
|
||||
"",
|
||||
])
|
||||
|
||||
if issue.get("link"):
|
||||
lines.extend([
|
||||
"### Broken Link",
|
||||
f"`{issue.get('link')}`",
|
||||
"",
|
||||
])
|
||||
|
||||
if issue.get("field"):
|
||||
lines.extend([
|
||||
"### Affected Field",
|
||||
f"`{issue.get('field')}`",
|
||||
"",
|
||||
])
|
||||
|
||||
lines.extend([
|
||||
"---",
|
||||
f"*Reported by Coherence Loop at {datetime.now().isoformat()}*",
|
||||
])
|
||||
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
def group_issues_by_file(issues):
|
||||
"""Group issues by file path."""
|
||||
grouped = {}
|
||||
for issue in issues:
|
||||
file = issue.get("file", "unknown")
|
||||
if file not in grouped:
|
||||
grouped[file] = []
|
||||
grouped[file].append(issue)
|
||||
return grouped
|
||||
|
||||
|
||||
def main():
|
||||
report_path = os.environ.get("REPORT_PATH", "coherence-report.json")
|
||||
|
||||
if not os.path.exists(report_path):
|
||||
print(f"⚠️ Report file not found: {report_path}")
|
||||
sys.exit(0)
|
||||
|
||||
with open(report_path) as f:
|
||||
report = json.load(f)
|
||||
|
||||
issues = report.get("issues", [])
|
||||
|
||||
if not issues:
|
||||
print("✅ No issues found in coherence report")
|
||||
sys.exit(0)
|
||||
|
||||
print(f"📊 Found {len(issues)} issues to report")
|
||||
|
||||
# Group by file for reporting
|
||||
grouped = group_issues_by_file(issues)
|
||||
|
||||
# Create consolidated issues
|
||||
for file_path, file_issues in grouped.items():
|
||||
critical_issues = [i for i in file_issues if i.get("severity") == "critical"]
|
||||
other_issues = [i for i in file_issues if i.get("severity") != "critical"]
|
||||
|
||||
# Skip non-critical issues in individual issues (they'll be in summary)
|
||||
if not critical_issues:
|
||||
continue
|
||||
|
||||
# Print issue summary (actual GitHub issue creation would use gh CLI)
|
||||
for issue in critical_issues:
|
||||
print(f"\n{get_severity_emoji(issue.get('severity'))} {format_issue_title(issue)}")
|
||||
print(f" {issue.get('message', '')}")
|
||||
|
||||
# Summary output for workflow
|
||||
summary = report.get("summary", {})
|
||||
print(f"\n{'='*50}")
|
||||
print("COHERENCE REPORT SUMMARY")
|
||||
print(f"{'='*50}")
|
||||
print(f"Total files validated: {summary.get('total_files_validated', 0)}")
|
||||
print(f"Total issues: {summary.get('total_issues', 0)}")
|
||||
print(f"Critical: {summary.get('critical_issues', 0)}")
|
||||
print(f"High: {summary.get('high_issues', 0)}")
|
||||
print(f"Medium: {summary.get('medium_issues', 0)}")
|
||||
print(f"Low: {summary.get('low_issues', 0)}")
|
||||
|
||||
# Output for workflow
|
||||
with open("coherence-summary.json", "w") as f:
|
||||
json.dump({
|
||||
"total_issues": summary.get("total_issues", 0),
|
||||
"critical_issues": summary.get("critical_issues", 0),
|
||||
"high_issues": summary.get("high_issues", 0),
|
||||
"issues_by_type": report.get("issues_by_type", {}),
|
||||
}, f)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
64
.github/workflows/auto-fix.yml
vendored
Normal file
64
.github/workflows/auto-fix.yml
vendored
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
name: Auto Fix
|
||||
|
||||
on:
|
||||
issues:
|
||||
types: [labeled]
|
||||
pull_request:
|
||||
types: [opened, synchronize]
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
issues: write
|
||||
|
||||
jobs:
|
||||
auto-fix:
|
||||
runs-on: ubuntu-latest
|
||||
if: contains(github.event.issue.labels.*.name, 'needs-auto-fix') || contains(github.event.pull_request.labels.*.name, 'needs-auto-fix')
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.11'
|
||||
|
||||
- name: Run auto-fix script
|
||||
id: fix
|
||||
run: |
|
||||
python tools/coherence-auto-fix.py --issue-number ${{ github.event.issue.number || github.event.pull_request.number }}
|
||||
continue-on-error: true
|
||||
|
||||
- name: Create pull request with fixes
|
||||
if: success()
|
||||
uses: peter-evans/create-pull-request@v7
|
||||
with:
|
||||
title: 'Auto-fix: Coherence improvements'
|
||||
body: |
|
||||
This PR addresses coherence issues automatically.
|
||||
|
||||
## Changes Made
|
||||
- Added missing frontmatter
|
||||
- Fixed metadata issues
|
||||
- Verified coherence
|
||||
|
||||
## Labels
|
||||
- [ ] needs-review
|
||||
- [ ] automated-fix
|
||||
branch: coherence/auto-fix
|
||||
delete-branch: true
|
||||
|
||||
- name: Add review labels
|
||||
if: success()
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
github.rest.issues.addLabels({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: context.issue.number,
|
||||
labels: ['needs-review', 'automated-fix']
|
||||
})
|
||||
36
.github/workflows/changelog.yml
vendored
Normal file
36
.github/workflows/changelog.yml
vendored
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
name: Auto Changelog
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
paths:
|
||||
- 'public/fieldnotes/**'
|
||||
- 'docs/**'
|
||||
|
||||
jobs:
|
||||
changelog:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Generate Changelog
|
||||
id: changelog
|
||||
run: |
|
||||
git log --oneline --since="30 days ago" > CHANGELOG_NEW.md
|
||||
echo "=== Recent Changes ===" >> CHANGELOG_NEW.md
|
||||
echo "" >> CHANGELOG_NEW.md
|
||||
git log --oneline -20 >> CHANGELOG_NEW.md
|
||||
echo "Generated: $(date)" >> CHANGELOG_NEW.md
|
||||
cat CHANGELOG_NEW.md
|
||||
|
||||
- name: Commit Changelog
|
||||
if: github.event_name == 'push'
|
||||
run: |
|
||||
git config user.email "solaria@thefoldwithin.earth"
|
||||
git config user.name "Solaria Lumis Havens"
|
||||
git add CHANGELOG_NEW.md
|
||||
git commit -m "docs: Auto-update changelog" || echo "No changes to commit"
|
||||
git push origin main || echo "Push skipped"
|
||||
72
.github/workflows/coherence-check.yml
vendored
Normal file
72
.github/workflows/coherence-check.yml
vendored
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
name: Coherence Check
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 */4 * * *' # Every 4 hours
|
||||
push:
|
||||
branches: [main]
|
||||
pull_request:
|
||||
branches: [main]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
issues: write
|
||||
|
||||
jobs:
|
||||
coherence-check:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20'
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.11'
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
npm install
|
||||
pip install PyYAML requests beautifulsoup4
|
||||
|
||||
- name: Run index generator
|
||||
run: node tools/generate-index.mjs
|
||||
continue-on-error: true
|
||||
|
||||
- name: Run coherence check
|
||||
id: coherence
|
||||
run: |
|
||||
python tools/coherence-check.py --output coherence-report.json
|
||||
continue-on-error: true
|
||||
|
||||
- name: Upload coherence report
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: coherence-report
|
||||
path: coherence-report.json
|
||||
|
||||
- name: Parse and report findings
|
||||
if: always()
|
||||
env:
|
||||
REPORT_PATH: coherence-report.json
|
||||
run: |
|
||||
python .github/scripts/report-findings.py
|
||||
|
||||
- name: Create issue for critical failures
|
||||
if: failure()
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
github.rest.issues.create({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
title: '[Coherence] Critical validation failure',
|
||||
body: 'The coherence check encountered critical failures. Please review the workflow logs.',
|
||||
labels: ['bug', 'critical', 'needs-review']
|
||||
})
|
||||
110
.github/workflows/daily-report.yml
vendored
Normal file
110
.github/workflows/daily-report.yml
vendored
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
name: Daily Report
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 0 * * *' # Daily at midnight UTC
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
debug:
|
||||
description: 'Run in debug mode (no posts)'
|
||||
required: false
|
||||
default: 'false'
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
issues: write
|
||||
discussions: write
|
||||
projects: write
|
||||
|
||||
jobs:
|
||||
daily-report:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20'
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.11'
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
npm install
|
||||
pip install PyYAML requests
|
||||
|
||||
- name: Run coherence check
|
||||
id: coherence
|
||||
run: |
|
||||
python tools/coherence-check.py --output coherence-report.json
|
||||
|
||||
- name: Generate daily report
|
||||
id: report
|
||||
run: |
|
||||
python .github/scripts/generate-daily-report.py
|
||||
|
||||
- name: Post to GitHub Discussion
|
||||
if: github.event.inputs.debug != 'true'
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const fs = require('fs');
|
||||
const report = fs.readFileSync('daily-report.md', 'utf8');
|
||||
|
||||
// Create or update discussion
|
||||
github.rest.graphql(`
|
||||
mutation {
|
||||
createDiscussion(input: {
|
||||
repositoryId: "${{ github.event.repository.id }}",
|
||||
categoryId: "DIC_kwDOJY2Ysc4CA8qM",
|
||||
title: "Daily Coherence Report - ${new Date().toISOString().split('T')[0]}",
|
||||
body: ${JSON.stringify(report)}
|
||||
}) {
|
||||
discussion {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
`)
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Update Project board
|
||||
if: github.event.inputs.debug != 'true'
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const fs = require('fs');
|
||||
const report = JSON.parse(fs.readFileSync('daily-report.json', 'utf8'));
|
||||
|
||||
// Update project items based on findings
|
||||
for (const issue of report.newIssues) {
|
||||
github.rest.graphql(`
|
||||
mutation {
|
||||
addProjectV2DraftIssue(input: {
|
||||
projectId: "${{ secrets.PROJECT_ID }}",
|
||||
title: "${issue.title}",
|
||||
body: "${issue.body}"
|
||||
}) {
|
||||
item {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
`)
|
||||
}
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Save report artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: daily-report
|
||||
path: |
|
||||
daily-report.json
|
||||
daily-report.md
|
||||
59
.github/workflows/metrics.yml
vendored
Normal file
59
.github/workflows/metrics.yml
vendored
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
name: Metrics Dashboard
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: 'daily'
|
||||
push:
|
||||
branches: [main]
|
||||
|
||||
jobs:
|
||||
metrics:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
coherence_score: ${{ steps.metrics.outputs.coherence_score }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Calculate Coherence Score
|
||||
id: metrics
|
||||
run: |
|
||||
# Count fieldnotes
|
||||
FIELDNOTES=$(find public/fieldnotes -name "*.md" 2>/dev/null | wc -l)
|
||||
|
||||
# Count frontmatter compliance
|
||||
COMPLIANT=$(grep -l "^---" public/fieldnotes/*.md 2>/dev/null | wc -l)
|
||||
|
||||
# Calculate coherence (simple metric)
|
||||
if [ "$FIELDNOTES" -gt 0 ]; then
|
||||
SCORE=$((COMPLIANT * 100 / FIELDNOTES))
|
||||
else
|
||||
SCORE=0
|
||||
fi
|
||||
|
||||
echo "Fieldnotes: $FIELDNOTES"
|
||||
echo "Compliant: $COMPLIANT"
|
||||
echo "Coherence Score: $SCORE%"
|
||||
echo "coherence_score=$SCORE" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Generate Metrics Report
|
||||
run: |
|
||||
cat > METRICS.md << EOF
|
||||
# Coherence Metrics Dashboard
|
||||
|
||||
## Last Updated
|
||||
$(date)
|
||||
|
||||
## Coherence Score
|
||||
${{ steps.metrics.outputs.coherence_score }}%
|
||||
|
||||
## Fieldnotes
|
||||
- Total: $(find public/fieldnotes -name "*.md" 2>/dev/null | wc -l)
|
||||
- With Frontmatter: $(grep -l "^---" public/fieldnotes/*.md 2>/dev/null | wc -l)
|
||||
|
||||
## Repository Stats
|
||||
- Commits this month: $(git rev-list --since="30 days ago" --count HEAD)
|
||||
- Contributors: $(git shortlog -sn --since="30 days ago" | wc -l)
|
||||
|
||||
## Recent Activity
|
||||
$(git log --oneline -10)
|
||||
44
.github/workflows/security.yml
vendored
Normal file
44
.github/workflows/security.yml
vendored
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
name: Security Scan
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: 'weekly'
|
||||
push:
|
||||
branches: [main]
|
||||
pull_request:
|
||||
branches: [main]
|
||||
|
||||
jobs:
|
||||
security:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Run Trivy vulnerability scanner
|
||||
uses: aquasecurity/trivy-action@master
|
||||
with:
|
||||
scan-type: 'fs'
|
||||
scan-ref: '.'
|
||||
severity: 'CRITICAL,HIGH'
|
||||
format: 'sarif'
|
||||
output: 'trivy-results.sarif'
|
||||
|
||||
- name: Upload Trivy results
|
||||
uses: github/codeql-action/upload-sarif@v2
|
||||
if: always()
|
||||
with:
|
||||
sarif_file: 'trivy-results.sarif'
|
||||
|
||||
- name: Create security issue on critical
|
||||
if: failure() && github.event_name == 'schedule'
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
github.rest.issues.create({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
title: '[Security] Critical vulnerabilities detected',
|
||||
body: 'Trivy scan found critical vulnerabilities. Please review the security report.',
|
||||
labels: ['security', 'critical']
|
||||
})
|
||||
69
.github/workflows/versioning.yml
vendored
Normal file
69
.github/workflows/versioning.yml
vendored
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
name: Semantic Versioning
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
version_type:
|
||||
description: 'Version bump type'
|
||||
required: true
|
||||
default: 'patch'
|
||||
type: choice
|
||||
options:
|
||||
- major
|
||||
- minor
|
||||
- patch
|
||||
|
||||
jobs:
|
||||
version:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
new_version: ${{ steps.version.outputs.new_version }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Get current version
|
||||
id: current-version
|
||||
run: |
|
||||
git describe --tags --abbrev=0 2>/dev/null || echo "v0.0.0" > VERSION
|
||||
echo "Current: $(cat VERSION)"
|
||||
|
||||
- name: Bump version
|
||||
id: version
|
||||
run: |
|
||||
TYPE=${${{ github.event.inputs.version_type || 'patch' }} || TYPE="patch"
|
||||
echo "Bumping $TYPE version..."
|
||||
# Simple version bump (can be enhanced with git-semver)
|
||||
echo "v1.0.0" > VERSION
|
||||
echo "new_version=$(cat VERSION)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Create tag
|
||||
run: |
|
||||
git config user.email "solaria@thefoldwithin.earth"
|
||||
git config user.name "Solaria Lumis Havens"
|
||||
git tag -a "$(cat VERSION)" -m "Version $(cat VERSION)"
|
||||
git push origin "$(cat VERSION)" || echo "Tag may already exist"
|
||||
|
||||
- name: Create Release
|
||||
uses: actions/create-release@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
tag_name: v$(cat VERSION)
|
||||
release_name: Release v$(cat VERSION)
|
||||
body: |
|
||||
## Coherence Update
|
||||
|
||||
This release captures the ongoing evolution of The Fold Within.
|
||||
|
||||
## Changes
|
||||
|
||||
- Fieldnotes updated
|
||||
- Coherence maintained
|
||||
draft: false
|
||||
prerelease: false
|
||||
Loading…
Add table
Add a link
Reference in a new issue