diff --git a/.claude/settings.local.json b/.claude/settings.local.json index 22e7242e6..ac9d961b6 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -2,6 +2,7 @@ "permissions": { "allow": [ "Bash(python:*)", + "Bash(python3:*)", "Bash(grep:*)", "Bash(find:*)", "Bash(rg:*)", @@ -25,10 +26,33 @@ "Bash(yarn build)", "Bash(git rm:*)", "Bash(git checkout:*)", - "Bash(awk:*)" + "Bash(awk:*)", + "Bash(node:*)", + "Bash(lsof:*)", + "Bash(xargs kill:*)", + "Bash(cat:*)", + "WebSearch", + "Bash(cargo check:*)", + "Bash(cargo build:*)", + "Bash(claude:*)", + "Bash(npm update:*)", + "Bash(npm audit:*)", + "Bash(npm install:*)", + "Bash(npm run build:*)", + "WebFetch(domain:raw.githubusercontent.com)", + "WebFetch(domain:www.ars.usda.gov)", + "Bash(for dir in cv/*/)", + "Bash(do [ -f \"$dir/index.html\" ])", + "Bash(done)", + "Bash(while read dir)", + "Bash(do [ -d \"cv/$dir\" ]:*)", + "Bash([ -f \"cv/$dir/detailed.json\" ])", + "Bash([ -d \"cv/$dir\" ])", + "Bash(git config:*)", + "WebFetch(domain:en.wikipedia.org)" ], "deny": [ "Read(../**)" ] } -} \ No newline at end of file +} diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 000000000..62f0986b2 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,164 @@ +# Git files and directories +.git +.gitignore +.gitmodules +.gitattributes +.github/ + +# Docker files (avoid copying Docker config into the image) +Dockerfile +docker-compose.yml +docker-compose*.yml +.dockerignore +docker/ + +# CI/CD and tooling +.claude/ +.vscode/ +.idea/ + +# Extra repos that are not submodules +apps +community +community-data +community-timelines +data-commons +data-pipeline +display +explore +membersense +modelearth.github.io +nisar +panels +products-big-files-to-delete +reality.streamlit* +recycling +requests +resources +trade-data +topojson +useeio +useeio-json +useeio.js +wiki + +# Configuration files +config +config/settings.js +config/keys.json +config/.env +settings.local.json +.siterepos + +# Auth keys and secrets +*.key +*.pem +env/* +.env +.env.* +!.env.example +*.env + +# Logs +*.log +logs/ +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Python +__pycache__/ +*.py[cod] +*$py.class +*.so +.Python +*.egg +*.egg-info/ +dist/ +build/ +*.whl +pip-log.txt +pip-delete-this-directory.txt +.pytest_cache/ +.mypy_cache/ +.dmypy.json +dmypy.json +venv/ +env/ +ENV/ +.venv + +# Testing and coverage +coverage/ +.nyc_output +*.lcov +htmlcov/ +.tox/ +.coverage +.coverage.* +nosetests.xml +coverage.xml +*.cover + +# Dependencies (install fresh in Docker) +node_modules/ +bower_components/ + +# Build outputs and cache +.next/ +.nuxt/ +.cache/ +.parcel-cache/ +.vuepress/dist/ +out/ +dist/ +build/ +target/ + +# Temporary files +*.tmp +*.temp +*.swp +*.swo +*~ + +# OS generated files +.DS_Store +.DS_Store? +._* +.Spotlight-V100 +.Trashes +ehthumbs.db +Thumbs.db +Desktop.ini + +# IDE files +*.sublime-project +*.sublime-workspace +.idea/ +*.iml +.vscode/ +*.code-workspace + +# Optional npm/yarn files +.npm +.yarn-integrity +.pnp.* +.node_repl_history + +# Serverless +.serverless/ + +# Other +.nojekyll +*.tgz +*.bak +*.backup +codechat-vectors/ +grid/ diff --git a/.env.example.old b/.env.example.old new file mode 100644 index 000000000..475db07ca --- /dev/null +++ b/.env.example.old @@ -0,0 +1,9 @@ +# Ideally not using the following since we have 3 databases: COMMONS, EXIOBASE, LOCATIONS + +# Environment variables for Docker Compose +# These are used for variable substitution in docker-compose.yml + +# PostgreSQL credentials (used for POSTGRES_USER and POSTGRES_PASSWORD) +POSTGRES_DEFAULT_USER=postgres +POSTGRES_DEFAULT_PASSWORD=yourpassword +POSTGRES_DEFAULT_DB=postgres \ No newline at end of file diff --git a/.github/workflows/vector_db_sync.yml b/.github/workflows/vector_db_sync.yml new file mode 100644 index 000000000..669fb6b87 --- /dev/null +++ b/.github/workflows/vector_db_sync.yml @@ -0,0 +1,62 @@ +name: VectorDB Sync + +on: + pull_request: + types: [closed] + push: + branches: [ main ] + +jobs: + sync: + if: | + (github.event_name == 'pull_request' && github.event.pull_request.merged == true && github.event.pull_request.base.ref == 'main') || + (github.event_name == 'push' && github.ref == 'refs/heads/main') + runs-on: ubuntu-latest + + steps: + - name: Checkout repo with submodules + uses: actions/checkout@v4 + with: + fetch-depth: 0 + submodules: recursive + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.11" + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r chat/ingestion/requirements.txt + + - name: Run VectorDB Sync + env: + PINECONE_API_KEY: ${{ secrets.PINECONE_API_KEY }} + VOYAGE_API_KEY: ${{ secrets.VOYAGE_API_KEY }} + run: python chat/ingestion/vector_db_sync.py --skip-on-missing-keys + + - name: Error summary + if: always() + shell: bash + run: | + if [ -f chat/.vector_sync_errors.jsonl ]; then + { + echo "## Vector Sync Errors"; + echo; + echo '```jsonl'; + tail -n 200 chat/.vector_sync_errors.jsonl; + echo '```'; + } >> "$GITHUB_STEP_SUMMARY" + else + echo "No errors file present." + fi + + - name: Upload VectorDB Sync errors + if: always() + uses: actions/upload-artifact@v4 + with: + name: vector-sync-errors + path: chat/.vector_sync_errors.jsonl + if-no-files-found: ignore + retention-days: 7 diff --git a/.github/workflows/vector_sync.yml b/.github/workflows/vector_sync.yml deleted file mode 100644 index 1bbd16b10..000000000 --- a/.github/workflows/vector_sync.yml +++ /dev/null @@ -1,90 +0,0 @@ -name: VectorDB Sync - -on: - pull_request: - types: [closed] - push: - branches: [ main ] - -jobs: - sync: - if: | - (github.event_name == 'pull_request' && github.event.pull_request.merged == true && github.event.pull_request.base.ref == 'main') || - (github.event_name == 'push' && github.ref == 'refs/heads/main') - runs-on: ubuntu-latest - - steps: - - name: Checkout repo with submodules - uses: actions/checkout@v4 - with: - fetch-depth: 0 - submodules: recursive - - - name: Set up Python - uses: actions/setup-python@v5 - with: - python-version: "3.11" - - - name: Install dependencies - run: | - python -m pip install --upgrade pip - # Try repo-specific requirements - pip install -r codechat/requirements.txt || true - # Core sync deps (serverless Pinecone SDK) - pip install --upgrade tiktoken tree_sitter tqdm pyyaml pandas pinecone openai - - - name: Run VectorDB Sync (commit-range) - env: - PINECONE_API_KEY: ${{ secrets.PINECONE_API_KEY }} - OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} - shell: bash - run: | - set -euo pipefail - # Skip if sync script not present (e.g., codechat PR not merged yet) - if [ ! -f codechat/vectordb_sync.py ]; then - echo "[skip] codechat/vectordb_sync.py not found; skipping VectorDB sync." - exit 0 - fi - - # Skip if required secrets not provided - if [ -z "${PINECONE_API_KEY:-}" ] || [ -z "${OPENAI_API_KEY:-}" ]; then - echo "[skip] Missing PINECONE_API_KEY or OPENAI_API_KEY; skipping VectorDB sync." - exit 0 - fi - if [ "${{ github.event_name }}" = "push" ]; then - BASE="${{ github.event.before }}"; HEAD="${{ github.sha }}" - else - BASE="${{ github.event.pull_request.base.sha }}" - HEAD="${{ github.event.pull_request.merge_commit_sha }}" - if [ -z "$HEAD" ]; then HEAD="${{ github.sha }}"; fi - fi - if [ "$BASE" = "0000000000000000000000000000000000000000" ] || [ -z "$BASE" ]; then - BASE="${HEAD}^" - fi - echo "[info] Sync range: $BASE..$HEAD" - python codechat/vectordb_sync.py --from-commit "$BASE" --to-commit "$HEAD" --repo-root . - - - name: Error summary - if: always() - shell: bash - run: | - if [ -f codechat/.vector_sync_errors.jsonl ]; then - { - echo "## Vector Sync Errors"; - echo; - echo '```jsonl'; - tail -n 200 codechat/.vector_sync_errors.jsonl; - echo '```'; - } >> "$GITHUB_STEP_SUMMARY" - else - echo "No errors file present." - fi - - - name: Upload VectorDB Sync errors - if: always() - uses: actions/upload-artifact@v4 - with: - name: vector-sync-errors - path: codechat/.vector_sync_errors.jsonl - if-no-files-found: ignore - retention-days: 7 diff --git a/.gitignore b/.gitignore index 494f2568b..a2f8b0c2f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,40 +1,19 @@ -# Extra repos that are not submodules -apps -community -community-data -community-timelines -data-commons -data-pipeline -display -explore -membersense -nisar -panels -products-big-files-to-delete -reality.streamlit* -recycling -requests -resources -trade-data -topojson -useeio -useeio-json -useeio.js -wiki - # Configuration files +config config/settings.js config/keys.json config/.env settings.local.json +.claude/settings.local.json # Auth keys and secrets *.key *.pem env/* .env -.env.local -.env.production +.env.* +!.env.example +*.env # Logs *.log @@ -105,4 +84,42 @@ target/ # Backup files *.bak -*.backup \ No newline at end of file +*.backup + +# Extra repos that are not submodules +apps +community +community-data +community-timelines +community-zipcodes +contributors +coreutilities +cv +data-commons +data-pipeline +data-pipeline-garage +*nuclear +display +explore +inspire +membersense +modelearth.github.io +nisar +panels +photos +products-data +products-big-files-to-delete +reality.streamlit* +recycling +requests +resources +setup +storm +swarmui +trade-data +topojson +useeio +useeio-json +useeio.js +wiki +zip \ No newline at end of file diff --git a/.gitmodules b/.gitmodules index 5e3fa3d65..37405874d 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,12 @@ +[submodule "docker"] + path = docker + url = https://github.com/modelearth/docker [submodule "localsite"] path = localsite url = https://github.com/ModelEarth/localsite +[submodule "team"] + path = team + url = https://github.com/ModelEarth/team [submodule "feed"] path = feed url = https://github.com/modelearth/feed @@ -10,30 +16,42 @@ [submodule "home"] path = home url = https://github.com/ModelEarth/home -[submodule "products"] - path = products - url = https://github.com/modelearth/products +[submodule "cloud"] + path = cloud + url = https://github.com/modelearth/cloud +[submodule "chat"] + path = chat + url = https://github.com/modelearth/chat +[submodule "codechat"] + path = codechat + url = https://github.com/modelearth/codechat [submodule "comparison"] path = comparison url = https://github.com/modelearth/comparison -[submodule "team"] - path = team - url = https://github.com/modelearth/team +[submodule "desktop"] + path = desktop + url = https://github.com/ModelEarth/desktop.git +[submodule "grid"] + path = grid + url = https://github.com/modelearth/grid [submodule "realitystream"] path = realitystream url = https://github.com/modelearth/realitystream +[submodule "streamlit"] + path = streamlit + url = https://github.com/modelearth/streamlit +[submodule "products"] + path = products + url = https://github.com/modelearth/products [submodule "projects"] path = projects url = https://github.com/modelearth/projects -[submodule "cloud"] - path = cloud - url = https://github.com/modelearth/cloud -[submodule "codechat"] - path = codechat - url = https://github.com/modelearth/codechat [submodule "exiobase"] path = exiobase url = https://github.com/modelearth/exiobase +[submodule "trade"] + path = trade + url = https://github.com/modelearth/trade [submodule "io"] path = io url = https://github.com/modelearth/io @@ -46,6 +64,6 @@ [submodule "community-forecasting"] path = community-forecasting url = https://github.com/modelearth/community-forecasting -[submodule "products-data"] - path = products-data - url = https://github.com/modelearth/products-data +[submodule "better-auth"] + path = better-auth + url = https://github.com/modelearth/better-auth diff --git a/.siterepos b/.siterepos new file mode 100644 index 000000000..5050bd742 --- /dev/null +++ b/.siterepos @@ -0,0 +1,12 @@ +[siterepo "community"] + path = community + url = https://github.com/modelearth/community +[siterepo "data-pipeline"] + path = data-pipeline + url = https://github.com/modelearth/data-pipeline +[siterepo "trade-data"] + path = trade-data + url = https://github.com/modelearth/trade-data +[siterepo "nisar"] + path = nisar + url = https://github.com/modelearth/nisar \ No newline at end of file diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 000000000..e1abd2de9 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,43 @@ +# AGENTS.md + +This is the equivalent to `CLAUDE.md`. + +Use a modern, clean response design that has rounded corners on boarderless panels. +Each new panel should use the "Panel Menu Toggle System" from localsite/js/localsite.js to place a cirlce icon in its upper right with options for Expand, Close, etc. +Include .dark mode css. Set responsive layouts based on parent div widths rather than browser width. When possible, reuse common css from localsite/css/base.css + +Primary guidance files: +- `/localsite/AGENTS.md` +- `/team/AGENTS.md` + +Submodule overview: +- `codechat/README.md` + +Key standards (from linked AGENTS files): +- HTML: use `/localsite/start/template/index.html` for new pages; include `` except in redirects or template fragments. +- DOM waits: never use `setTimeout` for DOM; use `waitForElm(selector)` from `localsite/js/localsite.js` (confirm it is included first). +- Hash state: prefer `getHash`, `goHash`, `updateHash`, and `hashChangeEvent` from `localsite/js/localsite.js`. +- Paths: never hardcode user-specific paths; use relative paths or repo-root discovery. "Users" and the current user's name or computer name are never included. +- Git: only run push/pull via `./git.sh` and only commit/push when the user explicitly asks. +- **Push scope**: when user says "push [repo]", push ONLY that specific repository. Do not use `git add .` or stage unrelated changes. Examples: + - "push localsite" → push only localsite submodule changes + - "push team" → push only team submodule changes + - "push" or "push all" → push webroot + all submodules via `./git.sh push` + +Claude Code sessions: +- Session history: `~/.claude/history.jsonl` (JSONL format with sessionId, timestamp, display, project) +- Use Python or `jq` to parse efficiently; avoid multiple `awk` attempts on macOS + +Start commands: +- `start server` — starts Python HTTP server and Python backend (not Flask) (`desktop/install/quickstart.sh`) +- `start rust` — Rust API server (from `team` repo) +- `start flask` — starts both `cloud` and `pipeline` +- `start cloud` — Flask for `cloud/run` (RealityStream), local + deploy to Google Cloud +- `start pipeline` — Flask for `data-pipeline/admin` +- `start html` — bare bones without Python (not needed if you ran `start server`) + +Ports: +- `8887` — Python HTTP server (`desktop/install/quickstart.sh`) +- `8081` — Rust API server (from `team` repo) +- `5001` — Data-Pipeline Flask server +- `8100` — Cloud/run Flask server diff --git a/CLAUDE.md b/CLAUDE.md index 8a2cc82bf..5d11e0d8c 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,3 +1,5 @@ # CLAUDE.md -The CLAUDE.md instructions reside in team/CLAUDE.md \ No newline at end of file +"push" always invokes the "./git.sh push" command. + +The CLAUDE.md instructions reside in team/AGENTS.md, localsite/AGENTS.md, data-pipeline/AGENTS.md, and cloud/AGENTS.md \ No newline at end of file diff --git a/PRD.md b/PRD.md new file mode 100644 index 000000000..2738a5e8f --- /dev/null +++ b/PRD.md @@ -0,0 +1,110 @@ +Product Requirements Document: PartnerTools CRM + +1. Executive Summary + +PartnerTools CRM is a high-performance, cost-efficient Customer Relationship Management platform. It aims to replace expensive Salesforce per-user licensing with a JAMstack architecture powered by a Rust API. + +By leveraging the Salesforce -like SuiteCRM SQL table structure aligned with the Microsoft Common Data Model (CDM), the system ensures data interoperability across agencies while reducing infrastructure costs. The platform focuses on speed, type safety, and "write-once, deploy-everywhere" web standards. + +2. Problem Statement + +High Costs: Licensing fees for Salesforce and Dynamics are a significant recurring drain. +Data Silos: Without a shared data language, integrating data from materials, manufacturing, and sales (or agency equivalents) requires custom, expensive implementations. + +Performance: Legacy CRM architectures (monolithic PHP/Java) often suffer from slow load times and security vulnerabilities compared to modern static-first approaches. + +3. Goals & Success Metrics + +Cost Reduction: Reduce CRM operating costs by eliminating per-user fees. +Performance: API response times under 50ms using Rust. +Interoperability: Achieve schema compliance with the Common Data Model (CDM) for core entities (accounts, contacts). + +4. Technical Architecture + +4.1. The Stack (JAMstack) + +Frontend (Markup/JS): A Single Page Application (SPA) served via CDN. +This decouples the web experience from the business logic. +API (The "A"): A REST/GraphQL API built in Rust. +Database: PostgreSQL, structured to mirror SuiteCRM. (See model.earth/profile/crm) + +4.2. Rust API Specification + +See: https://github.com/ModelEarth/team/blob/main/Cargo.toml + +Framework: Actix-web for high-performance, async handling. + +Need to confirm these are the ones used in Cargo.toml link above: +ORM Strategy: SeaORM is recommended over Diesel or SQLx.Rationale: SeaORM is async-native and inspired by SQLAlchemy, allowing for dynamic query construction which is essential for handling complex CRM schemas that may not have 1:1 struct mappings. + +Security: Rust’s memory safety ensures robust handling of sensitive government data. + +5. Data Model & Database Schema + +The database must be similar to the Salesforce-like SuiteCRM naming conventions while mapping conceptually to the Microsoft Common Data Model (CDM) to ensure standard shapes for "accounts" etc. + +5.1. Core Identity & UUIDs + +ID Format: All primary keys must use UUIDs (e.g., 46c35607-bcad-c7f1-1745-558d6b858b27) rather than auto-incrementing integers to facilitate data imports and merging. + +Naming Convention: Table names must be lowercase. + +5.2. Core Tables (CDM Mapped) + +SuiteCRM Table NameCDM Entity EquivalentDescriptionaccountsAccountOrganizations/Agencies. Columns: id (UUID), name, billing\_address\_street, deleted (bool).contactsContactIndividuals. Columns: id, first\_name, last\_name, phone\_mobile.opportunitiesOpportunityGrants/Contracts. Columns: id, amount, sales\_stage.campaignsCampaignOutreach http://initiatives.email\_addressesEmailNormalized email storage. + +5.3. Relationship Schema + +Relationships are managed via distinct join tables rather than database-level foreign key constraints, mirroring SuiteCRM’s logic to allow for application-level handling of "soft deletes". +Many-to-Many Implementation:Table: accounts\_contacts +Query Logic: Rust API must handle joins manually. +Example SQL: SELECT http://accounts.name, contacts.last\_name FROM accounts INNER JOIN accounts\_contacts ON http://accounts.id = accounts\_contacts.account\_id. + +Flex Relate:Fields parent\_type and parent\_id are used to link a record (e.g., a Call) to multiple potential entities (Account, Contact, or Lead). + +5.4. Custom Fields (\_cstm) - TO BE DETERMINED + +To support government-specific data without altering core schemas, custom fields are stored in \_cstm tables joined by id\_c. +Example: If an agency needs an "Age" field for a contact, it is stored in contacts\_cstm.age\_c. +Rust Implementation: The API must automatically perform LEFT JOIN on \_cstm tables when fetching detail views. + +6. Feature Requirements + +6.1. CRM Core +Entity Management: CRUD operations for Accounts, Contacts, Leads, and Opportunities. +Logic Hooks: Rust-based implementation of "Logic Hooks" to trigger actions (e.g., email notifications) on save/update, replacing PHP logic hooks. +Search: ElasticSearch integration for high-speed retrieval of UUID-based records. +6.2. Outlook Replacement (Web Add-in) +To replace the unstable COM add-ins, PartnerTools CRM will implement a Outlook Web Add-in. +Architecture: A side-pane web app running in the Outlook sandbox. +Features:Contextual View: Automatically pulls the CRM Contact record based on the sender\'s email address using the Rust API. + +One-Click Archiving: Button to save email content to the emails table in the CRM. +Manifest Type: Configure strictly as a Web Add-in to prevent installation of legacy COM counterparts. + +7. Migration & Integration Strategy + +7.1. Data Migration +ETL Process: Extract data from Salesforce/Dynamics, transform IDs to UUIDs, and load into the Postgres accounts and contacts tables. + +Schema Extension: Use the CDM's extensibility to map specific government verticals (e.g., Budget, Currency) into the standard model. +7.2. Interoperability +CDM Compliance: By adhering to the CDM metadata system, PartnerTools CRM data can be consumed by Microsoft PowerBI and Azure Data Lake without complex transformation. + +8. Security & Compliance + +Authentication: Better-auth OAuth2 implementation. + +Authorization: Role-based access control (RBAC) mirroring SuiteCRM's "Security Groups" to ensure agencies can only view their own data. + +Audit Logging: All relationship changes (e.g., removing a contact from an account) must be logged, as the DB does not enforce cascading deletes. + +9. Roadmap + +Phase 1 (Core): Rust API development; implementation of accounts and contacts schemas; UUID generation logic. + +Phase 2 (Frontend): JAMstack UI deployment; basic CRUD features. + +Phase 3 (Outlook): Development of the Web Add-in to deprecate COM plugins. + +Phase 4 (Analytics): Integration of FinOps dashboards for real-time financial transparency. \ No newline at end of file diff --git a/README.md b/README.md index b3545fe5a..851cd5ea2 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,4 @@ -Run the following in your local "webroot" folder using Claude to start an http server on port 8887: - - start server - -Or run without Claude.: - - python -m http.server 8887 - -Then view pages at: +

