chore: cascade main → dev (b28f3be) [skip ci] #1

Merged
jmiller merged 16 commits from main into dev 2026-05-07 19:23:23 +00:00
53 changed files with 2600 additions and 2498 deletions
+78
View File
@@ -0,0 +1,78 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
MokoStandards Repository Manifest
Auto-generated by MokoStandards bulk sync.
Manual edits to <governance> and <last-synced> may be overwritten.
See: docs/standards/mokostandards-file-spec.md
-->
<mokostandards xmlns="https://standards.mokoconsulting.tech/mokostandards/1.0" schema-version="1.0">
<identity>
<name>joomla-api-mcp</name>
<org>MokoConsulting</org>
<description>MCP server for Joomla Web Services API operations</description>
<license spdx="GPL-3.0-or-later">GNU General Public License v3</license>
</identity>
<governance>
<platform>waas-component</platform>
<standards-version>04.07.00</standards-version>
<standards-source>https://git.mokoconsulting.tech/MokoConsulting/MokoStandards</standards-source>
<last-synced>2026-05-02T23:06:09+00:00</last-synced>
</governance>
<build>
<language>Markdown</language>
<package-type>joomla-extension</package-type>
</build>
<deploy>
<target name="dev">
<host>${{ secrets.DEV_HOST }}</host>
<path>${{ secrets.DEV_PATH }}</path>
<method>sftp</method>
<branch>dev/**</branch>
<src-dir>src/</src-dir>
</target>
<target name="demo">
<host>${{ secrets.DEMO_HOST }}</host>
<path>${{ secrets.DEMO_PATH }}</path>
<method>sftp</method>
<branch>main</branch>
<src-dir>src/</src-dir>
</target>
</deploy>
<scripts>
<script name="lint" phase="lint">
<command>make lint</command>
<description>Lint via make</description>
<runner>make</runner>
</script>
<script name="validate" phase="validate">
<command>make validate</command>
<description>Validate via make</description>
<runner>make</runner>
</script>
<script name="test" phase="test">
<command>make test</command>
<description>Test via make</description>
<runner>make</runner>
</script>
<script name="clean" phase="build">
<command>make clean</command>
<description>Clean via make</description>
<runner>make</runner>
</script>
<script name="build" phase="build">
<command>make build</command>
<description>Build via make</description>
<runner>make</runner>
</script>
<script name="package" phase="build">
<command>make package</command>
<description>Package via make</description>
<runner>make</runner>
</script>
<script name="release" phase="release">
<command>make release</command>
<description>Release via make</description>
<runner>make</runner>
</script>
</scripts>
</mokostandards>
@@ -7,7 +7,7 @@
# REPO: https://github.com/mokoconsulting-tech/MokoStandards
# PATH: /.github/workflows/auto-assign.yml
# VERSION: 04.06.00
# BRIEF: Auto-assign jmiller-moko to unassigned issues and PRs every 15 minutes
# BRIEF: Auto-assign jmiller to unassigned issues and PRs every 15 minutes
name: Auto-Assign Issues & PRs
@@ -35,7 +35,7 @@ jobs:
GH_TOKEN: ${{ secrets.GH_TOKEN || github.token }}
run: |
REPO="${{ github.repository }}"
ASSIGNEE="jmiller-moko"
ASSIGNEE="jmiller"
echo "## 🏷️ Auto-Assign Report" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
@@ -135,7 +135,7 @@ jobs:
--title "$SUB_FULL_TITLE" \
--body "$SUB_BODY" \
--label "${SUB_LABELS}" \
--assignee "jmiller-moko" 2>&1)
--assignee "jmiller" 2>&1)
SUB_NUM=$(echo "$SUB_URL" | grep -oE '[0-9]+$')
if [ -n "$SUB_NUM" ]; then
@@ -154,7 +154,7 @@ jobs:
--title "$TITLE" \
--body "$PARENT_BODY" \
--label "${LABEL_TYPE},version" \
--assignee "jmiller-moko" 2>&1)
--assignee "jmiller" 2>&1)
PARENT_NUM=$(echo "$PARENT_URL" | grep -oE '[0-9]+$')
+184
View File
@@ -0,0 +1,184 @@
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
#
# SPDX-License-Identifier: GPL-3.0-or-later
#
# FILE INFORMATION
# DEFGROUP: Gitea.Workflow
# INGROUP: MokoStandards.Maintenance
# REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
# PATH: /templates/workflows/cascade-dev.yml.template
# VERSION: 01.00.00
# BRIEF: Forward-merge main → dev after every push to main
#
# +========================================================================+
# | CASCADE MAIN → DEV |
# +========================================================================+
# | |
# | Triggers on every push to main (PR merges, bot commits, etc.) |
# | |
# | 1. Check if a 'dev' branch exists |
# | 2. Create a PR (main → dev) via Gitea API |
# | 3. Auto-merge if clean; leave open for manual resolution on conflict |
# | |
# +========================================================================+
name: Cascade Main → Dev
on:
push:
branches:
- main
workflow_dispatch:
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
GITEA_URL: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }}
GITEA_ORG: ${{ vars.GITEA_ORG || github.repository_owner }}
GITEA_REPO: ${{ vars.GITEA_REPO || github.event.repository.name }}
permissions:
contents: write
pull-requests: write
jobs:
cascade:
name: Merge main → dev
runs-on: ubuntu-latest
if: >-
!contains(github.event.head_commit.message, '[skip ci]') &&
!contains(github.event.head_commit.message, '[skip cascade]')
steps:
- name: Check dev branch exists
id: check
env:
GA_TOKEN: ${{ secrets.GA_TOKEN }}
run: |
API="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
STATUS=$(curl -sS -o /dev/null -w "%{http_code}" \
-H "Authorization: token ${GA_TOKEN}" \
"${API}/branches/dev")
if [ "$STATUS" = "200" ]; then
echo "exists=true" >> "$GITHUB_OUTPUT"
echo "✅ dev branch exists"
else
echo "exists=false" >> "$GITHUB_OUTPUT"
echo "️ No dev branch found (HTTP ${STATUS}) — skipping cascade"
fi
- name: Check if dev is already up to date
if: steps.check.outputs.exists == 'true'
id: diff
env:
GA_TOKEN: ${{ secrets.GA_TOKEN }}
run: |
API="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
# Compare main..dev — if ahead_by is 0 there's nothing to cascade
RESPONSE=$(curl -sS \
-H "Authorization: token ${GA_TOKEN}" \
"${API}/compare/dev...main")
AHEAD=$(echo "$RESPONSE" | jq '.total_commits // 0')
if [ "$AHEAD" -eq 0 ]; then
echo "needs_merge=false" >> "$GITHUB_OUTPUT"
echo "✅ dev is already up to date with main"
else
echo "needs_merge=true" >> "$GITHUB_OUTPUT"
echo "️ main is ${AHEAD} commit(s) ahead of dev"
fi
- name: Create cascade PR
if: steps.diff.outputs.needs_merge == 'true'
id: pr
env:
GA_TOKEN: ${{ secrets.GA_TOKEN }}
run: |
API="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
SHORT_SHA="${GITHUB_SHA:0:7}"
# Check if a cascade PR already exists (main → dev)
EXISTING=$(curl -sS \
-H "Authorization: token ${GA_TOKEN}" \
"${API}/pulls?state=open&head=${GITEA_ORG}:main&base=dev&limit=1")
EXISTING_COUNT=$(echo "$EXISTING" | jq 'length')
if [ "$EXISTING_COUNT" -gt 0 ]; then
PR_NUMBER=$(echo "$EXISTING" | jq -r '.[0].number')
PR_URL=$(echo "$EXISTING" | jq -r '.[0].html_url')
echo "pr_number=${PR_NUMBER}" >> "$GITHUB_OUTPUT"
echo "pr_exists=true" >> "$GITHUB_OUTPUT"
echo "️ Cascade PR already exists: ${PR_URL}"
else
RESPONSE=$(curl -sS -w "\n%{http_code}" \
-X POST \
-H "Authorization: token ${GA_TOKEN}" \
-H "Content-Type: application/json" \
-d "{
\"title\": \"chore: cascade main → dev (${SHORT_SHA}) [skip ci]\",
\"body\": \"## Automatic cascade\n\nForward-merging \`main\` (${SHORT_SHA}) into \`dev\` to keep branches in sync.\n\nIf this PR has conflicts, please resolve them manually and merge.\n\n> Auto-created by the **Cascade Main → Dev** workflow.\",
\"head\": \"main\",
\"base\": \"dev\"
}" \
"${API}/pulls")
HTTP_CODE=$(echo "$RESPONSE" | tail -1)
BODY=$(echo "$RESPONSE" | sed '$d')
PR_NUMBER=$(echo "$BODY" | jq -r '.number // empty')
PR_URL=$(echo "$BODY" | jq -r '.html_url // empty')
if [ "$HTTP_CODE" = "201" ] && [ -n "$PR_NUMBER" ]; then
echo "pr_number=${PR_NUMBER}" >> "$GITHUB_OUTPUT"
echo "pr_exists=false" >> "$GITHUB_OUTPUT"
echo "✅ Created cascade PR #${PR_NUMBER}: ${PR_URL}"
else
echo "❌ Failed to create PR (HTTP ${HTTP_CODE}): ${BODY}"
exit 1
fi
fi
- name: Auto-merge cascade PR
if: steps.pr.outputs.pr_number != ''
env:
GA_TOKEN: ${{ secrets.GA_TOKEN }}
run: |
API="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
PR_NUMBER="${{ steps.pr.outputs.pr_number }}"
# Check if PR is mergeable
PR_DATA=$(curl -sS \
-H "Authorization: token ${GA_TOKEN}" \
"${API}/pulls/${PR_NUMBER}")
MERGEABLE=$(echo "$PR_DATA" | jq -r '.mergeable // false')
if [ "$MERGEABLE" != "true" ]; then
echo "⚠️ PR #${PR_NUMBER} has conflicts — leaving open for manual resolution"
exit 0
fi
# Merge the PR
RESPONSE=$(curl -sS -w "\n%{http_code}" \
-X POST \
-H "Authorization: token ${GA_TOKEN}" \
-H "Content-Type: application/json" \
-d "{
\"Do\": \"merge\",
\"merge_message_field\": \"chore: cascade main → dev [skip ci]\",
\"delete_branch_after_merge\": false
}" \
"${API}/pulls/${PR_NUMBER}/merge")
HTTP_CODE=$(echo "$RESPONSE" | tail -1)
if [ "$HTTP_CODE" = "200" ] || [ "$HTTP_CODE" = "204" ]; then
echo "✅ Cascade PR #${PR_NUMBER} merged — dev is now in sync with main"
else
BODY=$(echo "$RESPONSE" | sed '$d')
echo "⚠️ Merge failed (HTTP ${HTTP_CODE}): ${BODY}"
echo "PR #${PR_NUMBER} left open for manual resolution"
fi
@@ -94,7 +94,7 @@ jobs:
AUTHORIZED="false"
# Hardcoded authorized users — always allowed to deploy
AUTHORIZED_USERS="jmiller-moko github-actions[bot]"
AUTHORIZED_USERS="jmiller github-actions[bot]"
for user in $AUTHORIZED_USERS; do
if [ "$ACTOR" = "$user" ]; then
AUTHORIZED="true"
@@ -704,7 +704,7 @@ jobs:
--title "$TITLE" \
--body "$BODY" \
--label "$LABEL" \
--assignee "jmiller-moko" \
--assignee "jmiller" \
| tee -a "$GITHUB_STEP_SUMMARY"
fi
@@ -99,7 +99,7 @@ jobs:
AUTHORIZED="false"
# Hardcoded authorized users — always allowed to deploy
AUTHORIZED_USERS="jmiller-moko github-actions[bot]"
AUTHORIZED_USERS="jmiller github-actions[bot]"
for user in $AUTHORIZED_USERS; do
if [ "$ACTOR" = "$user" ]; then
AUTHORIZED="true"
@@ -80,7 +80,7 @@ jobs:
echo "✅ Scheduled run — authorized"
exit 0
fi
AUTHORIZED_USERS="jmiller-moko github-actions[bot]"
AUTHORIZED_USERS="jmiller github-actions[bot]"
for user in $AUTHORIZED_USERS; do
if [ "$ACTOR" = "$user" ]; then
echo "✅ ${ACTOR} authorized"
@@ -2601,7 +2601,7 @@ jobs:
echo "Updated issue #${EXISTING}"
else
gh issue create --repo "$REPO" --title "$TITLE" --body "$BODY" \
--label "$LABEL" --assignee "jmiller-moko"
--label "$LABEL" --assignee "jmiller"
fi
# CUSTOMIZATION:
-309
View File
@@ -1,309 +0,0 @@
<!--
Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
This file is part of a Moko Consulting project.
SPDX-License-Identifier: GPL-3.0-or-later
# FILE INFORMATION
DEFGROUP: MokoStandards.Templates.GitHub
INGROUP: MokoStandards.Templates
REPO: https://github.com/mokoconsulting-tech/MokoStandards
PATH: /templates/github/copilot-instructions.md.template
VERSION: XX.YY.ZZ
BRIEF: Standard GitHub Copilot custom instructions template for Moko Consulting governed repositories
NOTE: Synced to .github/copilot-instructions.md in all governed repositories via bulk sync.
Tokens replaced at sync time: MokoStandards-Template-Generic, https://github.com/mokoconsulting-tech/MokoStandards-Template-Generic, PHP, Generic project
-->
> [!IMPORTANT]
> **🔧 AI Self-Update Required on First Use**
>
> This file may contain unfilled `{{TOKEN}}` placeholders. The MokoStandards bulk-sync system
> replaces them automatically at sync time; if you can still see them, sync has not yet run for
> this repository — or this is a brand-new repo.
>
> **On your very first interaction in this repository, before answering any other question:**
>
> 1. Check whether any `{{TOKEN}}` placeholders remain in this file.
> 2. If they do, locate the values as described in the table below and replace every occurrence
> in **both** `.github/copilot-instructions.md` and `.github/CLAUDE.md`.
> 3. After replacing all tokens, **delete this entire notice block** (from `> [!IMPORTANT]`
> through the closing `> ---` line) in both files.
> 4. Tell the developer: *"I've self-updated the AI context files with this repository's
> values — all set."*
>
> | Placeholder | Where to find the value |
> |---|---|
> | `MokoStandards-Template-Generic` | The GitHub repository name (visible in the URL, `README.md` heading, or `git remote -v`) |
> | `https://github.com/mokoconsulting-tech/MokoStandards-Template-Generic` | Full GitHub URL, e.g. `https://github.com/mokoconsulting-tech/<repo-name>` |
> | `PHP` | The dominant programming language (check file extensions in the repository) |
> | `Generic project` | The project type: `PHP library`, `Joomla extension`, `Dolibarr module`, `WaaS site`, etc. — infer from repo structure |
>
> ---
# MokoStandards-Template-Generic — GitHub Copilot Custom Instructions
## What This Repo Is
This is a **Moko Consulting** repository governed by [MokoStandards](https://github.com/mokoconsulting-tech/MokoStandards). All coding standards, workflows, and policies are defined there and enforced here via bulk sync.
Repository URL: https://github.com/mokoconsulting-tech/MokoStandards-Template-Generic
Primary language: **PHP**
Platform type: **Generic project**
---
## Primary Language
**PHP is the primary language for this repository.** Follow the conventions documented in [MokoStandards coding-style-guide](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/coding-style-guide.md).
YAML uses 2-space indentation (spaces, not tabs). All other text files use tabs per `.editorconfig`.
---
## File Header — Always Required on New Files
Every new file needs a copyright header as its first content. Use the minimal form unless the file is a policy doc, README, or public API.
**PHP:**
```php
<?php
/* Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
*
* This file is part of a Moko Consulting project.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*
* FILE INFORMATION
* DEFGROUP: MokoStandards-Template-Generic.Module
* INGROUP: MokoStandards-Template-Generic
* REPO: https://github.com/mokoconsulting-tech/MokoStandards-Template-Generic
* PATH: /path/to/file.php
* VERSION: XX.YY.ZZ
* BRIEF: One-line description of purpose
*/
declare(strict_types=1);
```
**Markdown:**
```markdown
<!--
Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
This file is part of a Moko Consulting project.
SPDX-License-Identifier: GPL-3.0-or-later
# FILE INFORMATION
DEFGROUP: MokoStandards-Template-Generic.Documentation
INGROUP: MokoStandards-Template-Generic
REPO: https://github.com/mokoconsulting-tech/MokoStandards-Template-Generic
PATH: /docs/file.md
VERSION: XX.YY.ZZ
BRIEF: One-line description
-->
```
**YAML / Shell:** Use `#` comments with the same fields. JSON files are exempt.
---
## Version Management
**`README.md` is the single source of truth for the repository version.**
- **Bump the patch version on every PR** — increment `XX.YY.ZZ` (e.g. `01.02.03``01.02.04`) in `README.md` before opening the PR; the `sync-version-on-merge` workflow propagates it automatically to all badges and `FILE INFORMATION` headers on merge to `main`.
- The `VERSION: XX.YY.ZZ` field in the README.md `FILE INFORMATION` block governs all other version references.
- Update the version in `README.md` only — the `sync-version-on-merge` workflow propagates it automatically to all badges and `FILE INFORMATION` headers on merge to `main`.
- Version format is zero-padded semver: `XX.YY.ZZ` (e.g. `04.00.04`).
- Never hardcode a specific version in document body text — use the badge or FILE INFORMATION header only.
---
## GitHub Actions — Token Usage
Every workflow must use **`secrets.GH_TOKEN`** (the org-level Personal Access Token). This applies to all `actions/checkout`, `gh` CLI calls, and any step that talks to the GitHub API.
```yaml
# ✅ Correct
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
token: ${{ secrets.GH_TOKEN }}
env:
GH_TOKEN: ${{ secrets.GH_TOKEN }}
```
```yaml
# ❌ Wrong — never use these in workflows
token: ${{ github.token }}
token: ${{ secrets.GITHUB_TOKEN }}
```
PHP scripts read the token with: `getenv('GH_TOKEN') ?: getenv('GITHUB_TOKEN')``GH_TOKEN` is always preferred; `GITHUB_TOKEN` is accepted only as a local-dev fallback.
---
## Composer Package (PHP repositories)
This repository requires the MokoStandards enterprise library. The `composer.json` must include:
```json
{
"repositories": [
{
"type": "vcs",
"url": "https://github.com/mokoconsulting-tech/MokoStandards"
}
],
"require": {
"mokoconsulting/mokostandards": "^4.0"
}
}
```
Run `composer install` after adding the dependency. See [package-installation.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/guide/package-installation.md) for full instructions.
---
## PHP Script Pattern
All PHP scripts **must** extend `MokoStandards\Enterprise\CliFramework`. Never write standalone classes or extend the legacy `CliBase`.
```php
#!/usr/bin/env php
<?php
/* … file header … */
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use MokoStandards\Enterprise\CliFramework;
class MyScript extends CliFramework
{
protected function configure(): void
{
$this->setDescription('One-line description');
$this->addArgument('--path', 'Repository root', '.');
$this->addArgument('--dry-run', 'Preview without writing', false);
}
protected function run(): int
{
$path = $this->getArgument('--path');
$dryRun = (bool) $this->getArgument('--dry-run');
$this->log('INFO', "Processing: {$path}");
return 0;
}
}
$script = new MyScript('my_script', 'One-line description');
exit($script->execute());
```
**Key rules:**
- Abstract methods to implement: `configure()` and `run()`**not** `execute()`
- `execute()` is the **public entry point** that orchestrates setup (arg parsing, `initialize()`) and then calls your `run()` implementation; call it at the bottom with `exit($script->execute())`
- Entry point at the bottom: `$script->execute()`**not** `$script->run()`
- Constructor always takes `(string $name, string $description = '')`; pass the description here — `setDescription()` inside `configure()` is only needed to override it
- `log(string $level, string $message)` — level is the **first** argument (INFO / SUCCESS / WARNING / ERROR)
- `$this->dryRun` and `$this->verbose` are set automatically from `--dry-run` / `--verbose`
---
## Naming Conventions
| Context | Convention | Example |
|---------|-----------|---------|
| PHP class | `PascalCase` | `MyService` |
| PHP method / function | `camelCase` | `getUserData()` |
| PHP variable | `$snake_case` | `$repo_path` |
| PHP constant | `UPPER_SNAKE_CASE` | `DEFAULT_THRESHOLD` |
| PHP class file | `PascalCase.php` | `ApiClient.php` |
| PHP script file | `snake_case.php` | `check_health.php` |
| YAML workflow | `kebab-case.yml` | `bulk-repo-sync.yml` |
| Markdown doc | `kebab-case.md` | `coding-style-guide.md` |
---
## Commit Messages
Format: `<type>(<scope>): <subject>` — imperative, lower-case subject, no trailing period.
Valid types: `feat` · `fix` · `docs` · `chore` · `ci` · `refactor` · `style` · `test` · `perf` · `revert` · `build`
Examples:
- `feat(module): add user preference caching`
- `fix(api): handle null response from external service`
- `docs(readme): update installation instructions`
- `chore(deps): bump phpunit to 11.x`
---
## Branch Naming
Approved prefixes: `dev/` · `rc/` · `version/` · `copilot/` · `dependabot/`
- `dev/XX.YY` or `dev/feature-name` — development (version optional)
- `rc/XX.YY.ZZ` — release candidate (three-part required)
- `version/XX.YY` — archive branch (auto-created, two-part)
- Release tags: `vXX` (major only — one release per major version)
- Patch `00` = development (no release), first release = `01`
Examples:
-`dev/04.06` · `dev/new-dashboard` · `rc/04.06.01`
-`feature/my-thing` — rejected by branch protection
---
## Keeping Documentation Current
Whenever you make code changes, update the corresponding documentation in the same commit or PR. Do not leave docs stale.
| Change type | Documentation to update |
|-------------|------------------------|
| New or renamed public PHP method | PHPDoc block on the method; `docs/api/` index for that class |
| New or changed CLI script argument | Script's own `--help` text; `docs/api/` or equivalent |
| New or changed GitHub Actions workflow | `docs/workflows/<workflow-name>.md` |
| New or changed policy | Corresponding file under `docs/policy/` |
| New library class or major feature | `CHANGELOG.md` entry under `Added` |
| Bug fix | `CHANGELOG.md` entry under `Fixed` |
| Breaking change | `CHANGELOG.md` entry under `Changed`; update `CONTRIBUTING.md` if contributor steps change |
| Any modified file | Update the `VERSION` field in that file's `FILE INFORMATION` block |
| **Every PR** | **Bump the patch version** — increment `XX.YY.ZZ` in `README.md`; `sync-version-on-merge` propagates it to all headers and badges on merge |
If your code change makes any existing doc sentence false or incomplete, fix the doc before closing the PR.
---
## Key Constraints
- Never commit directly to `main` — all changes go via PR, squash-merged
- Never skip the FILE INFORMATION block on a new file
- Never use bare `catch (\Throwable $e) {}` without logging or re-throwing
- Never hardcode version numbers in body text — update `README.md` and let automation propagate
- Never use `github.token` or `secrets.GITHUB_TOKEN` in workflows — always use `secrets.GH_TOKEN`
- Never extend `CliBase` in PHP scripts — extend `MokoStandards\Enterprise\CliFramework`
- Never call `$script->run()` as the entry point — call `$script->execute()`
- Policy documents and guides must not be mixed
---
## MokoStandards Reference
This repository is governed by [MokoStandards](https://github.com/mokoconsulting-tech/MokoStandards). Authoritative policies:
| Document | Purpose |
|----------|---------|
| [file-header-standards.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/file-header-standards.md) | Copyright-header rules for every file type |
| [coding-style-guide.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/coding-style-guide.md) | Naming and formatting conventions |
| [branching-strategy.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/branching-strategy.md) | Branch naming, hierarchy, and release workflow |
| [merge-strategy.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/merge-strategy.md) | Squash-merge policy and PR title/body conventions |
| [changelog-standards.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/changelog-standards.md) | How and when to update CHANGELOG.md |
| [scripting-standards.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/scripting-standards.md) | PHP script requirements and CliFramework usage |
| [package-installation.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/guide/package-installation.md) | Installing `mokoconsulting/mokostandards` via Composer |
-54
View File
@@ -1,54 +0,0 @@
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
# SPDX-License-Identifier: GPL-3.0-or-later
#
# CODEOWNERS — require approval from jmiller-moko for protected paths
# Synced from MokoStandards. Do not edit manually.
#
# Changes to these paths require review from the listed owners before merge.
# Combined with branch protection (require PR reviews), this prevents
# unauthorized modifications to workflows, configs, and governance files.
# ── Synced workflows (managed by MokoStandards — do not edit manually) ────
/.github/workflows/deploy-dev.yml @jmiller-moko
/.github/workflows/deploy-demo.yml @jmiller-moko
/.github/workflows/deploy-manual.yml @jmiller-moko
/.github/workflows/auto-release.yml @jmiller-moko
/.github/workflows/auto-dev-issue.yml @jmiller-moko
/.github/workflows/auto-assign.yml @jmiller-moko
/.github/workflows/sync-version-on-merge.yml @jmiller-moko
/.github/workflows/enterprise-firewall-setup.yml @jmiller-moko
/.github/workflows/repository-cleanup.yml @jmiller-moko
/.github/workflows/standards-compliance.yml @jmiller-moko
/.github/workflows/codeql-analysis.yml @jmiller-moko
/.github/workflows/repo_health.yml @jmiller-moko
/.github/workflows/ci-joomla.yml @jmiller-moko
/.github/workflows/update-server.yml @jmiller-moko
/.github/workflows/deploy-manual.yml @jmiller-moko
/.github/workflows/ci-dolibarr.yml @jmiller-moko
/.github/workflows/publish-to-mokodolimods.yml @jmiller-moko
/.github/workflows/changelog-validation.yml @jmiller-moko
# Custom workflows in .github/workflows/ not listed above are repo-owned.
# ── GitHub configuration ─────────────────────────────────────────────────
/.github/ISSUE_TEMPLATE/ @jmiller-moko
/.github/CODEOWNERS @jmiller-moko
/.github/copilot.yml @jmiller-moko
/.github/copilot-instructions.md @jmiller-moko
/.github/CLAUDE.md @jmiller-moko
/.github/.mokostandards @jmiller-moko
# ── Build and config files ───────────────────────────────────────────────
/composer.json @jmiller-moko
/phpstan.neon @jmiller-moko
/Makefile @jmiller-moko
/.ftpignore @jmiller-moko
/.gitignore @jmiller-moko
/.gitattributes @jmiller-moko
/.editorconfig @jmiller-moko
# ── Governance documents ─────────────────────────────────────────────────
/LICENSE @jmiller-moko
/CONTRIBUTING.md @jmiller-moko
/SECURITY.md @jmiller-moko
/GOVERNANCE.md @jmiller-moko
/CODE_OF_CONDUCT.md @jmiller-moko
-125
View File
@@ -1,125 +0,0 @@
---
name: Architecture Decision Record (ADR)
about: Propose or document an architectural decision
title: '[ADR] '
labels: 'architecture, decision'
assignees: ''
---
<!--
SPDX-License-Identifier: GPL-3.0-or-later
Copyright (C) 2024-2026 Moko Consulting Tech
File: .github/ISSUE_TEMPLATE/adr.md
Description: Issue template for Architecture Decision Records
Project: .github-private
Author: Moko Consulting Tech
Version: 03.02.00
Revision History:
- 2026-01-04: Added MokoStandards compliant header with copyright, file info, and metadata
- 2026-03-11: Version bump to 03.02.00 to match MokoStandards
- 2024: Initial creation
-->
## ADR Number
ADR-XXXX
## Status
- [ ] Proposed
- [ ] Accepted
- [ ] Deprecated
- [ ] Superseded by ADR-XXXX
## Context
Describe the issue or problem that motivates this decision.
## Decision
State the architecture decision and provide rationale.
## Consequences
### Positive
- List positive consequences
### Negative
- List negative consequences or trade-offs
### Neutral
- List neutral aspects
## Alternatives Considered
### Alternative 1
- Description
- Pros
- Cons
- Why not chosen
### Alternative 2
- Description
- Pros
- Cons
- Why not chosen
## Implementation Plan
1. Step 1
2. Step 2
3. Step 3
## Stakeholders
- **Decision Makers**: @user1, @user2
- **Consulted**: @user3, @user4
- **Informed**: team-name
## Technical Details
### Architecture Diagram
```
[Add diagram or link]
```
### Dependencies
- Dependency 1
- Dependency 2
### Impact Analysis
- **Performance**: [Impact description]
- **Security**: [Impact description]
- **Scalability**: [Impact description]
- **Maintainability**: [Impact description]
## Testing Strategy
- [ ] Unit tests
- [ ] Integration tests
- [ ] Performance tests
- [ ] Security tests
## Documentation
- [ ] Architecture documentation updated
- [ ] API documentation updated
- [ ] Developer guide updated
- [ ] Runbook created
## Migration Path
Describe how to migrate from current state to new architecture.
## Rollback Plan
Describe how to rollback if issues occur.
## Timeline
- **Proposal Date**:
- **Decision Date**:
- **Implementation Start**:
- **Expected Completion**:
## References
- Related ADRs:
- External resources:
- RFCs:
## Review Checklist
- [ ] Aligns with enterprise architecture principles
- [ ] Security implications reviewed
- [ ] Performance implications reviewed
- [ ] Cost implications reviewed
- [ ] Compliance requirements met
- [ ] Team consensus achieved
-63
View File
@@ -1,63 +0,0 @@
---
name: Bug Report
about: Report a bug or issue with the project
title: '[BUG] '
labels: 'bug'
assignees: ''
---
<!--
SPDX-License-Identifier: GPL-3.0-or-later
Copyright (C) 2024-2026 Moko Consulting Tech
File: .github/ISSUE_TEMPLATE/bug_report.md
Description: Issue template for bug reports
Project: .github-private
Author: Moko Consulting Tech
Version: 03.02.00
Revision History:
- 2026-01-04: Added MokoStandards compliant header with copyright, file info, and metadata
- 2026-03-11: Version bump to 03.02.00 to match MokoStandards
- 2024: Initial creation
-->
## Bug Description
A clear and concise description of what the bug is.
## Steps to Reproduce
1. Go to '...'
2. Click on '...'
3. Scroll down to '...'
4. See error
## Expected Behavior
A clear and concise description of what you expected to happen.
## Actual Behavior
A clear and concise description of what actually happened.
## Screenshots
If applicable, add screenshots to help explain your problem.
## Environment
- **Project**: [e.g., MokoDoliTools, moko-cassiopeia]
- **Version**: [e.g., 1.2.3]
- **Platform**: [e.g., Dolibarr 18.0, Joomla 5.0]
- **PHP Version**: [e.g., 8.1]
- **Database**: [e.g., MySQL 8.0, PostgreSQL 14]
- **Browser** (if applicable): [e.g., Chrome 120, Firefox 121]
- **OS**: [e.g., Ubuntu 22.04, Windows 11]
## Additional Context
Add any other context about the problem here.
## Possible Solution
If you have suggestions on how to fix the issue, please describe them here.
## Checklist
- [ ] I have searched for similar issues before creating this one
- [ ] I have provided all the requested information
- [ ] I have tested this on the latest stable version
- [ ] I have checked the documentation and couldn't find a solution
-18
View File
@@ -1,18 +0,0 @@
---
blank_issues_enabled: true
contact_links:
- name: 💼 Enterprise Support
url: https://mokoconsulting.tech/enterprise
about: Enterprise-level support and consultation services
- name: 💬 Ask a Question
url: https://mokoconsulting.tech/
about: Get help or ask questions through our website
- name: 📚 MokoStandards Documentation
url: https://github.com/mokoconsulting-tech/MokoStandards
about: View our coding standards and best practices
- name: 🔒 Report a Security Vulnerability
url: https://github.com/mokoconsulting-tech/.github-private/security/advisories/new
about: Report security vulnerabilities privately (for critical issues)
- name: 💡 Community Discussions
url: https://github.com/orgs/mokoconsulting-tech/discussions
about: Join community discussions and Q&A
-67
View File
@@ -1,67 +0,0 @@
---
name: Documentation Issue
about: Report an issue with documentation
title: '[DOCS] '
labels: 'documentation'
assignees: ''
---
<!--
SPDX-License-Identifier: GPL-3.0-or-later
Copyright (C) 2024-2026 Moko Consulting Tech
File: .github/ISSUE_TEMPLATE/documentation.md
Description: Issue template for documentation-related issues
Project: .github-private
Author: Moko Consulting Tech
Version: 03.02.00
Revision History:
- 2026-01-04: Added MokoStandards compliant header with copyright, file info, and metadata
- 2026-03-11: Version bump to 03.02.00 to match MokoStandards
- 2024: Initial creation
-->
## Documentation Issue
**Location**:
<!-- Specify the file, page, or section with the issue -->
## Issue Type
<!-- Mark the relevant option with an "x" -->
- [ ] Typo or grammar error
- [ ] Outdated information
- [ ] Missing documentation
- [ ] Unclear explanation
- [ ] Broken links
- [ ] Missing examples
- [ ] Other (specify below)
## Description
<!-- Clearly describe the documentation issue -->
## Current Content
<!-- Quote or describe the current documentation (if applicable) -->
```
Current text here
```
## Suggested Improvement
<!-- Provide your suggestion for how to improve the documentation -->
```
Suggested text here
```
## Additional Context
<!-- Add any other context, screenshots, or references -->
## Standards Alignment
- [ ] Follows MokoStandards documentation guidelines
- [ ] Uses en_US/en_GB localization
- [ ] Includes proper SPDX headers where applicable
## Checklist
- [ ] I have searched for similar documentation issues
- [ ] I have provided a clear description
- [ ] I have suggested an improvement (if applicable)
@@ -1,100 +0,0 @@
---
name: Enterprise Support Request
about: Request enterprise-level support or consultation
title: '[ENTERPRISE] '
labels: 'enterprise, support'
assignees: ''
---
<!--
SPDX-License-Identifier: GPL-3.0-or-later
Copyright (C) 2024-2026 Moko Consulting Tech
File: .github/ISSUE_TEMPLATE/enterprise_support.md
Description: Issue template for enterprise support requests
Project: .github-private
Author: Moko Consulting Tech
Version: 03.02.00
Revision History:
- 2026-01-04: Added MokoStandards compliant header with copyright, file info, and metadata
- 2026-03-11: Version bump to 03.02.00 to match MokoStandards
- 2024: Initial creation
-->
## Support Request Type
- [ ] Critical Production Issue
- [ ] Performance Optimization
- [ ] Security Audit
- [ ] Architecture Review
- [ ] Custom Development
- [ ] Migration Support
- [ ] Training & Onboarding
- [ ] Other (please specify)
## Priority Level
- [ ] P0 - Critical (Production Down)
- [ ] P1 - High (Major Feature Broken)
- [ ] P2 - Medium (Non-Critical Issue)
- [ ] P3 - Low (Enhancement/Question)
## Organization Details
- **Company Name**:
- **Contact Person**:
- **Email**:
- **Phone** (for P0/P1 issues):
- **Timezone**:
## Issue Description
Provide a clear and detailed description of your request or issue.
## Business Impact
Describe the impact on your business operations:
- Number of users affected:
- Revenue impact (if applicable):
- Deadline/SLA requirements:
## Environment Details
- **Deployment Type**: [On-Premise / Cloud / Hybrid]
- **Platform**: [Joomla / Dolibarr / Custom]
- **Version**:
- **Infrastructure**: [AWS / Azure / GCP / Other]
- **Scale**: [Users / Transactions / Data Volume]
## Current Configuration
```yaml
# Paste relevant configuration (sanitize sensitive data)
```
## Logs and Diagnostics
```
# Paste relevant logs (sanitize sensitive data)
```
## Attempted Solutions
Describe any troubleshooting steps already taken.
## Expected Resolution
Describe your expected outcome or resolution.
## Additional Resources
- **Documentation Links**:
- **Related Issues**:
- **Screenshots/Videos**:
## Enterprise SLA
- [ ] Standard Support (initial response within 13 weeks)
- [ ] Premium Support (initial response within 5 business days)
- [ ] Critical Support (initial response within 72 hours)
- [ ] Custom SLA (specify):
## Compliance Requirements
- [ ] GDPR
- [ ] HIPAA
- [ ] SOC 2
- [ ] ISO 27001
- [ ] Other (specify):
---
**Note**: Enterprise support requests require an active support contract. If you don't have one, please contact us at enterprise@mokoconsulting.tech
-66
View File
@@ -1,66 +0,0 @@
---
name: Feature Request
about: Suggest a new feature or enhancement
title: '[FEATURE] '
labels: 'enhancement'
assignees: ''
---
<!--
SPDX-License-Identifier: GPL-3.0-or-later
Copyright (C) 2024-2026 Moko Consulting Tech
File: .github/ISSUE_TEMPLATE/feature_request.md
Description: Issue template for feature requests
Project: .github-private
Author: Moko Consulting Tech
Version: 03.02.00
Revision History:
- 2026-01-04: Added MokoStandards compliant header with copyright, file info, and metadata
- 2026-03-11: Version bump to 03.02.00 to match MokoStandards
- 2024: Initial creation
-->
## Feature Description
A clear and concise description of the feature you'd like to see.
## Problem or Use Case
Describe the problem this feature would solve or the use case it addresses.
Ex. I'm always frustrated when [...]
## Proposed Solution
A clear and concise description of what you want to happen.
## Alternative Solutions
A clear and concise description of any alternative solutions or features you've considered.
## Benefits
Describe how this feature would benefit users:
- Who would use this feature?
- What problems does it solve?
- What value does it add?
## Implementation Details (Optional)
If you have ideas about how this could be implemented, share them here:
- Technical approach
- Files/components that might need changes
- Any concerns or challenges you foresee
## Additional Context
Add any other context, mockups, or screenshots about the feature request here.
## Relevant Standards
Does this relate to any standards in [MokoStandards](https://github.com/mokoconsulting-tech/MokoStandards)?
- [ ] Accessibility (WCAG 2.1 AA)
- [ ] Localization (en_US/en_GB)
- [ ] Security best practices
- [ ] Code quality standards
- [ ] Other: [specify]
## Checklist
- [ ] I have searched for similar feature requests before creating this one
- [ ] I have clearly described the use case and benefits
- [ ] I have considered alternative solutions
- [ ] This feature aligns with the project's goals and scope
-203
View File
@@ -1,203 +0,0 @@
---
name: Firewall Request
about: Request firewall rule changes or access to external resources
title: '[FIREWALL] [Resource Name] - [Brief Description]'
labels: ['firewall-request', 'infrastructure', 'security']
assignees: []
---
<!--
SPDX-License-Identifier: GPL-3.0-or-later
Copyright (C) 2024-2026 Moko Consulting Tech
File: .github/ISSUE_TEMPLATE/firewall-request.md
Description: Issue template for firewall rule change and access requests
Project: .github-private
Author: Moko Consulting Tech
Version: 03.02.00
Revision History:
- 2026-03-11: Added SPDX header and version to match MokoStandards 03.02.00
-->
## Firewall Request
### Request Type
- [ ] Allow outbound access to external service/API
- [ ] Allow inbound access from external source
- [ ] Modify existing firewall rule
- [ ] Remove/revoke firewall rule
- [ ] Other (specify):
### Resource Information
**Service/Domain Name**:
**IP Address(es)**:
**Port(s)**:
**Protocol**:
- [ ] HTTP (80)
- [ ] HTTPS (443)
- [ ] SSH (22)
- [ ] FTP (21)
- [ ] SFTP (22)
- [ ] Custom (specify): _______________
### Requestor Information
**Name**:
**GitHub Username**: @
**Email**: @mokoconsulting.tech
**Team/Department**:
**Manager**: @
### Business Justification
**Why is this access needed?**
**Which project(s) require this access?**
**What functionality will break without this access?**
**Is there an alternative solution?**
- [ ] Yes (explain):
- [ ] No
### Security Considerations
**Data Classification**:
- [ ] Public
- [ ] Internal
- [ ] Confidential
- [ ] Restricted
**Sensitive Data Transmission**:
- [ ] No sensitive data will be transmitted
- [ ] Sensitive data will be transmitted (encryption required)
- [ ] Authentication credentials will be transmitted (secure storage required)
**Third-Party Service**:
- [ ] This is a trusted/verified third-party service
- [ ] This is a new/unverified service (security review required)
**Service Documentation**:
(Provide link to service documentation or API specs)
### Access Scope
**Affected Systems**:
- [ ] Development environment only
- [ ] Staging environment only
- [ ] Production environment
- [ ] All environments
**Access Duration**:
- [ ] Permanent (ongoing business need)
- [ ] Temporary (specify end date): _______________
- [ ] Testing only (specify duration): _______________
### Technical Details
**Source System(s)**:
(Which internal systems need access?)
**Destination System(s)**:
(Which external systems need to be accessed?)
**Expected Traffic Volume**:
(e.g., requests per hour/day)
**Traffic Pattern**:
- [ ] Continuous
- [ ] Periodic (specify frequency): _______________
- [ ] On-demand/manual
- [ ] Scheduled (specify schedule): _______________
### Testing Requirements
**Pre-Production Testing**:
- [ ] Request includes dev/staging access for testing
- [ ] Testing can be done with production access only
- [ ] No testing required (modify existing rule)
**Testing Plan**:
**Rollback Plan**:
(What happens if access needs to be revoked?)
### Compliance & Audit
**Compliance Requirements**:
- [ ] GDPR considerations
- [ ] SOC 2 compliance required
- [ ] PCI DSS considerations
- [ ] Other regulatory requirements: _______________
- [ ] No specific compliance requirements
**Audit/Logging Requirements**:
- [ ] Standard logging sufficient
- [ ] Enhanced logging/monitoring required
- [ ] Real-time alerting required
### Urgency
- [ ] Critical (production down, immediate access needed)
- [ ] High (needed within 24 hours)
- [ ] Normal (needed within 1 week)
- [ ] Low priority (needed within 1 month)
**If critical/high urgency, explain why:**
### Approvals
**Manager Approval**:
- [ ] Manager has been notified and approves this request
**Security Team Review Required**:
- [ ] Yes (new external service, sensitive data)
- [ ] No (minor change, established service)
### Additional Information
**Related Documentation**:
(Links to relevant docs, RFCs, tickets, etc.)
**Dependencies**:
(Other systems or changes this depends on)
**Comments/Questions**:
---
## For Infrastructure/Security Team Use Only
**Do not edit below this line**
### Security Review
- [ ] Security team review completed
- [ ] Risk assessment: Low / Medium / High
- [ ] Encryption required: Yes / No
- [ ] VPN required: Yes / No
- [ ] Additional security controls: _______________
**Reviewed By**: @_______________
**Review Date**: _______________
**Review Notes**:
### Implementation
- [ ] Firewall rule created/modified
- [ ] Rule tested in dev/staging
- [ ] Rule deployed to production
- [ ] Monitoring/alerting configured
- [ ] Documentation updated
**Firewall Rule ID**: _______________
**Implementation Date**: _______________
**Implemented By**: @_______________
**Configuration Details**:
```
Source:
Destination:
Port/Protocol:
Action: Allow/Deny
```
### Verification
- [ ] Requestor confirmed access working
- [ ] Logs reviewed (no anomalies)
- [ ] Security scan completed (if applicable)
**Verification Date**: _______________
**Verified By**: @_______________
### Notes
-86
View File
@@ -1,86 +0,0 @@
---
name: Question
about: Ask a question about usage, features, or best practices
title: '[QUESTION] '
labels: ['question']
assignees: []
---
<!--
Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
SPDX-License-Identifier: GPL-3.0-or-later
-->
## Question
**Your question:**
## Context
**What are you trying to accomplish?**
**What have you already tried?**
**Category**:
- [ ] Script usage
- [ ] Configuration
- [ ] Workflow setup
- [ ] Documentation interpretation
- [ ] Best practices
- [ ] Integration
- [ ] Other: __________
## Environment (if relevant)
**Your setup**:
- Operating System:
- Version:
## What You've Researched
**Documentation reviewed**:
- [ ] README.md
- [ ] Project documentation
- [ ] Other (specify): __________
**Similar issues/questions found**:
- #
- #
## Expected Outcome
**What result are you hoping for?**
## Code/Configuration Samples
**Relevant code or configuration** (if applicable):
```bash
# Your code here
```
## Additional Context
**Any other relevant information:**
**Screenshots** (if helpful):
## Urgency
- [ ] Urgent (blocking work)
- [ ] Normal (can work on other things meanwhile)
- [ ] Low priority (just curious)
## Checklist
- [ ] I have searched existing issues and discussions
- [ ] I have reviewed relevant documentation
- [ ] I have provided sufficient context
- [ ] I have included code/configuration samples if relevant
- [ ] This is a genuine question (not a bug report or feature request)
-120
View File
@@ -1,120 +0,0 @@
---
name: License Request
about: Request an organization license for Sublime Text
title: '[LICENSE REQUEST] Sublime Text - [Your Name]'
labels: ['license-request', 'admin']
assignees: []
---
<!--
SPDX-License-Identifier: GPL-3.0-or-later
Copyright (C) 2024-2026 Moko Consulting Tech
File: .github/ISSUE_TEMPLATE/request-license.md
Description: Issue template for organization software license requests
Project: .github-private
Author: Moko Consulting Tech
Version: 03.02.00
Revision History:
- 2026-03-11: Added SPDX header and version to match MokoStandards 03.02.00
-->
## License Request
### Tool Information
**Tool Name**: Sublime Text
**License Type Requested**: Organization Pool
**Personal Purchase**:
- [ ] I prefer to purchase my own license ($99 USD - recommended, immediate access)
- [ ] I prefer an organization license (1-2 business days, organization use only)
- [ ] I have already purchased my own license (registration only for support)
### Requestor Information
**Name**:
**GitHub Username**: @
**Email**: @mokoconsulting.tech
**Team/Department**:
**Manager**: @
### Justification
**Why do you need this license?**
**Primary use case**:
- [ ] Remote development (SFTP to servers)
- [ ] Local development
- [ ] Code review
- [ ] Documentation editing
- [ ] Other (specify):
**Which projects/repositories will you work on?**
**Have you evaluated the free trial?**
- [ ] Yes, I've used the trial and Sublime Text meets my needs
- [ ] No, requesting license before trial
**Alternative tools considered**:
- [ ] VS Code (free alternative)
- [ ] Vim/Neovim (free, terminal-based)
- [ ] Other: _______________
### Platform
- [ ] Windows
- [ ] macOS
- [ ] Linux (distribution: ________)
### Urgency
- [ ] Urgent (needed within 24 hours - please justify)
- [ ] Normal (1-2 business days)
- [ ] Low priority (when available)
**If urgent, please explain why:**
### SFTP Plugin
**Note**: Sublime SFTP plugin ($16 USD) is a **separate personal purchase** and is NOT provided by the organization.
- [ ] I understand SFTP plugin requires separate personal purchase
- [ ] I have already purchased SFTP plugin
- [ ] I will purchase SFTP plugin if needed for my work
- [ ] I don't need SFTP plugin (local development only)
### Acknowledgments
- [ ] I have read the License Management Policy (/docs/github-private/LICENSE_MANAGEMENT.md)
- [ ] I understand organization licenses are for work use only
- [ ] I understand organization licenses must be returned upon leaving
- [ ] I understand personal purchases ($99) are an alternative with lifetime access
- [ ] I understand SFTP plugin ($16) requires separate personal purchase
- [ ] I agree to the terms of use
### Additional Information
**Expected daily usage hours**: _____ hours/day
**Duration of need**:
- [ ] Permanent (ongoing role)
- [ ] Temporary project (_____ months)
- [ ] Trial/Evaluation (_____ weeks)
**Comments/Questions**:
---
## For Admin Use Only
**Do not edit below this line**
- [ ] Manager approval received (@manager-username)
- [ ] License available in pool (current: __/20)
- [ ] License type confirmed (Organization / Personal registration)
- [ ] License key sent via encrypted email
- [ ] Activation confirmed by user
- [ ] Added to license tracking sheet
- [ ] User notified of SFTP plugin requirement
**License Key ID**: _____________
**Date Issued**: _____________
**Issued By**: @_____________
**Notes**:
-141
View File
@@ -1,141 +0,0 @@
---
name: Request for Comments (RFC)
about: Propose a significant change for community discussion
title: '[RFC] '
labels: 'rfc, discussion'
assignees: ''
---
<!--
SPDX-License-Identifier: GPL-3.0-or-later
Copyright (C) 2024-2026 Moko Consulting Tech
File: .github/ISSUE_TEMPLATE/rfc.md
Description: Issue template for Request for Comments proposals
Project: .github-private
Author: Moko Consulting Tech
Version: 03.02.00
Revision History:
- 2026-01-04: Added MokoStandards compliant header with copyright, file info, and metadata
- 2026-03-11: Version bump to 03.02.00 to match MokoStandards
- 2024: Initial creation
-->
## RFC Summary
One-paragraph summary of the proposal.
## Motivation
Why are we doing this? What use cases does it support? What is the expected outcome?
## Detailed Design
### Overview
Provide a detailed explanation of the proposed change.
### API Changes (if applicable)
```php
// Before
function oldApi($param1) { }
// After
function newApi($param1, $param2) { }
```
### User Experience Changes
Describe how users will interact with this change.
### Implementation Approach
High-level implementation strategy.
## Drawbacks
Why should we *not* do this?
## Alternatives
What other designs have been considered? What is the impact of not doing this?
### Alternative 1
- Description
- Trade-offs
### Alternative 2
- Description
- Trade-offs
## Adoption Strategy
How will existing users adopt this? Is this a breaking change?
### Migration Guide
```bash
# Steps to migrate
```
### Deprecation Timeline
- **Announcement**:
- **Deprecation**:
- **Removal**:
## Unresolved Questions
- Question 1
- Question 2
## Future Possibilities
What future work does this enable?
## Impact Assessment
### Performance
Expected performance impact.
### Security
Security considerations and implications.
### Compatibility
- **Backward Compatible**: [Yes / No]
- **Breaking Changes**: [List]
### Maintenance
Long-term maintenance considerations.
## Community Input
### Stakeholders
- [ ] Core team
- [ ] Module developers
- [ ] End users
- [ ] Enterprise customers
### Feedback Period
**Duration**: [e.g., 2 weeks]
**Deadline**: [date]
## Implementation Timeline
### Phase 1: Design
- [ ] RFC discussion
- [ ] Design finalization
- [ ] Approval
### Phase 2: Implementation
- [ ] Core implementation
- [ ] Tests
- [ ] Documentation
### Phase 3: Release
- [ ] Beta release
- [ ] Feedback collection
- [ ] Stable release
## Success Metrics
How will we measure success?
- Metric 1
- Metric 2
## References
- Related RFCs:
- External documentation:
- Prior art:
## Open Questions for Community
1. Question 1?
2. Question 2?
---
**Note**: This RFC is open for community discussion. Please provide feedback in the comments below.
-66
View File
@@ -1,66 +0,0 @@
---
name: Security Vulnerability Report
about: Report a security vulnerability (use only for non-critical issues)
title: '[SECURITY] '
labels: 'security'
assignees: ''
---
<!--
SPDX-License-Identifier: GPL-3.0-or-later
Copyright (C) 2024-2026 Moko Consulting Tech
File: .github/ISSUE_TEMPLATE/security.md
Description: Issue template for security vulnerability reports
Project: .github-private
Author: Moko Consulting Tech
Version: 03.02.00
Revision History:
- 2026-01-04: Added MokoStandards compliant header with copyright, file info, and metadata
- 2026-03-11: Version bump to 03.02.00 to match MokoStandards
- 2024: Initial creation
-->
## ⚠️ IMPORTANT: Private Disclosure Required
**For critical security vulnerabilities, DO NOT use this template.**
Follow the process in [SECURITY.md](../SECURITY.md) for responsible disclosure.
Use this template only for:
- Security improvements
- Non-critical security suggestions
- Security documentation updates
---
## Security Issue
**Severity**:
<!-- Low, Medium, or informational only -->
## Description
<!-- Describe the security concern or improvement suggestion -->
## Affected Components
<!-- List the affected files, features, or components -->
## Suggested Mitigation
<!-- Describe how this could be addressed -->
## Standards Reference
Does this relate to security standards in [MokoStandards](https://github.com/mokoconsulting-tech/MokoStandards)?
- [ ] SPDX license identifiers
- [ ] Secret management
- [ ] Dependency security
- [ ] Access control
- [ ] Other: [specify]
## Additional Context
<!-- Add any other context about the security concern -->
## Checklist
- [ ] This is NOT a critical vulnerability requiring private disclosure
- [ ] I have reviewed the SECURITY.md policy
- [ ] I have provided sufficient detail for evaluation
-309
View File
@@ -1,309 +0,0 @@
<!--
Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
This file is part of a Moko Consulting project.
SPDX-License-Identifier: GPL-3.0-or-later
# FILE INFORMATION
DEFGROUP: MokoStandards.Templates.GitHub
INGROUP: MokoStandards.Templates
REPO: https://github.com/mokoconsulting-tech/MokoStandards
PATH: /templates/github/copilot-instructions.md.template
VERSION: XX.YY.ZZ
BRIEF: Standard GitHub Copilot custom instructions template for Moko Consulting governed repositories
NOTE: Synced to .github/copilot-instructions.md in all governed repositories via bulk sync.
Tokens replaced at sync time: MokoStandards-Template-Generic, https://github.com/mokoconsulting-tech/MokoStandards-Template-Generic, PHP, Generic project
-->
> [!IMPORTANT]
> **🔧 AI Self-Update Required on First Use**
>
> This file may contain unfilled `{{TOKEN}}` placeholders. The MokoStandards bulk-sync system
> replaces them automatically at sync time; if you can still see them, sync has not yet run for
> this repository — or this is a brand-new repo.
>
> **On your very first interaction in this repository, before answering any other question:**
>
> 1. Check whether any `{{TOKEN}}` placeholders remain in this file.
> 2. If they do, locate the values as described in the table below and replace every occurrence
> in **both** `.github/copilot-instructions.md` and `.github/CLAUDE.md`.
> 3. After replacing all tokens, **delete this entire notice block** (from `> [!IMPORTANT]`
> through the closing `> ---` line) in both files.
> 4. Tell the developer: *"I've self-updated the AI context files with this repository's
> values — all set."*
>
> | Placeholder | Where to find the value |
> |---|---|
> | `MokoStandards-Template-Generic` | The GitHub repository name (visible in the URL, `README.md` heading, or `git remote -v`) |
> | `https://github.com/mokoconsulting-tech/MokoStandards-Template-Generic` | Full GitHub URL, e.g. `https://github.com/mokoconsulting-tech/<repo-name>` |
> | `PHP` | The dominant programming language (check file extensions in the repository) |
> | `Generic project` | The project type: `PHP library`, `Joomla extension`, `Dolibarr module`, `WaaS site`, etc. — infer from repo structure |
>
> ---
# MokoStandards-Template-Generic — GitHub Copilot Custom Instructions
## What This Repo Is
This is a **Moko Consulting** repository governed by [MokoStandards](https://github.com/mokoconsulting-tech/MokoStandards). All coding standards, workflows, and policies are defined there and enforced here via bulk sync.
Repository URL: https://github.com/mokoconsulting-tech/MokoStandards-Template-Generic
Primary language: **PHP**
Platform type: **Generic project**
---
## Primary Language
**PHP is the primary language for this repository.** Follow the conventions documented in [MokoStandards coding-style-guide](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/coding-style-guide.md).
YAML uses 2-space indentation (spaces, not tabs). All other text files use tabs per `.editorconfig`.
---
## File Header — Always Required on New Files
Every new file needs a copyright header as its first content. Use the minimal form unless the file is a policy doc, README, or public API.
**PHP:**
```php
<?php
/* Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
*
* This file is part of a Moko Consulting project.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*
* FILE INFORMATION
* DEFGROUP: MokoStandards-Template-Generic.Module
* INGROUP: MokoStandards-Template-Generic
* REPO: https://github.com/mokoconsulting-tech/MokoStandards-Template-Generic
* PATH: /path/to/file.php
* VERSION: XX.YY.ZZ
* BRIEF: One-line description of purpose
*/
declare(strict_types=1);
```
**Markdown:**
```markdown
<!--
Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
This file is part of a Moko Consulting project.
SPDX-License-Identifier: GPL-3.0-or-later
# FILE INFORMATION
DEFGROUP: MokoStandards-Template-Generic.Documentation
INGROUP: MokoStandards-Template-Generic
REPO: https://github.com/mokoconsulting-tech/MokoStandards-Template-Generic
PATH: /docs/file.md
VERSION: XX.YY.ZZ
BRIEF: One-line description
-->
```
**YAML / Shell:** Use `#` comments with the same fields. JSON files are exempt.
---
## Version Management
**`README.md` is the single source of truth for the repository version.**
- **Bump the patch version on every PR** — increment `XX.YY.ZZ` (e.g. `01.02.03``01.02.04`) in `README.md` before opening the PR; the `sync-version-on-merge` workflow propagates it automatically to all badges and `FILE INFORMATION` headers on merge to `main`.
- The `VERSION: XX.YY.ZZ` field in the README.md `FILE INFORMATION` block governs all other version references.
- Update the version in `README.md` only — the `sync-version-on-merge` workflow propagates it automatically to all badges and `FILE INFORMATION` headers on merge to `main`.
- Version format is zero-padded semver: `XX.YY.ZZ` (e.g. `04.00.04`).
- Never hardcode a specific version in document body text — use the badge or FILE INFORMATION header only.
---
## GitHub Actions — Token Usage
Every workflow must use **`secrets.GH_TOKEN`** (the org-level Personal Access Token). This applies to all `actions/checkout`, `gh` CLI calls, and any step that talks to the GitHub API.
```yaml
# ✅ Correct
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
token: ${{ secrets.GH_TOKEN }}
env:
GH_TOKEN: ${{ secrets.GH_TOKEN }}
```
```yaml
# ❌ Wrong — never use these in workflows
token: ${{ github.token }}
token: ${{ secrets.GITHUB_TOKEN }}
```
PHP scripts read the token with: `getenv('GH_TOKEN') ?: getenv('GITHUB_TOKEN')``GH_TOKEN` is always preferred; `GITHUB_TOKEN` is accepted only as a local-dev fallback.
---
## Composer Package (PHP repositories)
This repository requires the MokoStandards enterprise library. The `composer.json` must include:
```json
{
"repositories": [
{
"type": "vcs",
"url": "https://github.com/mokoconsulting-tech/MokoStandards"
}
],
"require": {
"mokoconsulting/mokostandards": "^4.0"
}
}
```
Run `composer install` after adding the dependency. See [package-installation.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/guide/package-installation.md) for full instructions.
---
## PHP Script Pattern
All PHP scripts **must** extend `MokoStandards\Enterprise\CliFramework`. Never write standalone classes or extend the legacy `CliBase`.
```php
#!/usr/bin/env php
<?php
/* … file header … */
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use MokoStandards\Enterprise\CliFramework;
class MyScript extends CliFramework
{
protected function configure(): void
{
$this->setDescription('One-line description');
$this->addArgument('--path', 'Repository root', '.');
$this->addArgument('--dry-run', 'Preview without writing', false);
}
protected function run(): int
{
$path = $this->getArgument('--path');
$dryRun = (bool) $this->getArgument('--dry-run');
$this->log('INFO', "Processing: {$path}");
return 0;
}
}
$script = new MyScript('my_script', 'One-line description');
exit($script->execute());
```
**Key rules:**
- Abstract methods to implement: `configure()` and `run()`**not** `execute()`
- `execute()` is the **public entry point** that orchestrates setup (arg parsing, `initialize()`) and then calls your `run()` implementation; call it at the bottom with `exit($script->execute())`
- Entry point at the bottom: `$script->execute()`**not** `$script->run()`
- Constructor always takes `(string $name, string $description = '')`; pass the description here — `setDescription()` inside `configure()` is only needed to override it
- `log(string $level, string $message)` — level is the **first** argument (INFO / SUCCESS / WARNING / ERROR)
- `$this->dryRun` and `$this->verbose` are set automatically from `--dry-run` / `--verbose`
---
## Naming Conventions
| Context | Convention | Example |
|---------|-----------|---------|
| PHP class | `PascalCase` | `MyService` |
| PHP method / function | `camelCase` | `getUserData()` |
| PHP variable | `$snake_case` | `$repo_path` |
| PHP constant | `UPPER_SNAKE_CASE` | `DEFAULT_THRESHOLD` |
| PHP class file | `PascalCase.php` | `ApiClient.php` |
| PHP script file | `snake_case.php` | `check_health.php` |
| YAML workflow | `kebab-case.yml` | `bulk-repo-sync.yml` |
| Markdown doc | `kebab-case.md` | `coding-style-guide.md` |
---
## Commit Messages
Format: `<type>(<scope>): <subject>` — imperative, lower-case subject, no trailing period.
Valid types: `feat` · `fix` · `docs` · `chore` · `ci` · `refactor` · `style` · `test` · `perf` · `revert` · `build`
Examples:
- `feat(module): add user preference caching`
- `fix(api): handle null response from external service`
- `docs(readme): update installation instructions`
- `chore(deps): bump phpunit to 11.x`
---
## Branch Naming
Approved prefixes: `dev/` · `rc/` · `version/` · `copilot/` · `dependabot/`
- `dev/XX.YY` or `dev/feature-name` — development (version optional)
- `rc/XX.YY.ZZ` — release candidate (three-part required)
- `version/XX.YY` — archive branch (auto-created, two-part)
- Release tags: `vXX` (major only — one release per major version)
- Patch `00` = development (no release), first release = `01`
Examples:
-`dev/04.06` · `dev/new-dashboard` · `rc/04.06.01`
-`feature/my-thing` — rejected by branch protection
---
## Keeping Documentation Current
Whenever you make code changes, update the corresponding documentation in the same commit or PR. Do not leave docs stale.
| Change type | Documentation to update |
|-------------|------------------------|
| New or renamed public PHP method | PHPDoc block on the method; `docs/api/` index for that class |
| New or changed CLI script argument | Script's own `--help` text; `docs/api/` or equivalent |
| New or changed GitHub Actions workflow | `docs/workflows/<workflow-name>.md` |
| New or changed policy | Corresponding file under `docs/policy/` |
| New library class or major feature | `CHANGELOG.md` entry under `Added` |
| Bug fix | `CHANGELOG.md` entry under `Fixed` |
| Breaking change | `CHANGELOG.md` entry under `Changed`; update `CONTRIBUTING.md` if contributor steps change |
| Any modified file | Update the `VERSION` field in that file's `FILE INFORMATION` block |
| **Every PR** | **Bump the patch version** — increment `XX.YY.ZZ` in `README.md`; `sync-version-on-merge` propagates it to all headers and badges on merge |
If your code change makes any existing doc sentence false or incomplete, fix the doc before closing the PR.
---
## Key Constraints
- Never commit directly to `main` — all changes go via PR, squash-merged
- Never skip the FILE INFORMATION block on a new file
- Never use bare `catch (\Throwable $e) {}` without logging or re-throwing
- Never hardcode version numbers in body text — update `README.md` and let automation propagate
- Never use `github.token` or `secrets.GITHUB_TOKEN` in workflows — always use `secrets.GH_TOKEN`
- Never extend `CliBase` in PHP scripts — extend `MokoStandards\Enterprise\CliFramework`
- Never call `$script->run()` as the entry point — call `$script->execute()`
- Policy documents and guides must not be mixed
---
## MokoStandards Reference
This repository is governed by [MokoStandards](https://github.com/mokoconsulting-tech/MokoStandards). Authoritative policies:
| Document | Purpose |
|----------|---------|
| [file-header-standards.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/file-header-standards.md) | Copyright-header rules for every file type |
| [coding-style-guide.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/coding-style-guide.md) | Naming and formatting conventions |
| [branching-strategy.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/branching-strategy.md) | Branch naming, hierarchy, and release workflow |
| [merge-strategy.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/merge-strategy.md) | Squash-merge policy and PR title/body conventions |
| [changelog-standards.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/changelog-standards.md) | How and when to update CHANGELOG.md |
| [scripting-standards.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/scripting-standards.md) | PHP script requirements and CliFramework usage |
| [package-installation.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/guide/package-installation.md) | Installing `mokoconsulting/mokostandards` via Composer |
-126
View File
@@ -1,126 +0,0 @@
<!-- Copyright (C) 2025 Moko Consulting <hello@mokoconsulting.tech>
This file is part of a Moko Consulting project.
SPDX-LICENSE-IDENTIFIER: GPL-3.0-or-later
This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License (./LICENSE).
# FILE INFORMATION
DEFGROUP:
INGROUP: Project.Infrastructure
REPO: mokoconsulting-tech/MokoStandards-Template-Generic
VERSION: 00.00.01
PATH: ./.github/copilot/README.md
BRIEF: GitHub Copilot firewall configuration documentation
-->
# GitHub Copilot Firewall Configuration
This directory contains firewall configuration files for GitHub Copilot coding agent to access enterprise-ready sites and external resources.
## Files
### firewall-allowlist.json
JSON configuration file defining domains and URLs that should be accessible through the firewall. This includes:
- **License Sources**: gnu.org, opensource.org, apache.org, creativecommons.org
- **Standards Organizations**: fsf.org, spdx.org
- **Code Repositories**: github.com, raw.githubusercontent.com
The configuration is organized into categories with priority levels for better management.
### setup-firewall.sh
Bash script that reads the `firewall-allowlist.json` configuration and exports the allowlist as an environment variable for GitHub Actions workflows.
## Usage in GitHub Actions
To use this firewall configuration in your GitHub Actions workflows, add the following step **before** the Copilot agent runs:
```yaml
- name: Configure Copilot Firewall
run: |
bash .github/copilot/setup-firewall.sh
```
This will:
1. Read the firewall allowlist configuration
2. Export `COPILOT_FIREWALL_ALLOWLIST` environment variable
3. Make the domains accessible to the Copilot agent
## Example Workflow
```yaml
name: Copilot Agent
on:
pull_request:
types: [opened, synchronize]
jobs:
copilot:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Configure Copilot Firewall
run: bash .github/copilot/setup-firewall.sh
- name: Run Copilot Agent
uses: github/copilot-swe-agent@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
```
## Adding New Domains
To add new domains to the allowlist:
1. Edit `firewall-allowlist.json`
2. Add the domain to the `allowlist.domains` array
3. Optionally add specific URLs to `allowlist.urls`
4. Categorize the domain in the `categories` section
5. Commit and push the changes
Example:
```json
{
"allowlist": {
"domains": [
"existing-domain.com",
"new-domain.com"
]
}
}
```
## Security Considerations
- Only add trusted domains to the allowlist
- Use specific URLs when possible instead of wildcard domains
- Review allowlist changes carefully in pull requests
- Keep the allowlist minimal - only include necessary domains
- Document the purpose of each domain/URL in the categories section
## Troubleshooting
If the Copilot agent cannot access a required site:
1. Check if the domain is in `firewall-allowlist.json`
2. Verify the setup script ran in the GitHub Actions workflow
3. Check workflow logs for firewall configuration messages
4. Ensure the domain format is correct (e.g., `www.example.com` not `http://www.example.com`)
5. For wildcard patterns, ensure they follow the correct format (e.g., `*.example.com`)
## Revision History
| Date | Version | Author | Notes |
| --- | --- | --- | --- |
| 2026-01-16 | 0.1.0 | Copilot | Initial firewall configuration setup |
-73
View File
@@ -1,73 +0,0 @@
{
"$schema": "https://docs.github.com/assets/schemas/copilot-firewall-allowlist.json",
"version": "1.0",
"description": "Firewall allowlist configuration for GitHub Copilot coding agent to access enterprise-ready sites and license sources",
"allowlist": {
"domains": [
"*.gnu.org",
"fsf.org",
"www.fsf.org",
"spdx.org",
"www.spdx.org",
"opensource.org",
"www.opensource.org",
"creativecommons.org",
"www.creativecommons.org",
"apache.org",
"www.apache.org",
"github.com",
"api.github.com",
"raw.githubusercontent.com"
],
"urls": [
"https://www.gnu.org/licenses/gpl-3.0.txt",
"https://www.gnu.org/licenses/gpl-3.0.html",
"https://www.gnu.org/licenses/agpl-3.0.txt",
"https://www.gnu.org/licenses/lgpl-3.0.txt",
"https://www.apache.org/licenses/LICENSE-2.0.txt",
"https://opensource.org/licenses/MIT",
"https://spdx.org/licenses/",
"https://creativecommons.org/licenses/"
]
},
"categories": [
{
"name": "license-sources",
"description": "Official license text sources",
"priority": "high",
"hosts": [
"www.gnu.org",
"opensource.org",
"spdx.org",
"apache.org",
"creativecommons.org"
]
},
{
"name": "code-repositories",
"description": "Source code and package repositories",
"priority": "high",
"hosts": [
"github.com",
"api.github.com",
"raw.githubusercontent.com"
]
},
{
"name": "standards-organizations",
"description": "Standards and specification sources",
"priority": "medium",
"hosts": [
"fsf.org",
"spdx.org"
]
}
],
"notes": [
"This configuration allows access to common license sources and enterprise-ready sites",
"Domains use wildcard patterns where appropriate (e.g., *.gnu.org)",
"Specific license file URLs are explicitly allowlisted",
"Categories help organize and prioritize different types of access",
"This file should be referenced in GitHub Actions setup steps before firewall initialization"
]
}
-57
View File
@@ -1,57 +0,0 @@
#!/bin/bash
# Copyright (C) 2025 Moko Consulting <hello@mokoconsulting.tech>
# SPDX-LICENSE-IDENTIFIER: GPL-3.0-or-later
#
# Setup script for configuring firewall allowlist in GitHub Actions
# This script should be run in GitHub Actions setup steps before the firewall is enabled
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ALLOWLIST_FILE="${SCRIPT_DIR}/firewall-allowlist.json"
echo "=== GitHub Copilot Firewall Setup ==="
echo "Configuring firewall allowlist for enterprise-ready sites..."
if [ ! -f "$ALLOWLIST_FILE" ]; then
echo "ERROR: Allowlist file not found: $ALLOWLIST_FILE"
exit 1
fi
# Read domains from the allowlist configuration
if ! DOMAINS=$(jq -r '.allowlist.domains[]' "$ALLOWLIST_FILE" 2>&1); then
echo "ERROR: Failed to parse allowlist configuration: $DOMAINS"
exit 1
fi
if [ -z "$DOMAINS" ]; then
echo "WARNING: No domains found in allowlist configuration"
exit 0
fi
echo "Domains to allowlist:"
echo "$DOMAINS" | while read -r domain; do
echo " - $domain"
done
# Export environment variable for GitHub Copilot
# This tells the Copilot agent which domains are allowed
export COPILOT_FIREWALL_ALLOWLIST=$(jq -c '.allowlist.domains' "$ALLOWLIST_FILE")
echo ""
echo "Firewall allowlist configured successfully"
echo "Environment variable set: COPILOT_FIREWALL_ALLOWLIST"
echo ""
echo "To use this in GitHub Actions, add to your workflow:"
echo ""
echo " - name: Configure Copilot Firewall"
echo " run: |"
echo " bash .github/copilot/setup-firewall.sh"
echo " echo \"COPILOT_FIREWALL_ALLOWLIST=\$COPILOT_FIREWALL_ALLOWLIST\" >> \$GITHUB_ENV"
echo ""
# Optionally output the configuration for GitHub Actions to use
if [ "$GITHUB_ACTIONS" = "true" ]; then
echo "COPILOT_FIREWALL_ALLOWLIST=${COPILOT_FIREWALL_ALLOWLIST}" >> "$GITHUB_ENV"
echo "✓ Firewall allowlist exported to GitHub Actions environment"
fi
+2
View File
@@ -200,3 +200,5 @@ venv/
*.coverage
hypothesis/
profile.ps1
.mcp.json
+1 -1
View File
@@ -1,4 +1,4 @@
<!-- Copyright (C) 2025 Moko Consulting <hello@mokoconsulting.tech>
<!-- Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
This file is part of a Moko Consulting project.
+1 -1
View File
@@ -1,4 +1,4 @@
<!-- Copyright (C) 2025 Moko Consulting <hello@mokoconsulting.tech>
<!-- Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
This file is part of a Moko Consulting project.
+36 -2
View File
@@ -1,4 +1,4 @@
<!-- Copyright (C) 2025 Moko Consulting <hello@mokoconsulting.tech>
<!-- Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
This file is part of a Moko Consulting project.
@@ -13,7 +13,7 @@
# FILE INFORMATION
DEFGROUP:
INGROUP: Project.Documentation
REPO: mokoconsulting-tech/MokoStandards-Template-Generic
REPO: https://git.mokoconsulting.tech/MokoConsulting/MokoStandards-Template-Generic
VERSION: 00.00.01
PATH: ./CONTRIBUTING.md
BRIEF: Contribution guidelines for the project
@@ -125,3 +125,37 @@ If you have questions about contributing, feel free to open an issue or contact
| Date | Version | Author | Notes |
| --- | --- | --- | --- |
| 2026-01-16 | 0.1.0 | Copilot | Initial contributing guidelines |
## Infrastructure Standards
All repositories in the MokoConsulting org follow these conventions:
### Release Tags
Every repo maintains 5 standard release channel tags:
- `development` - Active development builds
- `alpha` - Early internal testing
- `beta` - Broader testing / client UAT
- `release-candidate` - Final QA before production
- `stable` - Production release
### Branch Protection
- `main` is protected; only `jmiller` can push directly
- All other contributors must use pull requests
- PRs are automatically reviewed by Claude Code
### CI/CD
- Gitea Actions runs all CI workflows
- GitHub Actions are disabled on mirrored repos
- Workflows live in both `.github/workflows/` and `.gitea/workflows/`
### Update Servers (Joomla)
In manifest `<updateservers>`, Gitea must be priority 1, GitHub priority 2.
### Secrets
All repos have `GA_TOKEN` and `GH_TOKEN` as Actions secrets for API access.
+153 -61
View File
@@ -1,4 +1,4 @@
<!-- Copyright (C) 2025 Moko Consulting <hello@mokoconsulting.tech>
<!-- Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
This file is part of a Moko Consulting project.
@@ -11,102 +11,194 @@
You should have received a copy of the GNU General Public License (./LICENSE).
# FILE INFORMATION
DEFGROUP:
INGROUP: Project.Documentation
REPO: mokoconsulting-tech/MokoStandards-Template-Generic
VERSION: 00.00.01
DEFGROUP: joomla-api-mcp.Documentation
INGROUP: joomla-api-mcp
REPO: https://git.mokoconsulting.tech/MokoConsulting/joomla-api-mcp
VERSION: 01.00.00
PATH: ./README.md
BRIEF: Generic coding project template according to MokoStandards
BRIEF: MCP server for Joomla Web Services API operations
-->
[![Version](https://img.shields.io/badge/version-00.00.01-blue.svg?logo=v&logoColor=white)](https://github.com/mokoconsulting-tech/MokoStandards-Template-Generic/releases/tag/v00)
[![Version](https://img.shields.io/badge/version-01.00.00-blue.svg?logo=v&logoColor=white)](https://git.mokoconsulting.tech/MokoConsulting/joomla-api-mcp/releases/tag/v00)
[![License](https://img.shields.io/badge/license-GPL--3.0--or--later-green.svg?logo=gnu&logoColor=white)](LICENSE)
[![PHP](https://img.shields.io/badge/PHP-8.1%2B-777BB4.svg?logo=php&logoColor=white)](https://www.php.net)
[![Node](https://img.shields.io/badge/Node.js-20%2B-339933.svg?logo=node.js&logoColor=white)](https://nodejs.org)
# MokoStandards-Template-Generic
# joomla-api-mcp
[![standard-readme compliant](https://img.shields.io/badge/readme%20style-standard-brightgreen.svg?style=flat-square)](https://github.com/RichardLitt/standard-readme)
A template repository for generic coding projects that follows MokoStandards conventions.
A Model Context Protocol (MCP) server that exposes the Joomla 4/5/6 Web Services API as tools for AI assistants.
This template provides a standardized structure for any coding project, including proper documentation, licensing, contribution guidelines, and project organization. It is designed to help you quickly bootstrap new projects with best practices and consistent conventions.
Connects to Joomla instances over HTTP using the built-in REST API (`/api/index.php/v1`) and API token authentication. Claude, Cursor, and other MCP clients can manage articles, categories, users, menus, plugins, and more — without SSH or direct server access.
## Table of Contents
- [Background](#background)
- [Install](#install)
- [Usage](#usage)
- [Structure](#structure)
- [Tools](#tools)
- [Configuration](#configuration)
- [Contributing](#contributing)
- [License](#license)
- [Maintainers](#maintainers)
## Background
MokoStandards-Template-Generic is a repository template designed to provide a consistent foundation for generic coding projects. It includes:
Joomla 4+ ships with a full Web Services API that supports content management, user administration, and site configuration over REST. This MCP server wraps that API into structured tools, enabling:
- Standard documentation structure (README, LICENSE, CONTRIBUTING, CODE_OF_CONDUCT, CHANGELOG)
- MokoStandards-compliant file headers and metadata
- EditorConfig for consistent coding styles across editors
- Git configuration templates
- Documentation index system for easy navigation
- Article management (list, create, update, delete, publish)
- Category management (list, create, update, delete)
- User administration (list, create, update, delete, groups)
- Menu and menu item inspection
- Plugin listing and enable/disable toggling
- Module and template listing
- Tag, contact, banner, and newsfeed management
- Media file browsing
- Application configuration read/write
- Private messaging
- Custom field inspection
- Raw API passthrough for any endpoint
This template follows the [standard-readme](https://github.com/RichardLitt/standard-readme) specification and incorporates MokoStandards conventions for enterprise-grade project organization.
Supports multiple named connections for managing several Joomla instances from a single MCP server.
## Install
To use this template:
1. Click the "Use this template" button on GitHub
2. Create a new repository from this template
3. Clone your new repository locally:
```sh
git clone https://github.com/your-username/your-new-repo.git
cd your-new-repo
git clone https://git.mokoconsulting.tech/MokoConsulting/joomla-api-mcp.git
cd joomla-api-mcp
npm install
npm run build
npm run setup
```
4. Update the project-specific details:
- Update README.md with your project name and description
- Update LICENSE if using a different license
- Update file headers with appropriate REPO, DEFGROUP, and BRIEF values
- Update CHANGELOG.md with your version history
The setup wizard will prompt for your Joomla site URL and API token. Run it again to add more connections — each site gets its own name, URL, and API key so you can manage multiple Joomla instances from a single MCP server.
## Usage
This template is designed to be customized for your specific project needs.
### Add to Claude Code
### Getting Started
In your Claude Code MCP settings (`~/.claude.json` or project `.mcp.json`):
1. Replace placeholder text with your project details
2. Add your source code to the `src/` directory
3. Add scripts to the `scripts/` directory
4. Add documentation to the `docs/` directory
5. Update the CHANGELOG.md as you make changes
### Project Structure
```
.
├── docs/ # Documentation files
├── scripts/ # Build and utility scripts
├── src/ # Source code
├── README.md # This file
├── LICENSE # License information
├── CONTRIBUTING.md # Contribution guidelines
├── CODE_OF_CONDUCT.md # Code of conduct
└── CHANGELOG.md # Version history
```json
{
"mcpServers": {
"joomla": {
"command": "node",
"args": ["/path/to/joomla-api-mcp/dist/index.js"]
}
}
}
```
## Structure
### Configuration
The repository follows MokoStandards conventions:
The easiest way to configure is `npm run setup`, which walks you through it interactively. Run it multiple times to add connections for each Joomla site you manage.
- **Documentation**: All `.md` files include copyright headers and file metadata
- **Index Files**: Each directory contains an `index.md` for navigation
- **EditorConfig**: Maintains consistent coding styles (tabs, width 2)
- **Git Configuration**: Includes `.gitattributes`, `.gitignore`, and `.gitmessage` templates
You can also create the config manually. Copy `config.example.json` to `~/.joomla-api-mcp.json` and edit:
```sh
cp config.example.json ~/.joomla-api-mcp.json
```
Each connection needs the Joomla site's base URL and an API token (generated in Joomla under Users > Edit User > API Token):
```json
{
"defaultConnection": "production",
"connections": {
"local-dev": {
"baseUrl": "https://localhost:8080",
"apiToken": "your-joomla-api-token-here",
"insecure": true
},
"production": {
"baseUrl": "https://www.example.com",
"apiToken": "your-production-api-token"
},
"staging": {
"baseUrl": "https://staging.example.com",
"apiToken": "your-staging-api-token"
}
}
}
```
| Field | Required | Description |
|-------|----------|-------------|
| `baseUrl` | Yes | Joomla site URL (no trailing slash) |
| `apiToken` | Yes | Joomla API token (Bearer auth) |
| `insecure` | No | Skip TLS verification for self-signed certs |
## Tools
### Articles
| Tool | Description |
|------|-------------|
| `joomla_articles_list` | List articles with optional category, state, and search filters |
| `joomla_article_get` | Get a single article by ID |
| `joomla_article_create` | Create a new article |
| `joomla_article_update` | Update an existing article |
| `joomla_article_delete` | Delete an article |
### Categories
| Tool | Description |
|------|-------------|
| `joomla_categories_list` | List content categories |
| `joomla_category_create` | Create a new category |
| `joomla_category_update` | Update a category |
| `joomla_category_delete` | Delete a category |
### Users
| Tool | Description |
|------|-------------|
| `joomla_users_list` | List users with optional search, group, and state filters |
| `joomla_user_get` | Get a single user by ID |
| `joomla_user_create` | Create a user with auto-generated secure password |
| `joomla_user_update` | Update a user |
| `joomla_user_delete` | Delete a user |
| `joomla_user_groups_list` | List user groups |
### Menus
| Tool | Description |
|------|-------------|
| `joomla_menus_list` | List menu types |
| `joomla_menu_items_list` | List menu items for a menu type |
| `joomla_menu_item_get` | Get a single menu item by ID |
### Plugins
| Tool | Description |
|------|-------------|
| `joomla_plugins_list` | List plugins with optional type, state, and search filters |
| `joomla_plugin_update` | Enable or disable a plugin |
### Other
| Tool | Description |
|------|-------------|
| `joomla_modules_list` | List site or admin modules |
| `joomla_templates_list` | List site or admin templates |
| `joomla_languages_list` | List installed content languages |
| `joomla_tags_list` | List tags |
| `joomla_tag_create` | Create a tag |
| `joomla_fields_list` | List custom fields for a context |
| `joomla_contacts_list` | List contacts |
| `joomla_banners_list` | List banners |
| `joomla_newsfeeds_list` | List newsfeeds |
| `joomla_messages_list` | List private messages |
| `joomla_message_get` | Get a single private message |
| `joomla_media_list` | List media files in a folder |
| `joomla_config_get` | Get application configuration |
| `joomla_config_update` | Update application configuration values |
| `joomla_api_request` | Raw API request to any Joomla endpoint |
| `joomla_list_connections` | List configured connections |
All tools accept an optional `connection` parameter to target a specific named connection.
## Contributing
@@ -118,11 +210,11 @@ This project follows the [Contributor Covenant](CODE_OF_CONDUCT.md) Code of Cond
This project is licensed under the GNU General Public License v3.0 or later - see the [LICENSE](LICENSE) file for details.
Copyright © 2025 Moko Consulting <hello@mokoconsulting.tech>
Copyright © 2026 Moko Consulting <hello@mokoconsulting.tech>
## Maintainers
[@mokoconsulting-tech](https://github.com/mokoconsulting-tech)
[@mokoconsulting-tech](https://git.mokoconsulting.tech/MokoConsulting)
For questions or support, please contact: hello@mokoconsulting.tech
@@ -130,4 +222,4 @@ For questions or support, please contact: hello@mokoconsulting.tech
| Date | Version | Author | Notes |
| --- | --- | --- | --- |
| 2026-01-16 | 0.1.0 | Copilot | Initial MokoStandards-compliant README |
| 2026-04-23 | 0.0.1 | jmiller | Initial MCP server with Joomla Web Services API tools |
+5
View File
@@ -45,6 +45,11 @@ Security updates are provided for the following versions:
Only the current major version receives security updates. Users should upgrade to the latest supported version to receive security patches.
## Reporting a Vulnerability
Report security vulnerabilities via Gitea issue (preferred):
https://git.mokoconsulting.tech/MokoConsulting/MokoStandards-Template-Generic/issues/new?template=security.yaml
Or email: hello@mokoconsulting.tech
### Where to Report
+12
View File
@@ -0,0 +1,12 @@
# TODO
> **Note:** This file is not tracked in version control (.gitignore). It is for local task tracking only.
## Critical
-
## Normal
-
## Low
-
+18
View File
@@ -0,0 +1,18 @@
{
"defaultConnection": "production",
"connections": {
"local-dev": {
"baseUrl": "https://localhost:8080",
"apiToken": "your-joomla-api-token-here",
"insecure": true
},
"production": {
"baseUrl": "https://www.example.com",
"apiToken": "your-production-api-token"
},
"staging": {
"baseUrl": "https://staging.example.com",
"apiToken": "your-staging-api-token"
}
}
}
+279
View File
@@ -0,0 +1,279 @@
<!--
Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
This file is part of a Moko Consulting project.
SPDX-License-Identifier: GPL-3.0-or-later
# FILE INFORMATION
DEFGROUP: joomla-api-mcp.Documentation
INGROUP: joomla-api-mcp
REPO: https://git.mokoconsulting.tech/MokoConsulting/joomla-api-mcp
PATH: /docs/API.md
VERSION: 00.00.01
BRIEF: MCP tool reference documentation
-->
# API Reference
All tools accept an optional `connection` parameter to target a specific named connection. If omitted, the default connection is used.
## Articles
### `joomla_articles_list`
List articles with optional filtering.
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `category_id` | number | No | Filter by category ID |
| `state` | `"0"` / `"1"` / `"-2"` | No | 1=published, 0=unpublished, -2=trashed |
| `search` | string | No | Search in title |
| `limit` | number | No | Max results (default 20) |
| `offset` | number | No | Pagination offset |
### `joomla_article_get`
Get a single article by ID.
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `id` | number | Yes | Article ID |
### `joomla_article_create`
Create a new article.
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `title` | string | Yes | Article title |
| `articletext` | string | Yes | Article body (HTML) |
| `catid` | number | Yes | Category ID |
| `state` | number | No | 1=published, 0=unpublished (default 0) |
| `language` | string | No | Language code (default `"*"`) |
| `featured` | number | No | 1=featured, 0=not |
| `metadesc` | string | No | Meta description |
| `metakey` | string | No | Meta keywords |
### `joomla_article_update`
Update an existing article. Only provided fields are changed.
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `id` | number | Yes | Article ID |
| `title` | string | No | New title |
| `articletext` | string | No | New body (HTML) |
| `catid` | number | No | New category ID |
| `state` | number | No | State value |
| `featured` | number | No | Featured flag |
| `metadesc` | string | No | Meta description |
### `joomla_article_delete`
Delete an article.
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `id` | number | Yes | Article ID |
## Categories
### `joomla_categories_list`
List content categories.
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `extension` | string | No | Extension name (default `"com_content"`) |
| `search` | string | No | Search in title |
### `joomla_category_create`
Create a new category.
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `title` | string | Yes | Category title |
| `parent_id` | number | No | Parent category ID (default 1 = root) |
| `extension` | string | No | Extension (default `"com_content"`) |
| `description` | string | No | Category description |
| `state` | number | No | 1=published, 0=unpublished |
| `language` | string | No | Language code (default `"*"`) |
### `joomla_category_update`
Update a category.
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `id` | number | Yes | Category ID |
| `title` | string | No | New title |
| `description` | string | No | New description |
| `state` | number | No | State value |
### `joomla_category_delete`
Delete a category.
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `id` | number | Yes | Category ID |
## Users
### `joomla_users_list`
List Joomla users.
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `search` | string | No | Search in name/username/email |
| `group_id` | number | No | Filter by user group ID |
| `state` | `"0"` / `"1"` | No | 0=blocked, 1=active |
| `limit` | number | No | Max results |
### `joomla_user_get`
Get a single user by ID.
### `joomla_user_create`
Create a user with auto-generated secure password.
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `name` | string | Yes | Full name |
| `username` | string | Yes | Username |
| `email` | string | Yes | Email address |
| `groups` | number[] | No | Group IDs (default `[2]` = Registered) |
| `block` | number | No | 0=active, 1=blocked (default 0) |
Returns the generated password in the response. Share securely with the user.
### `joomla_user_update`
Update a user.
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `id` | number | Yes | User ID |
| `name` | string | No | Full name |
| `email` | string | No | Email |
| `groups` | number[] | No | Group IDs |
| `block` | number | No | 0=active, 1=blocked |
### `joomla_user_delete`
Delete a user.
### `joomla_user_groups_list`
List all user groups. No parameters.
## Menus
### `joomla_menus_list`
List menu types. No parameters.
### `joomla_menu_items_list`
List menu items for a menu type.
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `menutype` | string | Yes | Menu type alias (e.g. `"mainmenu"`) |
### `joomla_menu_item_get`
Get a single menu item by ID.
## Plugins
### `joomla_plugins_list`
List plugins.
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `type` | string | No | Filter by plugin folder (e.g. `"system"`, `"content"`) |
| `state` | `"0"` / `"1"` | No | 0=disabled, 1=enabled |
| `search` | string | No | Search in name |
### `joomla_plugin_update`
Enable or disable a plugin.
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `id` | number | Yes | Plugin ID |
| `enabled` | number | Yes | 1=enable, 0=disable |
## Modules
### `joomla_modules_list`
List site or admin modules.
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `client_id` | `"0"` / `"1"` | No | 0=site, 1=admin |
## Templates
### `joomla_templates_list`
List site or admin templates.
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `client_id` | `"0"` / `"1"` | No | 0=site, 1=admin |
## Other Tools
### `joomla_languages_list`
List installed content languages.
### `joomla_tags_list`
List tags with optional search.
### `joomla_tag_create`
Create a tag.
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `title` | string | Yes | Tag title |
| `parent_id` | number | No | Parent tag ID |
### `joomla_fields_list`
List custom fields for a context (default `"com_content.article"`).
### `joomla_contacts_list`
List contacts with optional search.
### `joomla_banners_list`
List banners.
### `joomla_newsfeeds_list`
List newsfeeds.
### `joomla_messages_list`
List private messages.
### `joomla_message_get`
Get a single private message by ID.
### `joomla_media_list`
List media files in a folder.
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `path` | string | No | Folder path relative to media root |
### `joomla_config_get`
Get application configuration.
### `joomla_config_update`
Update application configuration values.
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `settings` | object | Yes | Key-value pairs of settings to update |
### `joomla_api_request`
Make a raw API request to any Joomla Web Services endpoint.
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `method` | `"GET"` / `"POST"` / `"PATCH"` / `"DELETE"` | Yes | HTTP method |
| `endpoint` | string | Yes | API path (e.g. `"/content/articles"`) |
| `body` | object | No | Request body for POST/PATCH |
| `params` | object | No | Query parameters |
### `joomla_list_connections`
List all configured connections. No parameters.
## Revision History
| Date | Version | Author | Notes |
| --- | --- | --- | --- |
| 2026-04-23 | 0.0.1 | jmiller | Initial API reference |
+80
View File
@@ -0,0 +1,80 @@
<!--
Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
This file is part of a Moko Consulting project.
SPDX-License-Identifier: GPL-3.0-or-later
# FILE INFORMATION
DEFGROUP: joomla-api-mcp.Documentation
INGROUP: joomla-api-mcp
REPO: https://git.mokoconsulting.tech/MokoConsulting/joomla-api-mcp
PATH: /docs/ARCHITECTURE.md
VERSION: 00.00.01
BRIEF: Architecture overview and design decisions
-->
# Architecture
## Overview
joomla-api-mcp is a Model Context Protocol (MCP) server that bridges AI assistants (Claude Code, Cursor, etc.) with Joomla's built-in Web Services REST API.
```
AI Assistant <--> MCP (stdio) <--> JoomlaClient <--> Joomla REST API
/api/index.php/v1
```
## Components
### `src/index.ts` — Server Entry Point
Registers all MCP tools with the `McpServer` from `@modelcontextprotocol/sdk`. Each tool maps to one or more Joomla API endpoints. Uses Zod schemas for input validation.
### `src/client.ts` — HTTP Client
The `JoomlaClient` class handles all HTTP communication with Joomla instances:
- Uses `node:https` / `node:http` for requests (not `fetch`) to support self-signed TLS certificates on Node.js 24+
- Authenticates via Bearer token in the `Authorization` header
- Sends `Accept: application/vnd.api+json` per Joomla's JSON:API spec
- Includes a JSON parser that handles Joomla responses that may append HTML error fragments after valid JSON
### `src/config.ts` — Configuration Loader
Loads connection details from `~/.joomla-api-mcp.json`. Supports multiple named connections with a configurable default.
### `src/types.ts` — Type Definitions
TypeScript interfaces for `JoomlaConnection`, `JoomlaConfig`, and `ApiResponse`.
### `scripts/setup.mjs` — Interactive Setup
Node.js script using `readline/promises` that walks users through creating the config file. Supports adding multiple connections incrementally.
## Design Decisions
### Why `node:https` instead of `fetch`?
Node.js 24's built-in `fetch` (undici-based) does not honor `NODE_TLS_REJECT_UNAUTHORIZED=0` for self-signed certificate bypass. The classic `node:https` module with `rejectUnauthorized: false` works reliably across all Node.js versions.
### Why JSON recovery parsing?
Joomla's API sometimes returns valid JSON with `text/html` content-type, and may append HTML error fragments (e.g. template errors) after the JSON body. The `tryParseJson` method handles this by finding the last valid JSON boundary when standard parsing fails.
### Why per-connection API tokens?
Each Joomla site requires its own API token scoped to a specific user. Multi-site support is a core use case — managing staging, production, and dev environments from a single MCP server.
## Data Flow
1. AI assistant sends a tool call via MCP stdio transport
2. `index.ts` validates parameters with Zod and resolves the connection
3. `JoomlaClient` constructs the API URL, attaches auth headers, and makes the HTTP request
4. Response is parsed (with JSON recovery if needed) and returned as MCP tool output
## Revision History
| Date | Version | Author | Notes |
| --- | --- | --- | --- |
| 2026-04-23 | 0.0.1 | jmiller | Initial architecture document |
+95 -391
View File
@@ -6,436 +6,140 @@ This file is part of a Moko Consulting project.
SPDX-License-Identifier: GPL-3.0-or-later
# FILE INFORMATION
DEFGROUP: joomla-api-mcp.Documentation
INGROUP: joomla-api-mcp
REPO: https://git.mokoconsulting.tech/MokoConsulting/joomla-api-mcp
PATH: /docs/INSTALLATION.md
VERSION: 04.00.15
BRIEF: Installation and setup instructions for [PROJECT_NAME]
VERSION: 00.00.01
BRIEF: Installation and setup instructions
-->
# Installation
## Overview
This document provides comprehensive installation and setup instructions for **[PROJECT_NAME]**.
## Table of Contents
- [Prerequisites](#prerequisites)
- [Installation Methods](#installation-methods)
- [Quick Start](#quick-start)
- [Detailed Installation](#detailed-installation)
- [Configuration](#configuration)
- [Verification](#verification)
- [Troubleshooting](#troubleshooting)
- [Next Steps](#next-steps)
## Prerequisites
### System Requirements
- **Node.js** 20.0.0 or later
- **npm** (included with Node.js)
- A Joomla 4/5/6 site with the Web Services API enabled
- A Joomla API token (generated in Users > Edit User > API Token tab)
- **Operating System**: [Specify supported OS versions]
- **Runtime**: [e.g., PHP 8.1+, Node.js 20+, Python 3.9+]
- **Memory**: [Minimum RAM required]
- **Disk Space**: [Minimum disk space required]
## Install
### Software Dependencies
**Required:**
- [List required dependencies with versions]
- Example: Git 2.30+
- Example: Composer 2.0+
**Optional:**
- [List optional dependencies]
### Access Requirements
- [Any required access permissions, credentials, or accounts]
- Example: GitHub account for cloning private repositories
- Example: Database access credentials
## Installation Methods
### Method 1: Using Package Manager (Recommended)
**For [Platform/Package Manager]:**
```bash
# Installation command
[package-manager] install [package-name]
# Verify installation
[package-name] --version
```sh
git clone https://git.mokoconsulting.tech/MokoConsulting/joomla-api-mcp.git
cd joomla-api-mcp
npm install
npm run build
npm run setup
```
### Method 2: From Source
The setup wizard will prompt for:
**Clone the repository:**
1. **Connection name** — a label for this site (e.g. `production`, `staging`)
2. **Joomla site URL** — the base URL of the site (e.g. `https://www.example.com`)
3. **API token** — the Joomla API token for authentication
4. **TLS verification** — whether to skip certificate verification (for self-signed certs)
```bash
# Clone from GitHub
git clone https://github.com/[organization]/[repository].git
cd [repository]
Run `npm run setup` again to add more connections.
# Checkout stable version (recommended)
git checkout tags/v[VERSION]
## Register with Claude Code
Add to your global Claude Code config (`~/.claude.json`):
```json
{
"mcpServers": {
"joomla-api": {
"type": "stdio",
"command": "node",
"args": ["/path/to/joomla-api-mcp/dist/index.js"]
}
}
}
```
### Method 3: Using Pre-built Binary/Package
Or add to a project-level `.mcp.json`:
**Download and install:**
```bash
# Download release
wget https://github.com/[organization]/[repository]/releases/download/v[VERSION]/[package-name]
# Make executable (if applicable)
chmod +x [package-name]
# Move to system path (optional)
sudo mv [package-name] /usr/local/bin/
```json
{
"mcpServers": {
"joomla-api": {
"command": "node",
"args": ["/path/to/joomla-api-mcp/dist/index.js"]
}
}
}
```
## Quick Start
Restart Claude Code after adding the server.
For users who want to get started quickly:
## Generating a Joomla API Token
```bash
# 1. Install
[installation-command]
1. Log in to the Joomla admin panel
2. Go to **Users** > **Manage** > select your user
3. Click the **API Token** tab
4. Click **Save** to generate a token
5. Copy the token value — it will not be shown again
# 2. Configure
[configuration-command]
The token must belong to a user with sufficient permissions for the operations you want to perform (e.g. Super Users for full access).
# 3. Run
[run-command]
## Configuration File
# 4. Verify
[verification-command]
The config is stored at `~/.joomla-api-mcp.json`:
```json
{
"defaultConnection": "production",
"connections": {
"production": {
"baseUrl": "https://www.example.com",
"apiToken": "your-api-token"
},
"staging": {
"baseUrl": "https://staging.example.com",
"apiToken": "your-staging-token",
"insecure": true
}
}
}
```
## Detailed Installation
### Step 1: Prepare Environment
**1.1 Install System Dependencies**
For Ubuntu/Debian:
```bash
sudo apt update
sudo apt install [dependencies]
```
For macOS:
```bash
brew install [dependencies]
```
For Windows:
```powershell
# PowerShell commands or link to Windows-specific guide
```
**1.2 Set Up Environment Variables**
```bash
# Add to ~/.bashrc or ~/.zshrc
export [VAR_NAME]=[value]
# Reload shell configuration
source ~/.bashrc
```
### Step 2: Install Application
**2.1 Install via [Method]**
```bash
[Detailed installation commands with explanations]
```
**2.2 Install Dependencies**
```bash
# For PHP projects
composer install --no-dev
# For Node.js projects
npm install --production
# For Python projects
pip install -r requirements.txt
```
### Step 3: Initial Configuration
**3.1 Create Configuration File**
```bash
# Copy example configuration
cp config/config.example.php config/config.php
# Or use configuration wizard
php bin/configure.php
```
**3.2 Configure Database (if applicable)**
```bash
# Create database
mysql -u root -p -e "CREATE DATABASE [db_name];"
# Import schema
mysql -u root -p [db_name] < database/schema.sql
# Update configuration
nano config/database.php
```
**3.3 Set Permissions**
```bash
# Set appropriate ownership
sudo chown -R www-data:www-data /var/www/[project]
# Set directory permissions (755)
find /var/www/[project] -type d -exec chmod 755 {} \;
# Set file permissions (644 for most files)
find /var/www/[project] -type f -exec chmod 644 {} \;
# Make executable files executable (if needed)
chmod +x /var/www/[project]/bin/*
# Restrict sensitive directories (storage, cache, logs)
chmod 750 /var/www/[project]/storage
chmod 750 /var/www/[project]/cache
```
### Step 4: Initialize Application
**4.1 Run Setup Script**
```bash
# Run initialization
php bin/setup.php
# Or for other platforms
./scripts/setup.sh
```
**4.2 Create Admin User (if applicable)**
```bash
# Create first admin user
php bin/create-admin.php --email=admin@example.com --name="Admin User"
```
## Configuration
### Configuration Files
| File | Purpose | Required |
|------|---------|----------|
| `config/config.php` | Main configuration | Yes |
| `config/database.php` | Database settings | Yes |
| `config/cache.php` | Cache configuration | No |
| `.env` | Environment variables | Yes |
### Essential Configuration Options
**config/config.php:**
```php
return [
'app_name' => '[APPLICATION_NAME]',
'app_url' => 'https://example.com',
'debug' => false, // Set to true for development
'timezone' => 'UTC',
];
```
**Database Configuration:**
```php
return [
'host' => 'localhost',
'port' => 3306,
'database' => '[db_name]',
'username' => '[db_user]',
'password' => '[db_password]',
];
```
### Environment Variables
Create `.env` file:
```bash
APP_ENV=production
APP_DEBUG=false
APP_URL=https://example.com
DB_HOST=localhost
DB_PORT=3306
DB_DATABASE=[db_name]
DB_USERNAME=[db_user]
DB_PASSWORD=[db_password]
```
| Field | Required | Description |
|-------|----------|-------------|
| `defaultConnection` | Yes | Name of the default connection |
| `connections` | Yes | Map of named connections |
| `baseUrl` | Yes | Joomla site URL (no trailing slash) |
| `apiToken` | Yes | Joomla API token (Bearer auth) |
| `insecure` | No | Set `true` to skip TLS verification |
## Verification
### Verify Installation
After setup, verify the server starts correctly:
**Check version:**
```bash
[command] --version
# Expected output: v[VERSION]
```sh
npm start
```
**Run health check:**
```bash
[command] health-check
# or
php bin/health-check.php
```
**Test basic functionality:**
```bash
# Run test command
[command] test
# Access web interface
curl http://localhost:[port]/health
```
### Expected Output
```
✓ Application installed successfully
✓ Database connection established
✓ All dependencies available
✓ Configuration valid
✓ System ready for use
```
If configured correctly, the server will start listening on stdio. If the config is missing or invalid, it will print an error with instructions.
## Troubleshooting
### Common Issues
### "Failed to load config" error
#### Issue: Installation fails with dependency error
The config file `~/.joomla-api-mcp.json` is missing or malformed. Run `npm run setup` to create it.
**Symptom:**
```
Error: Package [package-name] not found
```
### "terminated" or connection errors
**Solution:**
```bash
# Update package manager
[package-manager] update
- Verify the Joomla site is reachable from your machine
- For self-signed certs, set `"insecure": true` in the connection config
- Ensure the API token is valid and not expired
# Retry installation
[package-manager] install [package-name]
```
### "Resource not found" on certain endpoints
#### Issue: Database connection fails
Some Joomla API endpoints require specific components to be installed and enabled. For example, the menus API requires `com_menus` to expose its Web Services routes.
**Symptom:**
```
Error: SQLSTATE[HY000] [2002] Connection refused
```
## Revision History
**Solution:**
1. Verify database service is running:
```bash
sudo systemctl status mysql
```
2. Check database credentials in configuration
3. Verify database host and port are correct
#### Issue: Permission denied errors
**Symptom:**
```
Error: Permission denied: /var/www/[project]/storage
```
**Solution:**
```bash
# Fix ownership
sudo chown -R www-data:www-data /var/www/[project]
# Fix permissions
sudo chmod -R 755 /var/www/[project]/storage
```
### Getting Help
If you encounter issues not covered here:
1. **Check Logs:**
```bash
tail -f logs/application.log
tail -f /var/log/apache2/error.log
```
2. **Enable Debug Mode:**
```bash
# In config/config.php
'debug' => true
```
3. **Consult Documentation:**
- [Troubleshooting Guide](guide/troubleshooting.md)
- [FAQ](guide/faq.md)
4. **Community Support:**
- GitHub Issues: [link]
- Discussion Forum: [link]
- Email: support@example.com
## Next Steps
After successful installation:
1. **Review Configuration:**
- [Configuration Guide](guide/configuration.md)
- [Security Hardening](guide/security.md)
2. **Read Getting Started:**
- [Quick Start Guide](guide/quickstart.md)
- [User Guide](guide/user-guide.md)
3. **For Developers:**
- [Development Setup](development/setup.md)
- [Contributing Guidelines](../CONTRIBUTING.md)
4. **For Operators:**
- [Deployment Guide](deployment/procedures.md)
- [Monitoring Setup](operations/monitoring.md)
## Additional Resources
- [Project Documentation](README.md)
- [API Reference](reference/api/)
- [Change Log](../CHANGELOG.md)
- [Security Policy](../SECURITY.md)
---
## Support
For installation support:
- **Documentation**: Review all guides in [docs/guide/](guide/)
- **Issues**: Report problems at [GitHub Issues](https://github.com/[organization]/[repository]/issues)
- **Email**: support@mokoconsulting.tech
---
*Last Updated: [DATE]*
*Version: [VERSION]*
| Date | Version | Author | Notes |
| --- | --- | --- | --- |
| 2026-04-23 | 0.0.1 | jmiller | Initial installation guide |
+1 -1
View File
@@ -1,4 +1,4 @@
<!-- Copyright (C) 2025 Moko Consulting <hello@mokoconsulting.tech>
<!-- Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
This file is part of a Moko Consulting project.
+10 -33
View File
@@ -1,8 +1,7 @@
{
// The tab key will cycle through the settings when first created
// Sublime Text SFTP Plugin
// Visit https://codexns.io/products/sftp_for_subime/settings for help
// sftp, ftp or ftps
"type": "sftp",
"save_before_upload": true,
@@ -14,43 +13,21 @@
"confirm_sync": true,
"confirm_overwrite_newer": false,
"host": "example.com",
"user": "username",
"host": "dev.mokoconsulting.tech",
"user": "mokoconsulting_dev",
"port": "22",
//Default
//"port": "22",
"ssh_key_file": "C:/Users/jmill/OneDrive/Documents/Keys/repos/joomla-api-mcp",
//"password": "",
//Uncomment One:
//"ssh_key_file": "absolute/path/to/key/file",
//"password": "password",
"remote_path": "/example/path/",
"remote_path": "/home/mokoconsulting_dev/",
"ignore_regexes": [
"\\.sublime-(project|workspace|settings)", "\\.libsass.json/",
"sftp-config(-alt\\d?)?\\.json",
"sftp-config(-alt\\d?)?\\.json", "sftp-config.json.template",
"sftp-settings\\.json", "/venv/", "\\.svn/", "\\.hg/", "\\.git*",
"\\.bzr", "_darcs", "CVS", "\\.DS_Store", "Thumbs\\.db", "robots\\.txt",
"desktop\\.ini", "configuration\\.php",
"administrator/components/com_akeebabackup/backup", "\\.ffs*", "\\.md",
"\\.zip", "\\.editorconfig"
"desktop\\.ini", "\\.ffs*", "\\.editorconfig", "\\.md", "\\.zip", "docs/"
],
//"file_permissions": "664",
//"dir_permissions": "775",
//"extra_list_connections": 0,
"connect_timeout": 30,
//"keepalive": 120,
//"ftp_passive_mode": true,
//"ftp_obey_passive_host": false,
//"ssh_key_file": "~/.ssh/id_rsa",
//"sftp_sudo": false,
//"sftp_debug": false,
//"sftp_flags": ["-F", "/path/to/ssh_config"],
//"preserve_modification_times": false,
//"remote_time_offset_in_hours": 0,
//"remote_encoding": "utf-8",
//"remote_locale": "C",
//"allow_config_upload": false,
"connect_timeout": 30
}
+35
View File
@@ -0,0 +1,35 @@
{
"name": "@mokoconsulting/joomla-api-mcp",
"version": "1.0.0",
"description": "MCP server for Joomla Web Services API operations",
"type": "module",
"main": "dist/index.js",
"bin": {
"joomla-api-mcp": "dist/index.js"
},
"scripts": {
"build": "tsc",
"dev": "tsc --watch",
"start": "node dist/index.js",
"lint": "eslint src/",
"setup": "node scripts/setup.mjs",
"clean": "rm -rf dist/"
},
"dependencies": {
"@modelcontextprotocol/sdk": "^1.12.1",
"zod": "^3.24.4"
},
"devDependencies": {
"@types/node": "^22.15.3",
"typescript": "^5.8.3"
},
"engines": {
"node": ">=20.0.0"
},
"license": "GPL-3.0-or-later",
"author": "Moko Consulting <hello@mokoconsulting.tech>",
"repository": {
"type": "git",
"url": "https://git.mokoconsulting.tech/MokoConsulting/joomla-api-mcp.git"
}
}
+119
View File
@@ -0,0 +1,119 @@
#!/usr/bin/env node
/* Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
*
* This file is part of a Moko Consulting project.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*
* FILE INFORMATION
* DEFGROUP: joomla-api-mcp.Scripts
* INGROUP: joomla-api-mcp
* REPO: https://git.mokoconsulting.tech/MokoConsulting/joomla-api-mcp
* PATH: /scripts/setup.mjs
* VERSION: 00.00.01
* BRIEF: Interactive setup — prompts for Joomla API connection details and writes config
*/
import { createInterface } from 'node:readline/promises';
import { readFile, writeFile } from 'node:fs/promises';
import { resolve } from 'node:path';
import { homedir } from 'node:os';
const CONFIG_PATH = resolve(homedir(), '.joomla-api-mcp.json');
const rl = createInterface({ input: process.stdin, output: process.stdout });
async function prompt(question, defaultValue) {
const suffix = defaultValue ? ` [${defaultValue}]` : '';
const answer = await rl.question(`${question}${suffix}: `);
return answer.trim() || defaultValue || '';
}
async function promptRequired(question) {
let answer = '';
while (!answer) {
answer = (await rl.question(`${question}: `)).trim();
if (!answer) {
console.log(' This field is required.');
}
}
return answer;
}
async function main() {
console.log('');
console.log('=== joomla-api-mcp Setup ===');
console.log('');
console.log('This will create your configuration file at:');
console.log(` ${CONFIG_PATH}`);
console.log('');
// Check for existing config
let existing = null;
try {
const raw = await readFile(CONFIG_PATH, 'utf-8');
existing = JSON.parse(raw);
console.log('Existing config found. You can add a new connection or overwrite.');
console.log(` Current connections: ${Object.keys(existing.connections).join(', ')}`);
console.log('');
} catch {
// No existing config
}
const connectionName = await prompt('Connection name', 'production');
const baseUrl = await promptRequired('Joomla site URL (e.g. https://www.example.com)');
const apiToken = await promptRequired('Joomla API token');
const cleanUrl = baseUrl.replace(/\/+$/, '');
const insecureAnswer = await prompt('Skip TLS verification for self-signed certs? (y/N)', 'N');
const insecure = insecureAnswer.toLowerCase() === 'y';
const connection = { baseUrl: cleanUrl, apiToken };
if (insecure) {
connection.insecure = true;
}
let config;
if (existing) {
config = existing;
config.connections[connectionName] = connection;
const setDefault = await prompt(`Set "${connectionName}" as default connection? (y/N)`, 'N');
if (setDefault.toLowerCase() === 'y') {
config.defaultConnection = connectionName;
}
} else {
config = {
defaultConnection: connectionName,
connections: {
[connectionName]: connection,
},
};
}
await writeFile(CONFIG_PATH, JSON.stringify(config, null, '\t') + '\n', 'utf-8');
console.log('');
console.log(`Config written to ${CONFIG_PATH}`);
console.log(` Connection "${connectionName}" configured for ${cleanUrl}`);
console.log('');
const addAnother = await prompt('Add another connection? (y/N)', 'N');
if (addAnother.toLowerCase() === 'y') {
rl.close();
// Re-run to add another
const { execFileSync } = await import('node:child_process');
execFileSync('node', [new URL(import.meta.url).pathname], { stdio: 'inherit' });
return;
}
console.log('Setup complete. You can now use the MCP server.');
console.log('');
rl.close();
}
main().catch((err) => {
console.error(`Setup failed: ${err.message}`);
rl.close();
process.exit(1);
});
View File
+141
View File
@@ -0,0 +1,141 @@
/* Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
*
* This file is part of a Moko Consulting project.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*
* FILE INFORMATION
* DEFGROUP: joomla-api-mcp.Client
* INGROUP: joomla-api-mcp
* REPO: https://git.mokoconsulting.tech/MokoConsulting/joomla-api-mcp
* PATH: /src/client.ts
* VERSION: 01.00.00
* BRIEF: HTTP client for Joomla Web Services API (v1)
*/
import * as https from 'node:https';
import * as http from 'node:http';
import type { JoomlaConnection, ApiResponse } from './types.js';
const API_PREFIX = '/api/index.php/v1';
const TIMEOUT_MS = 30_000;
export class JoomlaClient {
private readonly base_url: string;
private readonly headers: Record<string, string>;
private readonly insecure: boolean;
constructor(conn: JoomlaConnection) {
this.base_url = conn.baseUrl.replace(/\/+$/, '') + API_PREFIX;
this.headers = {
'Authorization': `Bearer ${conn.apiToken}`,
'Content-Type': 'application/json',
'Accept': 'application/vnd.api+json',
};
this.insecure = conn.insecure ?? false;
}
async get(endpoint: string, params?: Record<string, string>): Promise<ApiResponse> {
const url = this.buildUrl(endpoint, params);
return this.request(url, 'GET');
}
async post(endpoint: string, body?: unknown): Promise<ApiResponse> {
const url = this.buildUrl(endpoint);
return this.request(url, 'POST', body);
}
async patch(endpoint: string, body: unknown): Promise<ApiResponse> {
const url = this.buildUrl(endpoint);
return this.request(url, 'PATCH', body);
}
async delete(endpoint: string): Promise<ApiResponse> {
const url = this.buildUrl(endpoint);
return this.request(url, 'DELETE');
}
private buildUrl(endpoint: string, params?: Record<string, string>): string {
const path = endpoint.startsWith('/') ? endpoint : `/${endpoint}`;
const url = new URL(`${this.base_url}${path}`);
if (params) {
for (const [key, value] of Object.entries(params)) {
url.searchParams.set(key, value);
}
}
return url.toString();
}
private tryParseJson(raw: string): unknown | null {
// Try full string first
try { return JSON.parse(raw); } catch { /* fall through */ }
// Joomla may append HTML after JSON — find the last } or ] and try parsing up to that point
const trimmed = raw.trimStart();
if (!trimmed.startsWith('{') && !trimmed.startsWith('[')) return null;
const closer = trimmed.startsWith('{') ? '}' : ']';
let idx = raw.lastIndexOf(closer);
while (idx > 0) {
try {
return JSON.parse(raw.substring(0, idx + 1));
} catch {
idx = raw.lastIndexOf(closer, idx - 1);
}
}
return null;
}
private request(url: string, method: string, body?: unknown): Promise<ApiResponse> {
return new Promise((resolve, reject) => {
const parsed = new URL(url);
const is_https = parsed.protocol === 'https:';
const transport = is_https ? https : http;
const options: https.RequestOptions = {
hostname: parsed.hostname,
port: parsed.port || (is_https ? 443 : 80),
path: parsed.pathname + parsed.search,
method,
headers: { ...this.headers },
timeout: TIMEOUT_MS,
};
if (this.insecure && is_https) {
options.rejectUnauthorized = false;
}
const payload = body !== undefined ? JSON.stringify(body) : undefined;
if (payload) {
(options.headers as Record<string, string>)['Content-Length'] = Buffer.byteLength(payload).toString();
}
const req = transport.request(options, (res) => {
const chunks: Buffer[] = [];
res.on('data', (chunk: Buffer) => chunks.push(chunk));
res.on('end', () => {
const raw = Buffer.concat(chunks).toString('utf-8');
let data: unknown;
// Joomla API may return JSON with text/html content-type,
// and may append HTML error fragments after valid JSON.
// Try to parse as JSON, trimming trailing non-JSON content.
data = this.tryParseJson(raw) ?? raw;
resolve({ status: res.statusCode ?? 0, data });
});
});
req.on('error', (err) => reject(err));
req.on('timeout', () => {
req.destroy();
reject(new Error('Request timed out'));
});
if (payload) {
req.write(payload);
}
req.end();
});
}
}
+58
View File
@@ -0,0 +1,58 @@
/* Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
*
* This file is part of a Moko Consulting project.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*
* FILE INFORMATION
* DEFGROUP: joomla-api-mcp.Config
* INGROUP: joomla-api-mcp
* REPO: https://git.mokoconsulting.tech/MokoConsulting/joomla-api-mcp
* PATH: /src/config.ts
* VERSION: 01.00.00
* BRIEF: Configuration loader for Joomla API MCP connections
*/
import { readFile } from 'node:fs/promises';
import { resolve } from 'node:path';
import { homedir } from 'node:os';
import type { JoomlaConfig, JoomlaConnection } from './types.js';
const CONFIG_FILENAME = '.joomla-api-mcp.json';
export async function loadConfig(): Promise<JoomlaConfig> {
const config_path = process.env.JOOMLA_API_MCP_CONFIG
? resolve(process.env.JOOMLA_API_MCP_CONFIG)
: resolve(homedir(), CONFIG_FILENAME);
try {
const raw = await readFile(config_path, 'utf-8');
const parsed = JSON.parse(raw) as Partial<JoomlaConfig>;
if (!parsed.connections || Object.keys(parsed.connections).length === 0) {
throw new Error('No connections defined in config');
}
return {
connections: parsed.connections,
defaultConnection: parsed.defaultConnection ?? Object.keys(parsed.connections)[0],
};
} catch (err) {
const message = err instanceof Error ? err.message : String(err);
throw new Error(
`Failed to load config from ${config_path}: ${message}\n` +
`Create ${config_path} — see config.example.json for format.`,
);
}
}
export function getConnection(config: JoomlaConfig, name?: string): JoomlaConnection {
const key = name ?? config.defaultConnection;
const conn = config.connections[key];
if (!conn) {
throw new Error(
`Connection "${key}" not found. Available: ${Object.keys(config.connections).join(', ')}`,
);
}
return conn;
}
-16
View File
@@ -1,16 +0,0 @@
# Docs Index: /templates/repos/generic/src
## Purpose
This index provides navigation to documentation within this folder.
## Metadata
- **Document Type:** index
- **Auto-generated:** This file is automatically generated by rebuild_indexes.py
## Revision History
| Change | Notes | Author |
| --- | --- | --- |
| Automated update | Generated by documentation index automation | rebuild_indexes.py |
+1232
View File
File diff suppressed because it is too large Load Diff
+32
View File
@@ -0,0 +1,32 @@
/* Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
*
* This file is part of a Moko Consulting project.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*
* FILE INFORMATION
* DEFGROUP: joomla-api-mcp.Types
* INGROUP: joomla-api-mcp
* REPO: https://git.mokoconsulting.tech/MokoConsulting/joomla-api-mcp
* PATH: /src/types.ts
* VERSION: 01.00.00
* BRIEF: TypeScript type definitions for Joomla API MCP server
*/
export interface JoomlaConnection {
baseUrl: string;
apiToken: string;
/** Skip TLS certificate verification (self-signed certs) */
insecure?: boolean;
}
export interface JoomlaConfig {
connections: Record<string, JoomlaConnection>;
defaultConnection: string;
}
export interface ApiResponse {
status: number;
data: unknown;
errors?: Array<{ title: string; detail?: string }>;
}
+19
View File
@@ -0,0 +1,19 @@
{
"compilerOptions": {
"target": "ES2022",
"module": "Node16",
"moduleResolution": "Node16",
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"declaration": true,
"declarationMap": true,
"sourceMap": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}