Then view pages at:

[localhost:8887/](http://localhost:8887/) [localhost:8887/team](http://localhost:8887/team/) @@ -16,47 +8,4 @@ Then view pages at: [localhost:8887/home](http://localhost:8887/home/) [localhost:8887/feed](http://localhost:8887/feed/) -
- - 🗄️ - Rust API and Database - -
- -Look at the code in your webroot with an editor like [Sublime Text](https://www.sublimetext.com/) ($99), [VS Code](https://code.visualstudio.com/) or [WebStorm](https://www.jetbrains.com/webstorm/). - -
- -## How to deploy changes - -Update and make commits often (at least hourly). -Append nopr" or "No PR" if you are not yet ready to send a Pull Request. - -Run "pull" hourly to safely pull updates to the modelearth repos residing in your webroot - -When making any change, run "push" to send a PR. -"push" updates the webroot, submodules and forks. It does a "pull" automatically first. - - push - -If you find "push" is asking for mulitple approvals, Claude may not have read the claude.md instructions. -For the first usage, include extra guidance: - - push using claude.md with git.sh - -Addtional deployment commands: - - push [folder name] # Deploy a specific submodule or fork - push submodules # Deploy changes in all submodules - push forks # Deploy the extra forks added - - -## Alternative to using Claude Code CLI - -You can also use Github Desktop to choose a repo inthe webroot using "File > Add Local Repository". -Then submit a PR through the Github.com website. (The "push" with Claude will send a PR automatically.) - - -You can refresh all your local submodule by running: - - git submodule foreach 'git pull origin main || git pull origin master' \ No newline at end of file +Look at the code in your webroot with an editor like [Sublime Text](https://www.sublimetext.com/) ($99), [VS Code](https://code.visualstudio.com/) or [WebStorm](https://www.jetbrains.com/webstorm/). \ No newline at end of file diff --git a/better-auth b/better-auth new file mode 160000 index 000000000..46f16afb5 --- /dev/null +++ b/better-auth @@ -0,0 +1 @@ +Subproject commit 46f16afb5c8dc2f46dcd0505047021c2e6f686d8 diff --git a/chat b/chat new file mode 160000 index 000000000..e844b8265 --- /dev/null +++ b/chat @@ -0,0 +1 @@ +Subproject commit e844b8265e3c11f5fbb9f1172d916b4b796f7e27 diff --git a/cloud b/cloud index 15074609c..e04e7eb6e 160000 --- a/cloud +++ b/cloud @@ -1 +1 @@ -Subproject commit 15074609cad1b26d906fa0e2b4c1b00fd5063254 +Subproject commit e04e7eb6e1c07ba5f760b0a6f8f37efda95f2c97 diff --git a/codechat b/codechat index b64b7c6d1..51db20285 160000 --- a/codechat +++ b/codechat @@ -1 +1 @@ -Subproject commit b64b7c6d1eefa466ce6e044432d6c5d246fa1117 +Subproject commit 51db20285048e19bfb70ed80e8b630576aec05ef diff --git a/comparison b/comparison index 46372e22a..82b98f48d 160000 --- a/comparison +++ b/comparison @@ -1 +1 @@ -Subproject commit 46372e22a2c9f5019a366120e2644f20bafcc74d +Subproject commit 82b98f48dc7f9cded1707b9e0fa7857786809b60 diff --git a/deploy.md b/deploy.md new file mode 100644 index 000000000..4aee5d38d --- /dev/null +++ b/deploy.md @@ -0,0 +1,96 @@ +

How to deploy changes

+ +Update and make commits often. (At least hourly if you are editing code.) +Append "nopr" or "No PR" if you are not yet ready to send a Pull Request. + +## Using git.sh (Recommended) + +Your Code CLI can write your PR comments if you run the "push" command below. + +Or run your git.sh commands as follows in a separate terminal from your CLI. + +Start a secure virtual session in your local webroot and give the git.sh files permission. + + + python3 -m venv env + source env/bin/activate + chmod +x git.sh + chmod +x team/git.sh + +Run ./git.sh in your webroot. In the root git.sh is a pass-through to the team/git.sh file. + +You can watch your webroot's file status change in Github Desktop to confirm updates are deployed. + + ./git.sh push # Push all repositories with changes (auto-pulls first) + ./git.sh pull # Pull all repositories (webroot + submodules + extra repos) + ./git.sh push [name] # Push specific repository (webroot, submodule, or extra repo) + ./git.sh pull [name] # Pull specific repository + +You probably won't need these since cmds above resolve detached heads for submodules that differ from their parent repos. + + ./git.sh fix # Fix detached HEAD states + ./git.sh remotes # Update remotes for current GitHub user + +"push" also sends a Pull Request (PR) unless you include "nopr" + +### Wait to submit Pull Request: +- Add `nopr` to skip PR creation: `./git.sh push nopr` + + + +### Supported repositories: +- **Webroot**: webroot +- **Submodules**: Automatically detected from .gitmodules file +- **Extra Repos**: Automatically detected from .siterepos file + +## Using Github Desktop + +You can also use Github Desktop to choose a repo in the webroot using "File > Add Local Repository". +Then submit a PR through the Github.com website. +Or "./git.sh push" to send a PR automatically, but there won't be detailed comments from your CLI coding. +Or prompt "push" with your CLI to have a description of your changes included. +Note: Sometimes CLIs gets confused and treat the team folder as the webroot. + + +IMPORTANT: If you're using Github Desktop to push, you'll still need to send the PR from within Github.com. + + +## Using your CLI with ./git.sh push + +For the first usage, include extra guidance. Your push will also pull recent updates from others on Github. + + push using webroot/AGENTS.md with git.sh + + +If you find "push" is asking for multiple approvals, your CLI isn't following its AGENTS.md instructions. +When AGENTS.md is followed, "push" uses the git.sh file to first pull, then update the webroot, submodules and forks. + + push + +Additional deployment commands: + + push [folder name] # Deploy a specific submodule or fork + push submodules # Deploy changes in all submodules + push forks # Deploy the extra forks added + +"push" also sends a Pull Request (PR) unless you include "nopr" + + +## Manual submodule refresh + +You can refresh all your local submodules by running: + + git submodule foreach 'git pull origin main || git pull origin master' \ No newline at end of file diff --git a/desktop b/desktop new file mode 160000 index 000000000..b532ff6ac --- /dev/null +++ b/desktop @@ -0,0 +1 @@ +Subproject commit b532ff6acfd1aae785e1bbdb9052801ec7252aa1 diff --git a/docker b/docker new file mode 160000 index 000000000..f97fc5a19 --- /dev/null +++ b/docker @@ -0,0 +1 @@ +Subproject commit f97fc5a198e07b586901a4ebb302e4dfdd70d9a3 diff --git a/exiobase b/exiobase index 2822c0f0c..1ced035bd 160000 --- a/exiobase +++ b/exiobase @@ -1 +1 @@ -Subproject commit 2822c0f0cc2eaba90024aead41a250aebb822985 +Subproject commit 1ced035bd0d189eab16fbdc7f1bc4f8ed7964116 diff --git a/feed b/feed index 39f8fd23e..64ea118df 160000 --- a/feed +++ b/feed @@ -1 +1 @@ -Subproject commit 39f8fd23e9780d168daba9c90f8561d6e179bb30 +Subproject commit 64ea118df4ab3c5f3ebebec26b5e45e08ff87b07 diff --git a/git.sh b/git.sh index 27d205319..c7fa11b63 100755 --- a/git.sh +++ b/git.sh @@ -1,1379 +1,25 @@ #!/bin/bash -# git.sh - Streamlined git operations for webroot repository -# Usage: ./git.sh [command] [options] -# Push commands automatically pull first unless 'nopull' or 'no pull' is specified +# Simple passthrough script to team/git.sh +# Usage: ./git.sh [any arguments] # -# IMPORTANT: This script includes safeguards against submodule rollbacks -# - Uses safe_submodule_update() to preserve newer commits in submodules -# - Prevents accidental reversion to older commits during merges/pulls - -set -e # Exit on any error - -# Global setting for safe submodule updates (can be overridden with --unsafe-submodules) -SAFE_SUBMODULE_UPDATES=true - -# Parse command line arguments for global flags -for arg in "$@"; do - case $arg in - --unsafe-submodules) - SAFE_SUBMODULE_UPDATES=false - echo "⚠️ WARNING: Safe submodule protection DISABLED" - ;; - esac -done - -# Helper function to check if we're in webroot -check_webroot() { - CURRENT_REMOTE=$(git remote get-url origin 2>/dev/null || echo "") - if [[ "$CURRENT_REMOTE" != *"webroot"* ]]; then - echo "⚠️ ERROR: Not in webroot repository." - exit 1 - fi -} - -# Add upstream remote if it doesn't exist -add_upstream() { - local repo_name="$1" - local is_capital="$2" - - if [ -z "$(git remote | grep upstream)" ]; then - if [[ "$is_capital" == "true" ]]; then - git remote add upstream "https://github.com/ModelEarth/$repo_name.git" - else - git remote add upstream "https://github.com/modelearth/$repo_name.git" - fi - fi -} - -# Merge from upstream with fallback branches -merge_upstream() { - local repo_name="$1" - git fetch upstream 2>/dev/null || git fetch upstream - - # Try main/master first for all repos - if git merge upstream/main --no-edit 2>/dev/null; then - return 0 - elif git merge upstream/master --no-edit 2>/dev/null; then - return 0 - else - echo "⚠️ Merge conflicts - manual resolution needed" - return 1 - fi -} - -# Detect parent repository account (modelearth or partnertools) -get_parent_account() { - local repo_name="$1" - - # Check if upstream remote exists and points to expected parent - local upstream_url=$(git remote get-url upstream 2>/dev/null || echo "") - if [[ "$upstream_url" == *"modelearth/$repo_name"* ]]; then - echo "modelearth" - elif [[ "$upstream_url" == *"partnertools/$repo_name"* ]]; then - echo "partnertools" - else - # Fallback: try to determine from typical parent structure - if [[ "$repo_name" == "localsite" ]] || [[ "$repo_name" == "home" ]] || [[ "$repo_name" == "webroot" ]]; then - echo "ModelEarth" # Capital M for these repos - else - echo "modelearth" # lowercase for others - fi - fi -} - -# Get current GitHub user account -get_current_user() { - local user=$(gh api user --jq .login 2>/dev/null || echo "") - if [ -z "$user" ]; then - # Don't echo error message, just return failure - return 1 - fi - echo "$user" - return 0 -} - -# Check if current user owns the repository or has write access -is_repo_owner() { - local repo_name="$1" - local current_origin=$(git remote get-url origin 2>/dev/null || echo "") - - # Extract username from origin URL - if [[ "$current_origin" =~ github\.com[:/]([^/]+)/$repo_name ]]; then - local repo_owner="${BASH_REMATCH[1]}" - - # Try to get GitHub CLI user first - local gh_user=$(get_current_user) - local gh_result=$? - - if [ $gh_result -eq 0 ] && [ "$gh_user" = "$repo_owner" ]; then - return 0 # User owns the repo via GitHub CLI - fi - - # If GitHub CLI fails, check if it's a personal fork (not ModelEarth/modelearth) - if [[ "$repo_owner" != "ModelEarth" ]] && [[ "$repo_owner" != "modelearth" ]]; then - return 0 # Likely a fork owned by the user - fi - - # Special case: if pointing to ModelEarth repositories, assume user has access - # (since they wouldn't have these repos cloned unless they have access) - if [[ "$repo_owner" == "ModelEarth" ]]; then - return 0 # Assume user has access to ModelEarth repositories - fi - fi - - return 1 # Not the owner or couldn't determine -} - -# Clear git credentials and setup fresh authentication for current GitHub user -refresh_git_credentials() { - local current_user="$1" - - echo "🔄 Refreshing git credentials for $current_user..." - - # Clear cached git credentials - git credential-manager-core erase 2>/dev/null || true - git credential erase 2>/dev/null || true - - # Clear macOS keychain git credentials - if command -v security >/dev/null 2>&1; then - security delete-internet-password -s github.com 2>/dev/null || true - fi - - # Setup git to use GitHub CLI credentials - gh auth setup-git - - echo "✅ Git credentials refreshed for $current_user" -} - -# Store last known user in a temporary file for comparison -USER_CACHE_FILE="/tmp/git_sh_last_user" - -# Check if current user has changed and update remotes accordingly -check_user_change() { - local name="$1" - - # If user owns the repo, skip GitHub CLI requirement - if is_repo_owner "$name"; then - return 0 # User owns the repo, no need to update remotes - fi - - # Try to get current user via GitHub CLI - local current_user=$(get_current_user) - if [ $? -ne 0 ] || [ -z "$current_user" ]; then - # GitHub CLI not authenticated, but check if we can proceed without it - local current_origin=$(git remote get-url origin 2>/dev/null || echo "") - if [[ "$current_origin" =~ github\.com[:/]([^/]+)/$name ]]; then - local repo_owner="${BASH_REMATCH[1]}" - if [[ "$repo_owner" != "ModelEarth" ]] && [[ "$repo_owner" != "modelearth" ]]; then - echo "ℹ️ GitHub CLI not authenticated, but using existing fork remote" - return 0 - elif [[ "$repo_owner" == "ModelEarth" ]] && [[ "$name" == "webroot" ]]; then - echo "ℹ️ GitHub CLI not authenticated, but have access to ModelEarth/webroot" - return 0 - fi - fi - echo "⚠️ GitHub CLI not authenticated and repository requires it for operations" - return 1 - fi - - # Check if user has changed since last run - local last_user="" - if [ -f "$USER_CACHE_FILE" ]; then - last_user=$(cat "$USER_CACHE_FILE" 2>/dev/null) - fi - - # If user has changed, refresh git credentials - if [ -n "$last_user" ] && [ "$last_user" != "$current_user" ]; then - echo "👤 GitHub user changed from $last_user to $current_user" - refresh_git_credentials "$current_user" - fi - - # Store current user for next comparison - echo "$current_user" > "$USER_CACHE_FILE" - - # Check current origin remote - local current_origin=$(git remote get-url origin 2>/dev/null || echo "") - local expected_origin="https://github.com/$current_user/$name.git" - - # If origin doesn't match current user, update it - if [[ "$current_origin" != "$expected_origin" ]]; then - echo "🔄 GitHub user changed to $current_user - updating origin remote..." - git remote set-url origin "$expected_origin" 2>/dev/null || { - echo "⚠️ Failed to update origin remote for $current_user" - return 1 - } - echo "🔧 Updated origin to point to $current_user/$name" - fi - return 0 -} - -# Create fork and update remote to user's fork -setup_fork() { - local name="$1" - local parent_account="$2" - - # If user already owns the repo, no need to fork - if is_repo_owner "$name"; then - echo "ℹ️ Already using user's repository, no fork needed" - return 0 - fi - - local current_user=$(get_current_user) - if [ $? -ne 0 ]; then - echo "⚠️ Cannot create fork - GitHub CLI not authenticated" - return 1 - fi - - echo "🍴 Creating fork of $parent_account/$name for $current_user..." - - # Create fork (gh handles case where fork already exists) - local fork_url=$(gh repo fork "$parent_account/$name" --clone=false 2>/dev/null || echo "") - - if [ -n "$fork_url" ]; then - echo "✅ Fork created/found: $fork_url" - - # Update origin to point to user's fork - git remote set-url origin "$fork_url.git" 2>/dev/null || \ - git remote set-url origin "https://github.com/$current_user/$name.git" - - echo "🔧 Updated origin remote to point to $current_user fork" - return 0 - else - echo "⚠️ Failed to create/find fork for $current_user" - return 1 - fi -} - -# Update webroot submodule reference to point to user's fork -update_webroot_submodule_reference() { - local name="$1" - local commit_hash="$2" - - # Get current user login - local user_login=$(get_current_user) - if [ $? -ne 0 ]; then - echo "⚠️ Could not determine GitHub username" - return 1 - fi - - echo "🔄 Updating webroot submodule reference..." - cd $(git rev-parse --show-toplevel) - - # Update .gitmodules to point to user's fork - git config -f .gitmodules submodule.$name.url "https://github.com/$user_login/$name.git" - - # Sync the submodule URL change - git submodule sync "$name" - - # Update submodule to point to the specific commit - cd "$name" - git checkout "$commit_hash" 2>/dev/null - cd .. - - # Commit the submodule reference update - if [ -n "$(git status --porcelain | grep -E "($name|\.gitmodules)")" ]; then - git add "$name" .gitmodules - git commit -m "Update $name submodule to point to $user_login fork (commit $commit_hash)" - - if git push origin main 2>/dev/null; then - echo "✅ Updated webroot submodule reference to your fork" - else - echo "⚠️ Failed to push webroot submodule reference update" - fi - fi -} - -# Safely update submodules without reverting to older commits -safe_submodule_update() { - if [ "$SAFE_SUBMODULE_UPDATES" = "false" ]; then - echo "⚠️ Using UNSAFE submodule update (may revert to older commits)" - git submodule update --remote --recursive - return - fi - - echo "🛡️ Performing safe submodule update (preserving newer commits)..." - - # List of all known submodules - local submodules=(cloud comparison feed home localsite products projects realitystream swiper team trade codechat exiobase io profile reports community-forecasting) - - for sub in "${submodules[@]}"; do - if [ -d "$sub" ] && [ -d "$sub/.git" ]; then - echo "🔍 Checking submodule: $sub" - cd "$sub" - - # Get current commit hash and timestamp - local current_commit=$(git rev-parse HEAD 2>/dev/null || echo "") - local current_timestamp="" - if [ -n "$current_commit" ]; then - current_timestamp=$(git show -s --format=%ct "$current_commit" 2>/dev/null || echo "0") - fi - - # Check what commit the parent repository wants - cd .. - local expected_commit=$(git ls-tree HEAD "$sub" | awk '{print $3}' || echo "") - - if [ -n "$expected_commit" ] && [ -n "$current_commit" ]; then - cd "$sub" - # Get timestamp of expected commit - local expected_timestamp=$(git show -s --format=%ct "$expected_commit" 2>/dev/null || echo "0") - - # Only update if expected commit is newer than current commit - if [ "$expected_timestamp" -gt "$current_timestamp" ]; then - echo "⬆️ Updating $sub to newer commit: $expected_commit ($(git show -s --format='%ci' "$expected_commit" 2>/dev/null || echo 'unknown date'))" - git checkout "$expected_commit" 2>/dev/null || echo "⚠️ Failed to checkout $expected_commit in $sub" - elif [ "$expected_timestamp" -lt "$current_timestamp" ]; then - echo "🛡️ Preserving newer commit in $sub: $current_commit ($(git show -s --format='%ci' "$current_commit" 2>/dev/null || echo 'unknown date'))" - echo " ↳ Parent repo wants older commit: $expected_commit ($(git show -s --format='%ci' "$expected_commit" 2>/dev/null || echo 'unknown date'))" - - # Update parent repo to point to the newer commit - cd .. - git add "$sub" - echo "📌 Updated parent repo to preserve newer $sub commit" - else - echo "✅ $sub is already at the correct commit" - fi - cd .. - else - echo "⚠️ Could not determine commit information for $sub" - cd .. - fi - fi - done - - echo "✅ Safe submodule update completed" -} - -# Safely update a single submodule without reverting to older commits -safe_single_submodule_update() { - local sub="$1" - echo "🛡️ Safely updating submodule: $sub" - - if [ -d "$sub" ] && [ -d "$sub/.git" ]; then - cd "$sub" - - # Get current commit hash and timestamp - local current_commit=$(git rev-parse HEAD 2>/dev/null || echo "") - local current_timestamp="" - if [ -n "$current_commit" ]; then - current_timestamp=$(git show -s --format=%ct "$current_commit" 2>/dev/null || echo "0") - fi - - # Update to latest from remote main branch (safer than parent repo reference) - git fetch origin main 2>/dev/null || git fetch origin master 2>/dev/null - local latest_commit=$(git rev-parse origin/main 2>/dev/null || git rev-parse origin/master 2>/dev/null || echo "") - - if [ -n "$latest_commit" ] && [ -n "$current_commit" ]; then - local latest_timestamp=$(git show -s --format=%ct "$latest_commit" 2>/dev/null || echo "0") - - # Only update if remote has newer commits - if [ "$latest_timestamp" -gt "$current_timestamp" ]; then - echo "⬆️ Updating $sub to latest: $latest_commit" - git checkout "$latest_commit" 2>/dev/null || echo "⚠️ Failed to checkout latest in $sub" - else - echo "✅ $sub is already up to date" - fi - fi - cd .. - else - echo "⚠️ Submodule $sub not found or not initialized" - fi -} - -# Fix detached HEAD state by merging into main branch -fix_detached_head() { - local name="$1" - - # Check if we're in detached HEAD state - local current_branch=$(git symbolic-ref -q HEAD 2>/dev/null || echo "") - if [ -z "$current_branch" ]; then - echo "⚠️ $name is in detached HEAD state - fixing..." - - # Get the current commit hash - local detached_commit=$(git rev-parse HEAD) - - # Switch to main branch - git checkout main 2>/dev/null || git checkout master 2>/dev/null || { - echo "⚠️ No main/master branch found in $name" - return 1 - } - - # Check if we need to merge the detached commit - if ! git merge-base --is-ancestor "$detached_commit" HEAD; then - echo "🔄 Merging detached commit $detached_commit into main branch" - if git merge "$detached_commit" --no-edit 2>/dev/null; then - echo "✅ Successfully merged detached HEAD in $name" - else - echo "⚠️ Merge conflicts in $name - manual resolution needed" - return 1 - fi - else - echo "✅ Detached commit already in $name main branch" - fi - fi - return 0 -} - -# Ensure all pending commits are pushed to origin -ensure_push_completion() { - local name="$1" - local max_retries=3 - local retry_count=0 - - while [ $retry_count -lt $max_retries ]; do - # Check if there are unpushed commits - local unpushed=$(git rev-list --count @{u}..HEAD 2>/dev/null || echo "0") - if [ "$unpushed" = "0" ]; then - echo "✅ All commits pushed for $name" - return 0 - fi - - echo "📤 Pushing $unpushed pending commits for $name..." - - # Try different push strategies - if git push 2>/dev/null; then - echo "✅ Successfully pushed $name" - return 0 - elif git push origin HEAD:main 2>/dev/null; then - echo "✅ Successfully pushed $name to main" - return 0 - elif git push origin HEAD:master 2>/dev/null; then - echo "✅ Successfully pushed $name to master" - return 0 - elif git push --force-with-lease 2>/dev/null; then - echo "✅ Force pushed $name with lease" - return 0 - else - ((retry_count++)) - echo "⚠️ Push attempt $retry_count failed for $name" - if [ $retry_count -lt $max_retries ]; then - echo "🔄 Retrying in 2 seconds..." - sleep 2 - fi - fi - done - - echo "❌ Failed to push $name after $max_retries attempts" - echo "💡 You may need to manually resolve this in GitHub Desktop" - return 1 -} - -# Enhanced commit and push with automatic fork creation -commit_push() { - local name="$1" - local skip_pr="$2" - - # Fix detached HEAD before committing - fix_detached_head "$name" - - # Check if there are changes to commit first - if [ -n "$(git status --porcelain)" ]; then - # Only check user change and update remotes when there are actual changes - check_user_change "$name" - git add . - git commit -m "Update $name" - local commit_hash=$(git rev-parse HEAD) - - # Determine target branch - local target_branch="main" - - # Check if user owns the repository - if is_repo_owner "$name"; then - echo "✅ User owns $name repository - attempting direct push" - # Try multiple push strategies for owned repositories - local push_error="" - if git push origin HEAD:$target_branch 2>/dev/null; then - echo "✅ Successfully pushed $name to $target_branch branch" - ensure_push_completion "$name" - return 0 - elif git push origin $target_branch 2>/dev/null; then - echo "✅ Successfully pushed $name to $target_branch" - ensure_push_completion "$name" - return 0 - elif push_error=$(git push 2>&1); then - echo "✅ Successfully pushed $name" - ensure_push_completion "$name" - return 0 - else - # Check for specific OAuth workflow scope error - if [[ "$push_error" == *"workflow"* ]] && [[ "$push_error" == *"OAuth"* ]]; then - echo "🔒 GitHub OAuth token lacks 'workflow' scope for updating GitHub Actions" - echo "💡 To fix this, run: gh auth refresh -h github.com -s workflow" - echo "💡 Then retry the commit command" - return 1 - else - echo "⚠️ Push failed for owned repository $name with error:" - echo "$push_error" - echo "💡 Trying force push with lease..." - if git push --force-with-lease 2>/dev/null; then - echo "✅ Force pushed $name" - ensure_push_completion "$name" - return 0 - else - echo "❌ All push strategies failed for owned repo $name" - return 1 - fi - fi - fi - else - echo "🔒 User does not own $name repository - trying fork workflow" - # Try to push directly first in case we have access - if git push origin HEAD:$target_branch 2>/dev/null; then - echo "✅ Successfully pushed $name to $target_branch branch" - ensure_push_completion "$name" - return 0 - fi - - # If direct push fails, check if it's a permission issue - local push_output=$(git push origin HEAD:$target_branch 2>&1) - if [[ "$push_output" == *"Permission denied"* ]] || [[ "$push_output" == *"403"* ]]; then - echo "🔒 Permission denied - setting up fork workflow..." - - # Detect parent account - local parent_account=$(get_parent_account "$name") - echo "📍 Detected parent: $parent_account/$name" - - # Setup fork and update remote - if setup_fork "$name" "$parent_account"; then - # Try pushing to fork - if git push origin HEAD:$target_branch 2>/dev/null; then - echo "✅ Successfully pushed $name to your fork" - ensure_push_completion "$name" - else - # Force push if normal push fails - echo "🔄 Normal push failed, trying force push..." - if git push --force-with-lease origin HEAD:$target_branch 2>/dev/null; then - echo "✅ Force pushed $name to your fork" - ensure_push_completion "$name" - else - echo "⚠️ Failed to push $name to fork" - return 1 - fi - fi - - # Create PR if not skipped - if [[ "$skip_pr" != "nopr" ]]; then - echo "📝 Creating pull request..." - local pr_url=$(gh pr create \ - --title "Update $name" \ - --body "Automated update from git.sh commit workflow" \ - --base $target_branch \ - --head $target_branch \ - --repo "$parent_account/$name" 2>/dev/null || echo "") - - if [ -n "$pr_url" ]; then - echo "🔄 Created PR: $pr_url" - else - echo "⚠️ PR creation failed for $name" - fi - fi - - # Update webroot submodule reference if this is a submodule - if [[ "$name" != "webroot" ]] && [[ "$name" != "exiobase" ]] && [[ "$name" != "profile" ]] && [[ "$name" != "io" ]]; then - update_webroot_submodule_reference "$name" "$commit_hash" - fi - else - echo "⚠️ Failed to push to fork" - fi - elif [[ "$skip_pr" != "nopr" ]]; then - # Other push failure - try feature branch PR - git push origin HEAD:feature-$name-updates 2>/dev/null && \ - gh pr create --title "Update $name" --body "Automated update" --base $target_branch --head feature-$name-updates 2>/dev/null || \ - echo "🔄 PR creation failed for $name" - fi - fi - fi -} - -# Pull command - streamlined pull workflow -pull_command() { - local repo_name="$1" - - echo "🔄 Starting pull workflow..." - cd $(git rev-parse --show-toplevel) - check_webroot - - # If specific repo name provided, pull only that repo - if [ -n "$repo_name" ]; then - pull_specific_repo "$repo_name" - return - fi - - # Pull webroot - echo "📥 Pulling webroot..." - git pull origin main 2>/dev/null || echo "⚠️ Checking for conflicts in webroot" - - # Update webroot from parent (skip partnertools) - WEBROOT_REMOTE=$(git remote get-url origin) - if [[ "$WEBROOT_REMOTE" != *"partnertools"* ]]; then - add_upstream "webroot" "true" - merge_upstream "webroot" - fi - - # Pull submodules - echo "📥 Pulling submodules..." - for sub in cloud comparison feed home localsite products projects realitystream swiper team trade codechat exiobase io profile reports community-forecasting; do - [ ! -d "$sub" ] && continue - cd "$sub" - - REMOTE=$(git remote get-url origin 2>/dev/null || echo "") - if [[ "$REMOTE" != *"partnertools"* ]]; then - if [[ "$sub" == "localsite" ]] || [[ "$sub" == "home" ]]; then - add_upstream "$sub" "true" - else - add_upstream "$sub" "false" - fi - merge_upstream "$sub" - fi - cd .. - done - - # Update submodule references safely (preserve newer commits) - echo "🔄 Updating submodule references..." - safe_submodule_update - - # Check for and fix any detached HEAD states after pulls - echo "🔍 Checking for detached HEAD states after pull..." - fix_all_detached_heads - - # Pull extra repos - echo "📥 Pulling extra repos..." - for repo in community nisar data-pipeline; do - [ ! -d "$repo" ] && continue - cd "$repo" - git pull origin main 2>/dev/null || echo "⚠️ Checking for conflicts in $repo" - - REMOTE=$(git remote get-url origin 2>/dev/null || echo "") - if [[ "$REMOTE" != *"partnertools"* ]]; then - add_upstream "$repo" "false" - merge_upstream "$repo" - fi - cd .. - done - - echo "✅ Pull completed! Use: ./git.sh push" -} - -# Pull specific repository -pull_specific_repo() { - local repo_name="$1" - - cd $(git rev-parse --show-toplevel) - check_webroot - - # Check if it's webroot - if [[ "$repo_name" == "webroot" ]]; then - echo "📥 Pulling webroot..." - git pull origin main 2>/dev/null || echo "⚠️ Checking for conflicts in webroot" - - WEBROOT_REMOTE=$(git remote get-url origin) - if [[ "$WEBROOT_REMOTE" != *"partnertools"* ]]; then - add_upstream "webroot" "true" - merge_upstream "webroot" - fi - echo "✅ Webroot pull completed!" - return - fi - - # Check if it's a submodule - if [[ " cloud comparison feed home localsite products projects realitystream swiper team trade codechat exiobase io profile reports community-forecasting " =~ " $repo_name " ]]; then - if [ -d "$repo_name" ]; then - echo "📥 Pulling submodule: $repo_name..." - cd "$repo_name" - - REMOTE=$(git remote get-url origin 2>/dev/null || echo "") - if [[ "$REMOTE" != *"partnertools"* ]]; then - if [[ "$repo_name" == "localsite" ]] || [[ "$repo_name" == "home" ]]; then - add_upstream "$repo_name" "true" - else - add_upstream "$repo_name" "false" - fi - merge_upstream "$repo_name" - fi - - cd .. - safe_single_submodule_update "$repo_name" - echo "✅ $repo_name submodule pull completed!" - else - echo "⚠️ Submodule not found: $repo_name" - fi - return - fi - - # Check if it's an extra repo - if [[ " community nisar data-pipeline " =~ " $repo_name " ]]; then - if [ -d "$repo_name" ]; then - echo "📥 Pulling extra repo: $repo_name..." - cd "$repo_name" - git pull origin main 2>/dev/null || echo "⚠️ Checking for conflicts in $repo_name" - - REMOTE=$(git remote get-url origin 2>/dev/null || echo "") - if [[ "$REMOTE" != *"partnertools"* ]]; then - add_upstream "$repo_name" "false" - merge_upstream "$repo_name" - fi - cd .. - echo "✅ $repo_name extra repo pull completed!" - else - echo "⚠️ Extra repo not found: $repo_name" - fi - return - fi - - echo "⚠️ Repository not recognized: $repo_name" - echo "Supported repositories:" - echo " Webroot: webroot" - echo " Submodules: cloud, comparison, feed, home, localsite, products, projects, realitystream, swiper, team, trade, codechat, exiobase, io, profile, reports, community-forecasting" - echo " Extra Repos: community, nisar, data-pipeline" -} - -# Check and fix detached HEAD states in all repositories -fix_all_detached_heads() { - echo "🔍 Checking for detached HEAD states in all repositories..." - cd $(git rev-parse --show-toplevel) - check_webroot - - local fixed_count=0 - - # Check webroot - echo "📁 Checking webroot..." - if fix_detached_head "webroot"; then - ((fixed_count++)) - fi - - # Check all submodules - echo "📁 Checking submodules..." - for sub in cloud comparison feed home localsite products projects realitystream swiper team trade codechat exiobase io profile reports community-forecasting; do - if [ -d "$sub" ]; then - echo "📁 Checking $sub..." - cd "$sub" - if fix_detached_head "$sub"; then - ((fixed_count++)) - fi - cd .. - fi - done - - # Check extra repos - echo "📁 Checking extra repos..." - for repo in community nisar data-pipeline; do - if [ -d "$repo" ]; then - echo "📁 Checking $repo..." - cd "$repo" - if fix_detached_head "$repo"; then - ((fixed_count++)) - fi - cd .. - fi - done - - if [ $fixed_count -gt 0 ]; then - echo "✅ All $fixed_count submodules pointed at main branch" - echo "💡 You may want to run './git.sh push' to update submodule references" - else - echo "✅ All submodules already on main branch" - fi -} - -# Check and update all remotes for current GitHub user -update_all_remotes_for_user() { - echo "🔄 Updating all remotes for current GitHub user..." - cd $(git rev-parse --show-toplevel) - check_webroot - - local current_user=$(get_current_user) - if [ $? -ne 0 ]; then - return 1 - fi - - echo "👤 Current GitHub user: $current_user" - local updated_count=0 - - # Check webroot - echo "📁 Checking webroot remotes..." - if check_user_change "webroot"; then - ((updated_count++)) - fi - - # Check all submodules - echo "📁 Checking submodule remotes..." - for sub in cloud comparison feed home localsite products projects realitystream swiper team trade codechat exiobase io profile reports community-forecasting; do - if [ -d "$sub" ]; then - echo "📁 Checking $sub remotes..." - cd "$sub" - if check_user_change "$sub"; then - ((updated_count++)) - fi - cd .. - fi - done - - # Check extra repos - echo "📁 Checking extra repo remotes..." - for repo in community nisar data-pipeline; do - if [ -d "$repo" ]; then - echo "📁 Checking $repo remotes..." - cd "$repo" - if check_user_change "$repo"; then - ((updated_count++)) - fi - cd .. - fi - done - - if [ $updated_count -gt 0 ]; then - echo "✅ Updated remotes for $updated_count repositories to $current_user" - else - echo "✅ All remotes already point to $current_user" - fi -} - -# Check if GitHub Pages is enabled for a repository -check_github_pages() { - local user_login="$1" - local repo_name="$2" - - # Check if GitHub Pages is enabled using GitHub API - local pages_info=$(gh api "repos/$user_login/$repo_name/pages" 2>/dev/null || echo "") - if [ -n "$pages_info" ]; then - return 0 # Pages is enabled - else - return 1 # Pages is not enabled - fi -} - -# Enable GitHub Pages for a repository -enable_github_pages() { - local user_login="$1" - local repo_name="$2" - - echo "🌐 Enabling GitHub Pages for $user_login/$repo_name..." - - # Try to enable GitHub Pages using main branch - local result=$(gh api --method POST "repos/$user_login/$repo_name/pages" \ - -f source.branch=main \ - -f source.path=/ 2>/dev/null || echo "") - - if [ -n "$result" ]; then - echo "✅ GitHub Pages enabled for $user_login/$repo_name" - echo "📋 Site will be available at: https://$user_login.github.io/$repo_name" - return 0 - else - echo "⚠️ Could not enable GitHub Pages automatically" - echo "💡 Please manually enable GitHub Pages in your fork:" - echo " 1. Go to https://github.com/$user_login/$repo_name/settings/pages" - echo " 2. Set Source to 'Deploy from a branch'" - echo " 3. Select branch: main, folder: / (root)" - echo " 4. Click Save" - echo "📋 After setup, your site will be at: https://$user_login.github.io/$repo_name" - echo "" - echo "Options:" - echo " Y - Continue with PR creation (recommended)" - echo " N - Skip PR creation and continue with commit only" - echo " Q - Quit without creating PR or committing" - - read -p "Choose an option [Y/n/q]: " choice - case "${choice,,}" in - ""|y|yes) - echo "✅ Continuing with PR creation..." - return 0 - ;; - n|no) - echo "⚠️ Skipping PR creation as requested" - return 2 # Special return code for skip PR - ;; - q|quit) - echo "❌ Aborting commit and PR creation" - return 3 # Special return code for quit - ;; - *) - echo "Invalid choice. Defaulting to continue with PR..." - return 0 - ;; - esac - fi -} - -# Create PR for webroot to its parent with GitHub Pages integration -create_webroot_pr() { - local skip_pr="$1" - - if [[ "$skip_pr" == "nopr" ]]; then - return 0 - fi - - # Get webroot remote URLs - local origin_url=$(git remote get-url origin 2>/dev/null || echo "") - local upstream_url=$(git remote get-url upstream 2>/dev/null || echo "") - - # Extract parent account from upstream or determine from origin - local parent_account="" - if [[ "$upstream_url" == *"ModelEarth/webroot"* ]]; then - parent_account="ModelEarth" - elif [[ "$upstream_url" == *"partnertools/webroot"* ]]; then - parent_account="partnertools" - elif [[ "$origin_url" != *"ModelEarth/webroot"* ]] && [[ "$origin_url" != *"partnertools/webroot"* ]]; then - # This is likely a fork, default to ModelEarth as parent - parent_account="ModelEarth" - else - # Already pointing to parent, no PR needed - return 0 - fi - - echo "📝 Creating webroot PR to $parent_account/webroot..." - - # Get current user login for head specification - local user_login=$(get_current_user) - local head_spec="main" - if [ $? -eq 0 ] && [ -n "$user_login" ]; then - head_spec="$user_login:main" - else - echo "⚠️ Could not determine current user for PR creation" - return 1 - fi - - # Check and setup GitHub Pages for the fork - local pages_url="" - local pages_status="" - local pages_result=0 - - if check_github_pages "$user_login" "webroot"; then - pages_url="https://$user_login.github.io/webroot" - pages_status="✅ GitHub Pages is enabled" - echo "$pages_status: $pages_url" - else - echo "🔍 GitHub Pages not detected, attempting to enable..." - enable_github_pages "$user_login" "webroot" - pages_result=$? - - case $pages_result in - 0) - pages_url="https://$user_login.github.io/webroot" - pages_status="🌐 GitHub Pages enabled (may take a few minutes to be available)" - ;; - 2) - echo "🔄 Continuing with commit only (no PR as requested)" - return 0 # Skip PR creation but continue - ;; - 3) - echo "❌ Aborting PR creation as requested" - return 1 # Abort completely - ;; - *) - pages_url="https://$user_login.github.io/webroot" - pages_status="⚠️ GitHub Pages setup needed - continuing with PR creation" - ;; - esac - fi - - # Create enhanced PR body with review links - local pr_body="## Webroot Update - -Automated webroot update from git.sh commit workflow - includes submodule reference updates and configuration changes. - -## Review Links - -📋 **Live Preview**: [$pages_url]($pages_url) -🔗 **Fork Repository**: [https://github.com/$user_login/webroot](https://github.com/$user_login/webroot) - -## GitHub Pages Status -$pages_status - ---- -*Generated by git.sh commit workflow*" - - local pr_url=$(gh pr create \ - --title "Update webroot with submodule changes" \ - --body "$pr_body" \ - --base main \ - --head "$head_spec" \ - --repo "$parent_account/webroot" 2>/dev/null || echo "") - - if [ -n "$pr_url" ]; then - echo "🔄 Created webroot PR: $pr_url" - if [ -n "$pages_url" ]; then - echo "📋 Review at: $pages_url" - fi - else - echo "⚠️ Webroot PR creation failed or not needed" - fi -} - -# Push specific repository -push_specific_repo() { - local name="$1" - local skip_pr="$2" - - cd $(git rev-parse --show-toplevel) - check_webroot - - # Auto-pull unless nopull/no pull is specified - if [[ "$skip_pr" != *"nopull"* ]] && [[ "$skip_pr" != *"no pull"* ]]; then - echo "🔄 Auto-pulling $name before push..." - pull_command "$name" - echo "✅ Pull completed for $name, proceeding with push..." - fi - - # Check if it's webroot - if [[ "$name" == "webroot" ]]; then - commit_push "webroot" "$skip_pr" - - # Check if webroot needs PR after direct changes - local webroot_commits_ahead=$(git rev-list --count upstream/main..HEAD 2>/dev/null || echo "0") - if [[ "$webroot_commits_ahead" -gt "0" ]] && [[ "$skip_pr" != "nopr" ]]; then - create_webroot_pr "$skip_pr" - fi - - echo "🔍 Checking for remaining unpushed commits..." - final_push_completion_check - return - fi - - # Check if it's a submodule - if [[ " cloud comparison feed home localsite products projects realitystream swiper team trade codechat exiobase io profile reports community-forecasting " =~ " $name " ]]; then - if [ -d "$name" ]; then - cd "$name" - commit_push "$name" "$skip_pr" - - # Update webroot submodule reference - cd .. - safe_single_submodule_update "$name" - if [ -n "$(git status --porcelain | grep $name)" ]; then - git add "$name" - git commit -m "Update $name submodule reference" - - # Try to push webroot changes - if git push 2>/dev/null; then - echo "✅ Updated $name submodule reference" - else - echo "🔄 Webroot push failed for $name - attempting PR workflow" - create_webroot_pr "$skip_pr" - fi - fi - - # Check if we need to create a webroot PR (for when webroot push succeeded but we want PR anyway) - local webroot_commits_ahead=$(git rev-list --count upstream/main..HEAD 2>/dev/null || echo "0") - if [[ "$webroot_commits_ahead" -gt "0" ]] && [[ "$skip_pr" != "nopr" ]]; then - create_webroot_pr "$skip_pr" - fi - - # Final push completion check - echo "🔍 Checking for remaining unpushed commits..." - final_push_completion_check - else - echo "⚠️ Submodule not found: $name" - fi - return - fi - - # Check if it's an extra repo - if [[ " community nisar data-pipeline " =~ " $name " ]]; then - if [ -d "$name" ]; then - cd "$name" - commit_push "$name" "$skip_pr" - cd .. - - echo "🔍 Checking for remaining unpushed commits..." - final_push_completion_check - else - echo "⚠️ Extra repo not found: $name" - fi - return - fi - - echo "⚠️ Repository not recognized: $name" - echo "Supported repositories:" - echo " Webroot: webroot" - echo " Submodules: cloud, comparison, feed, home, localsite, products, projects, realitystream, swiper, team, trade, codechat, exiobase, io, profile, reports, community-forecasting" - echo " Extra Repos: community, nisar, data-pipeline" -} - -# Push all submodules -push_submodules() { - local skip_pr="$1" - - cd $(git rev-parse --show-toplevel) - check_webroot - - # Auto-pull unless nopull/no pull is specified - if [[ "$skip_pr" != *"nopull"* ]] && [[ "$skip_pr" != *"no pull"* ]]; then - echo "🔄 Auto-pulling submodules before push..." - pull_command - echo "✅ Pull completed for submodules, proceeding with push..." - fi - - # Push each submodule with changes - for sub in cloud comparison feed home localsite products projects realitystream swiper team trade codechat exiobase io profile reports community-forecasting; do - [ ! -d "$sub" ] && continue - cd "$sub" - commit_push "$sub" "$skip_pr" - cd .. - done - - # Update webroot submodule references - safe_submodule_update - if [ -n "$(git status --porcelain)" ]; then - git add . - git commit -m "Update submodule references" - git push 2>/dev/null || echo "🔄 Webroot push failed" - echo "✅ Updated submodule references" - fi - - # Final push completion check - echo "🔍 Checking for remaining unpushed commits..." - final_push_completion_check -} - -# Complete push workflow -push_all() { - local skip_pr="$1" - - cd $(git rev-parse --show-toplevel) - check_webroot - - # Auto-pull unless nopull/no pull is specified - if [[ "$skip_pr" != *"nopull"* ]] && [[ "$skip_pr" != *"no pull"* ]]; then - echo "🔄 Auto-pulling before push..." - pull_command - echo "✅ Pull completed, proceeding with push..." - fi - - # Push webroot changes - commit_push "webroot" "$skip_pr" - - # Check if webroot needs PR after direct changes - local webroot_commits_ahead=$(git rev-list --count upstream/main..HEAD 2>/dev/null || echo "0") - if [[ "$webroot_commits_ahead" -gt "0" ]] && [[ "$skip_pr" != "nopr" ]]; then - create_webroot_pr "$skip_pr" - fi - - # Push all submodules - push_submodules "$skip_pr" - - # Push extra repos - for repo in community nisar data-pipeline; do - [ ! -d "$repo" ] && continue - cd "$repo" - commit_push "$repo" "$skip_pr" - cd .. - done - - # Final push completion check for all repositories - echo "🔍 Checking for any remaining unpushed commits..." - final_push_completion_check - - echo "✅ Complete push finished!" - - # Check extra repos for uncommitted changes - check_extra_repos_for_changes -} - -# Check extra repos for uncommitted changes and prompt user -check_extra_repos_for_changes() { - cd $(git rev-parse --show-toplevel) - - local repos_with_changes=() - local repo_names=("community" "nisar" "data-pipeline") - - # Check each extra repo for changes - for repo in "${repo_names[@]}"; do - if [ -d "$repo" ]; then - cd "$repo" - if [ -n "$(git status --porcelain)" ]; then - repos_with_changes+=("$repo") - fi - cd .. - fi - done - - # If there are changes, prompt the user - if [ ${#repos_with_changes[@]} -gt 0 ]; then - echo "" - echo "📝 Extra repos with uncommitted changes detected:" - echo "" - - local i=1 - for repo in "${repos_with_changes[@]}"; do - echo " $i) $repo" - ((i++)) - done - echo " $i) all" - echo "" - - read -p "Which extra repo would you like to push? (1-$i or press Enter to skip): " choice - - if [ -n "$choice" ]; then - if [ "$choice" -eq "$i" ] 2>/dev/null; then - # Push all extra repos with changes - echo "🚀 Pushing all extra repos with changes..." - for repo in "${repos_with_changes[@]}"; do - push_extra_repo "$repo" - done - elif [ "$choice" -ge 1 ] && [ "$choice" -lt "$i" ] 2>/dev/null; then - # Push specific repo - local selected_repo="${repos_with_changes[$((choice-1))]}" - echo "🚀 Pushing $selected_repo..." - push_extra_repo "$selected_repo" - else - echo "❌ Invalid choice. Skipping extra repo push." - fi - else - echo "⏭️ Skipping extra repo push." - fi - fi -} - -# Push a specific extra repo -push_extra_repo() { - local repo_name="$1" - - cd $(git rev-parse --show-toplevel) - - if [ -d "$repo_name" ]; then - cd "$repo_name" - - if [ -n "$(git status --porcelain)" ]; then - git add . - git commit -m "Update $repo_name repository" - - if git push origin main 2>/dev/null; then - echo "✅ Successfully pushed $repo_name repository" - else - echo "⚠️ Push failed for $repo_name repository" - - # Try to create PR if it's a fork - local current_user=$(get_current_user) - if [ $? -eq 0 ] && [ -n "$current_user" ]; then - local remote_url=$(git remote get-url origin) - if [[ "$remote_url" =~ "$current_user/$repo_name" ]]; then - echo "🔄 Creating pull request for $repo_name..." - gh pr create --title "Update $repo_name" --body "Automated update from webroot integration" --base main --head main 2>/dev/null || echo "PR creation failed for $repo_name" - fi - fi - fi - else - echo "✅ No changes to push in $repo_name" - fi - - cd .. - else - echo "⚠️ Extra repo not found: $repo_name" - fi -} - -# Check all repositories for unpushed commits and push them -final_push_completion_check() { - cd $(git rev-parse --show-toplevel) - - # Check webroot - if [ -n "$(git rev-list --count @{u}..HEAD 2>/dev/null)" ] && [ "$(git rev-list --count @{u}..HEAD 2>/dev/null)" != "0" ]; then - echo "📤 Found unpushed commits in webroot..." - ensure_push_completion "webroot" - fi - - # Check all submodules - for sub in cloud comparison feed home localsite products projects realitystream swiper team trade codechat exiobase io profile reports community-forecasting; do - if [ -d "$sub" ]; then - cd "$sub" - if [ -n "$(git rev-list --count @{u}..HEAD 2>/dev/null)" ] && [ "$(git rev-list --count @{u}..HEAD 2>/dev/null)" != "0" ]; then - echo "📤 Found unpushed commits in $sub..." - ensure_push_completion "$sub" - fi - cd .. - fi - done - - # Check extra repos - for repo in community nisar data-pipeline; do - if [ -d "$repo" ]; then - cd "$repo" - if [ -n "$(git rev-list --count @{u}..HEAD 2>/dev/null)" ] && [ "$(git rev-list --count @{u}..HEAD 2>/dev/null)" != "0" ]; then - echo "📤 Found unpushed commits in $repo..." - ensure_push_completion "$repo" - fi - cd .. - fi - done -} - -# Main command dispatcher -case "$1" in - "pull"|"pull-all") - pull_command "$2" - ;; - "push"|"push-all") - if [ "$2" = "submodules" ]; then - push_submodules "$3" - elif [ "$2" = "all" ] || [ -z "$2" ]; then - push_all "$2$3" # Handle both 'push' and 'push all [nopr]' - elif [ -n "$2" ]; then - push_specific_repo "$2" "$3" - fi - ;; - "fix-heads"|"fix") - fix_all_detached_heads - ;; - "update-remotes"|"remotes") - update_all_remotes_for_user - ;; - "refresh-auth"|"auth") - current_user=$(get_current_user) - if [ $? -eq 0 ]; then - refresh_git_credentials "$current_user" - update_all_remotes_for_user - fi - ;; - # Legacy command support with helpful messages - "update") - echo "⚠️ Please use 'pull' or 'pull all' instead of 'update'. Examples:" - echo " • pull - Pull all changes from webroot, submodules, and industry repos" - echo " • pull localsite - Pull changes for localsite submodule only" - echo " • pull webroot - Pull changes for webroot only" - echo "" - exit 1 - ;; - "commit") - echo "⚠️ Please use 'push' instead of 'commit'. Examples:" - echo " • push - Push all repositories with changes" - echo " • push localsite - Push changes for localsite submodule" - echo " • push webroot - Push changes for webroot only" - echo " • push all - Push all repositories with changes (same as 'push')" - echo "" - exit 1 - ;; - *) - echo "Usage: ./git.sh [pull|push|fix|remotes|auth] [repo_name|submodules|all] [nopr] [--unsafe-submodules]" - echo "" - echo "Commands:" - echo " ./git.sh pull - Pull all repositories (webroot + submodules + extra repos)" - echo " ./git.sh pull [repo_name] - Pull specific repository" - echo " ./git.sh push - Push all repositories with changes" - echo " ./git.sh push all - Push all repositories with changes (same as 'push')" - echo " ./git.sh push [repo_name] - Push specific repository" - echo " ./git.sh push submodules - Push all submodules only" - echo " ./git.sh fix - Check and fix detached HEAD states in all repos" - echo " ./git.sh remotes - Update all remotes to current GitHub user" - echo " ./git.sh auth - Refresh git credentials for current GitHub user" - echo "" - echo "Supported Repository Names:" - echo " Webroot: webroot" - echo " Submodules: cloud, comparison, feed, home, localsite, products, projects, realitystream, swiper, team, trade, codechat, exiobase, io, profile, reports, community-forecasting" - echo " Extra Repos: community, nisar, data-pipeline" - echo "" - echo "Options:" - echo " nopr - Skip PR creation on push failures" - echo " --unsafe-submodules - Disable safe submodule protection (may revert to older commits)" - echo "" - echo "Safety Features:" - echo " 🛡️ Safe submodule updates enabled by default - preserves newer commits during merges" - echo " 🔍 Prevents accidental rollback to older submodule commits from merged PRs" - echo "" - echo "Legacy Commands (deprecated):" - echo " update -> use 'pull' or 'pull all'" - echo " commit -> use 'push'" - exit 1 - ;; -esac - -# Always return to webroot repository root at the end. Webroot may have different names for each user who forks and clones it. -cd $(git rev-parse --show-toplevel) \ No newline at end of file +# Expected behavior when running "./git.sh push" from webroot: +# - Commit all submodules of the webroot repo (including the team submodule) +# - Commit extra repos that are not submodules +# - Commit the webroot repo itself +# - Push all repositories with changes + +# Run here (in webroot) regardless of where called from +cd "$(dirname "$0")" + +# Check if team/git.sh exists +if [ ! -f "team/git.sh" ]; then + echo "⚠️ ERROR: team/git.sh not found" + echo "Make sure you're in the webroot directory and the team submodule is initialized" + exit 1 +fi + +# Run team/git.sh from webroot directory with proper context +# Pass webroot path as environment variable so team/git.sh knows the context +export WEBROOT_CONTEXT="$(pwd)" +exec ./team/git.sh "$@" \ No newline at end of file diff --git a/grid b/grid new file mode 160000 index 000000000..c39a97da0 --- /dev/null +++ b/grid @@ -0,0 +1 @@ +Subproject commit c39a97da0e24624cd8dfb39d662bc571eb6b59c4 diff --git a/home b/home index 75dfc4eb6..a04686ee8 160000 --- a/home +++ b/home @@ -1 +1 @@ -Subproject commit 75dfc4eb672b1b4a0ce1e15ba989c24dcda659f5 +Subproject commit a04686ee84c412517e11625a348114b69ce90ac6 diff --git a/index.html b/index.html index c4cda626f..967d00f84 100644 --- a/index.html +++ b/index.html @@ -12,43 +12,33 @@ - - @@ -139,7 +110,97 @@
+
+
+
+
+ + + + + - \ No newline at end of file + diff --git a/io b/io index 787b1036d..20fb44c47 160000 --- a/io +++ b/io @@ -1 +1 @@ -Subproject commit 787b1036ddfddf3fb6d6d7a86f5e4a8dc333da25 +Subproject commit 20fb44c476226746cd572f19d39bb79e5d31b64d diff --git a/localsite b/localsite index fe232e5ec..47c3bd99a 160000 --- a/localsite +++ b/localsite @@ -1 +1 @@ -Subproject commit fe232e5ec69e1292640860aace6d464aa8fd5c8f +Subproject commit 47c3bd99a6407286613c19b41e59fc4ff1e25b32 diff --git a/products b/products index ad36e1a0c..08ed5650f 160000 --- a/products +++ b/products @@ -1 +1 @@ -Subproject commit ad36e1a0cf0d2fca70a39410c0562abbc2918c86 +Subproject commit 08ed5650fce49c4b781f44d17c6e71f3caf84fcf diff --git a/products-data b/products-data deleted file mode 160000 index d57c61d78..000000000 --- a/products-data +++ /dev/null @@ -1 +0,0 @@ -Subproject commit d57c61d78fef2d86d57b9a330cd87c6ce5c410f9 diff --git a/profile b/profile index 920b144a5..3a1414f09 160000 --- a/profile +++ b/profile @@ -1 +1 @@ -Subproject commit 920b144a5583d860a94d049c3a47ecadf75a413b +Subproject commit 3a1414f095f5b53da5822094ef123eead44f8ab6 diff --git a/projects b/projects index 4aef1bf1b..38020c3d4 160000 --- a/projects +++ b/projects @@ -1 +1 @@ -Subproject commit 4aef1bf1be4858a4e6f0d548d098e734bd10a5ac +Subproject commit 38020c3d4bca49ba949012280fd75de92d8c99dd diff --git a/realitystream b/realitystream index ba30b274d..f352c9ce3 160000 --- a/realitystream +++ b/realitystream @@ -1 +1 @@ -Subproject commit ba30b274df3719cb409087fb2d1a976f8a0f77fc +Subproject commit f352c9ce3d99d966d70119c033c7b0a6cd0b279e diff --git a/reports b/reports index 23e997780..bd559d2d9 160000 --- a/reports +++ b/reports @@ -1 +1 @@ -Subproject commit 23e99778080c67f331bca9a458a1757494e06cf4 +Subproject commit bd559d2d9655fc02223f6c6378e892c90403c962 diff --git a/streamlit b/streamlit new file mode 160000 index 000000000..23343e2bc --- /dev/null +++ b/streamlit @@ -0,0 +1 @@ +Subproject commit 23343e2bc599e23f33529eae2fe9ba18a6af9f9f diff --git a/swiper b/swiper index 3e2ee56da..9a3deaedf 160000 --- a/swiper +++ b/swiper @@ -1 +1 @@ -Subproject commit 3e2ee56da007e54097c4e54d5dc39f0271d421f6 +Subproject commit 9a3deaedfaa59b278ca80a3ff24700a973a2a2ad diff --git a/team b/team index d51b7a763..52c372a1a 160000 --- a/team +++ b/team @@ -1 +1 @@ -Subproject commit d51b7a763af469fc9e0bea1c6a9e3e0b96a9e455 +Subproject commit 52c372a1aa7bbb27ab55cf3a6dca343342188b87 diff --git a/trade b/trade new file mode 160000 index 000000000..9b44dd368 --- /dev/null +++ b/trade @@ -0,0 +1 @@ +Subproject commit 9b44dd368f41e72215ef3a4e6a3c772404d5700c