@mokoconsulting/mcp-windows 3.0.0 → 3.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -10,9 +10,9 @@
|
|
|
10
10
|
# VERSION: 05.00.00
|
|
11
11
|
# BRIEF: Universal build & release � detects platform from manifest.xml
|
|
12
12
|
#
|
|
13
|
-
#
|
|
13
|
+
# +=======================================================================+
|
|
14
14
|
# | UNIVERSAL BUILD & RELEASE PIPELINE |
|
|
15
|
-
#
|
|
15
|
+
# +=======================================================================+
|
|
16
16
|
# | |
|
|
17
17
|
# | Reads manifest.xml (joomla|dolibarr|generic) to branch logic. |
|
|
18
18
|
# | |
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
# | dolibarr: mod*.class.php, update.txt, dev version reset |
|
|
22
22
|
# | generic: README-only, no update stream |
|
|
23
23
|
# | |
|
|
24
|
-
#
|
|
24
|
+
# +=======================================================================+
|
|
25
25
|
|
|
26
26
|
name: "Universal: Build & Release"
|
|
27
27
|
|
|
@@ -51,7 +51,7 @@ permissions:
|
|
|
51
51
|
contents: write
|
|
52
52
|
|
|
53
53
|
jobs:
|
|
54
|
-
# ── PR Opened → Rename branch to RC and build RC release
|
|
54
|
+
# ── PR Opened → Rename branch to RC and build RC release ─────────────────────────
|
|
55
55
|
promote-rc:
|
|
56
56
|
name: Promote to RC
|
|
57
57
|
runs-on: release
|
|
@@ -149,7 +149,7 @@ jobs:
|
|
|
149
149
|
echo "## Promoted to Release Candidate" >> $GITHUB_STEP_SUMMARY
|
|
150
150
|
echo "Branch renamed to rc, minor bump, RC release built" >> $GITHUB_STEP_SUMMARY
|
|
151
151
|
|
|
152
|
-
# ── Merged PR → Build & Release (or promote RC to stable)
|
|
152
|
+
# ── Merged PR → Build & Release (or promote RC to stable) ─────────────────────────
|
|
153
153
|
release:
|
|
154
154
|
name: Build & Release Pipeline
|
|
155
155
|
runs-on: release
|
|
@@ -241,11 +241,47 @@ jobs:
|
|
|
241
241
|
VERSION=$(echo "$VERSION" | sed 's/-\(dev\|alpha\|beta\|rc\)$//')
|
|
242
242
|
[ -z "$VERSION" ] && VERSION="00.00.00" && echo "skip=true" >> "$GITHUB_OUTPUT"
|
|
243
243
|
echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
|
|
244
|
-
|
|
245
|
-
|
|
244
|
+
PLATFORM="${{ steps.platform.outputs.platform }}"
|
|
245
|
+
if [[ "$PLATFORM" == joomla* ]]; then
|
|
246
|
+
echo "tag=stable" >> "$GITHUB_OUTPUT"
|
|
247
|
+
echo "release_tag=stable" >> "$GITHUB_OUTPUT"
|
|
248
|
+
else
|
|
249
|
+
echo "tag=v${VERSION}" >> "$GITHUB_OUTPUT"
|
|
250
|
+
echo "release_tag=v${VERSION}" >> "$GITHUB_OUTPUT"
|
|
251
|
+
fi
|
|
246
252
|
echo "branch=main" >> "$GITHUB_OUTPUT"
|
|
247
253
|
echo "Published version: ${VERSION}"
|
|
248
254
|
|
|
255
|
+
- name: "Create semver tag for non-Joomla repos"
|
|
256
|
+
id: semver
|
|
257
|
+
if: |
|
|
258
|
+
steps.version.outputs.skip != 'true' &&
|
|
259
|
+
!startsWith(steps.platform.outputs.platform, 'joomla')
|
|
260
|
+
run: |
|
|
261
|
+
VERSION="${{ steps.version.outputs.version }}"
|
|
262
|
+
API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
|
|
263
|
+
TOKEN="${{ secrets.MOKOGITEA_TOKEN }}"
|
|
264
|
+
SEMVER_TAG="v${VERSION}"
|
|
265
|
+
|
|
266
|
+
echo "Creating semver tag: ${SEMVER_TAG}"
|
|
267
|
+
|
|
268
|
+
# Create the git tag via API
|
|
269
|
+
HTTP_CODE=$(curl -sf -o /dev/null -w "%{http_code}" \
|
|
270
|
+
-X POST -H "Authorization: token ${TOKEN}" \
|
|
271
|
+
-H "Content-Type: application/json" \
|
|
272
|
+
"${API_BASE}/tags" \
|
|
273
|
+
-d "{\"tag_name\":\"${SEMVER_TAG}\",\"target\":\"main\",\"message\":\"Release ${VERSION}\"}" 2>/dev/null || echo "000")
|
|
274
|
+
|
|
275
|
+
if [ "$HTTP_CODE" = "201" ] || [ "$HTTP_CODE" = "200" ]; then
|
|
276
|
+
echo "Created semver tag: ${SEMVER_TAG}"
|
|
277
|
+
elif [ "$HTTP_CODE" = "409" ]; then
|
|
278
|
+
echo "Semver tag ${SEMVER_TAG} already exists (skipped)"
|
|
279
|
+
else
|
|
280
|
+
echo "::warning::Failed to create semver tag ${SEMVER_TAG} (HTTP ${HTTP_CODE})"
|
|
281
|
+
fi
|
|
282
|
+
|
|
283
|
+
echo "semver_tag=${SEMVER_TAG}" >> "$GITHUB_OUTPUT"
|
|
284
|
+
|
|
249
285
|
- name: Update release notes and promote changelog
|
|
250
286
|
run: |
|
|
251
287
|
API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
|
2
|
+
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
3
|
+
|
|
4
|
+
name: "Publish to Composer"
|
|
5
|
+
|
|
6
|
+
on:
|
|
7
|
+
push:
|
|
8
|
+
tags:
|
|
9
|
+
- 'v*'
|
|
10
|
+
- '[0-9]*.[0-9]*.[0-9]*'
|
|
11
|
+
release:
|
|
12
|
+
types: [published]
|
|
13
|
+
workflow_dispatch:
|
|
14
|
+
|
|
15
|
+
env:
|
|
16
|
+
GITEA_URL: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }}
|
|
17
|
+
|
|
18
|
+
jobs:
|
|
19
|
+
publish:
|
|
20
|
+
name: Publish Package
|
|
21
|
+
runs-on: ubuntu-latest
|
|
22
|
+
if: >-
|
|
23
|
+
!contains(github.event.head_commit.message, '[skip ci]') &&
|
|
24
|
+
!contains(github.event.head_commit.message, '[skip publish]')
|
|
25
|
+
steps:
|
|
26
|
+
- name: Checkout
|
|
27
|
+
uses: actions/checkout@v4
|
|
28
|
+
|
|
29
|
+
- name: Setup PHP
|
|
30
|
+
run: |
|
|
31
|
+
if ! command -v php &> /dev/null; then
|
|
32
|
+
sudo apt-get update -qq
|
|
33
|
+
sudo apt-get install -y -qq php-cli php-mbstring php-xml php-zip php-curl composer >/dev/null 2>&1
|
|
34
|
+
fi
|
|
35
|
+
|
|
36
|
+
- name: Install dependencies
|
|
37
|
+
run: composer install --no-dev --no-interaction --prefer-dist --quiet
|
|
38
|
+
|
|
39
|
+
- name: Determine version
|
|
40
|
+
id: version
|
|
41
|
+
run: |
|
|
42
|
+
VERSION=$(php -r "echo json_decode(file_get_contents('composer.json'))->version;")
|
|
43
|
+
echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
|
|
44
|
+
echo "Package version: ${VERSION}"
|
|
45
|
+
|
|
46
|
+
# Gitea Composer Registry — auto-publishes from tags
|
|
47
|
+
# The tag push itself registers the package at:
|
|
48
|
+
# https://git.mokoconsulting.tech/api/packages/MokoConsulting/composer
|
|
49
|
+
- name: Verify Gitea registry
|
|
50
|
+
run: |
|
|
51
|
+
echo "Gitea Composer registry auto-publishes from tags."
|
|
52
|
+
echo "Package available at: ${GITEA_URL}/api/packages/MokoConsulting/composer"
|
|
53
|
+
echo "Install: composer require mokoconsulting/mokocli"
|
|
54
|
+
|
|
55
|
+
# Packagist — notify of new version
|
|
56
|
+
- name: Notify Packagist
|
|
57
|
+
if: secrets.PACKAGIST_TOKEN != ''
|
|
58
|
+
run: |
|
|
59
|
+
VERSION="${{ steps.version.outputs.version }}"
|
|
60
|
+
echo "Notifying Packagist of version ${VERSION}..."
|
|
61
|
+
curl -sf -X POST \
|
|
62
|
+
-H "Content-Type: application/json" \
|
|
63
|
+
-d '{"repository":{"url":"https://git.mokoconsulting.tech/MokoConsulting/mokocli"}}' \
|
|
64
|
+
"https://packagist.org/api/update-package?username=mokoconsulting&apiToken=${{ secrets.PACKAGIST_TOKEN }}" \
|
|
65
|
+
&& echo "Packagist notified" \
|
|
66
|
+
|| echo "::warning::Packagist notification failed (package may not be registered yet)"
|
|
67
|
+
|
|
68
|
+
- name: Summary
|
|
69
|
+
run: |
|
|
70
|
+
VERSION="${{ steps.version.outputs.version }}"
|
|
71
|
+
echo "## Composer Package Published" >> $GITHUB_STEP_SUMMARY
|
|
72
|
+
echo "" >> $GITHUB_STEP_SUMMARY
|
|
73
|
+
echo "| Registry | Status |" >> $GITHUB_STEP_SUMMARY
|
|
74
|
+
echo "|----------|--------|" >> $GITHUB_STEP_SUMMARY
|
|
75
|
+
echo "| Gitea | \`composer require mokoconsulting/mokocli:${VERSION}\` |" >> $GITHUB_STEP_SUMMARY
|
|
76
|
+
echo "| Packagist | \`composer require mokoconsulting/mokocli\` |" >> $GITHUB_STEP_SUMMARY
|
|
@@ -88,8 +88,20 @@ jobs:
|
|
|
88
88
|
php ${MOKO_CLI}/platform_detect.php --path . --github-output 2>/dev/null || true
|
|
89
89
|
php ${MOKO_CLI}/manifest_read.php --path . --github-output
|
|
90
90
|
|
|
91
|
+
- name: Check platform eligibility (Joomla only)
|
|
92
|
+
id: eligibility
|
|
93
|
+
run: |
|
|
94
|
+
PLATFORM="${{ steps.platform.outputs.platform }}"
|
|
95
|
+
if [[ "$PLATFORM" == joomla* ]] || [[ "$PLATFORM" == "joomla" ]]; then
|
|
96
|
+
echo "proceed=true" >> "$GITHUB_OUTPUT"
|
|
97
|
+
else
|
|
98
|
+
echo "proceed=false" >> "$GITHUB_OUTPUT"
|
|
99
|
+
echo "::notice::Platform '$PLATFORM' — non-Joomla, skipping pre-release auto-bump"
|
|
100
|
+
fi
|
|
101
|
+
|
|
91
102
|
- name: Resolve metadata and bump version
|
|
92
103
|
id: meta
|
|
104
|
+
if: steps.eligibility.outputs.proceed == 'true'
|
|
93
105
|
run: |
|
|
94
106
|
# Auto-detect stability from branch name on push, or use input on dispatch
|
|
95
107
|
if [ "${{ github.event_name }}" = "push" ]; then
|
|
@@ -166,6 +178,7 @@ jobs:
|
|
|
166
178
|
|
|
167
179
|
- name: Create release
|
|
168
180
|
id: release
|
|
181
|
+
if: steps.eligibility.outputs.proceed == 'true'
|
|
169
182
|
run: |
|
|
170
183
|
TAG="${{ steps.meta.outputs.tag }}"
|
|
171
184
|
VERSION="${{ steps.meta.outputs.version }}"
|
|
@@ -176,6 +189,7 @@ jobs:
|
|
|
176
189
|
--repo "${GITEA_REPO}" --branch "${{ github.ref_name }}" --prerelease
|
|
177
190
|
|
|
178
191
|
- name: Update release notes from CHANGELOG.md
|
|
192
|
+
if: steps.eligibility.outputs.proceed == 'true'
|
|
179
193
|
run: |
|
|
180
194
|
TAG="${{ steps.meta.outputs.tag }}"
|
|
181
195
|
VERSION="${{ steps.meta.outputs.version }}"
|
|
@@ -212,6 +226,7 @@ jobs:
|
|
|
212
226
|
|
|
213
227
|
- name: Build package and upload
|
|
214
228
|
id: package
|
|
229
|
+
if: steps.eligibility.outputs.proceed == 'true'
|
|
215
230
|
run: |
|
|
216
231
|
VERSION="${{ steps.meta.outputs.version }}"
|
|
217
232
|
TAG="${{ steps.meta.outputs.tag }}"
|
|
@@ -225,6 +240,7 @@ jobs:
|
|
|
225
240
|
# No need to build, commit, or sync updates.xml from workflows
|
|
226
241
|
|
|
227
242
|
- name: "Delete lesser pre-release channels (cascade)"
|
|
243
|
+
if: steps.eligibility.outputs.proceed == 'true'
|
|
228
244
|
continue-on-error: true
|
|
229
245
|
run: |
|
|
230
246
|
API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
|
package/package.json
CHANGED
|
@@ -1,237 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
# ============================================================================
|
|
3
|
-
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
|
4
|
-
#
|
|
5
|
-
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
6
|
-
#
|
|
7
|
-
# FILE INFORMATION
|
|
8
|
-
# DEFGROUP: Automation.CI
|
|
9
|
-
# INGROUP: moko-platform.Automation
|
|
10
|
-
# REPO: https://git.mokoconsulting.tech/MokoConsulting/moko-platform
|
|
11
|
-
# PATH: /automation/ci-issue-reporter.sh
|
|
12
|
-
# VERSION: 09.23.00
|
|
13
|
-
# BRIEF: Creates or updates a Gitea issue when a CI gate fails.
|
|
14
|
-
# Deduplicates by searching open issues with the "ci-auto" label
|
|
15
|
-
# whose title matches the gate. If a matching issue exists, a comment
|
|
16
|
-
# is appended instead of opening a duplicate.
|
|
17
|
-
# ============================================================================
|
|
18
|
-
|
|
19
|
-
set -euo pipefail
|
|
20
|
-
|
|
21
|
-
# ── Defaults ────────────────────────────────────────────────────────────────
|
|
22
|
-
GITEA_URL="${GITEA_URL:-https://git.mokoconsulting.tech}"
|
|
23
|
-
GITEA_TOKEN="${GITEA_TOKEN:-}"
|
|
24
|
-
REPO="${GITHUB_REPOSITORY:-}"
|
|
25
|
-
RUN_URL="${GITHUB_SERVER_URL:-${GITEA_URL}}/${REPO}/actions/runs/${GITHUB_RUN_ID:-0}"
|
|
26
|
-
LABEL_NAME="ci-auto"
|
|
27
|
-
LABEL_COLOR="#e11d48"
|
|
28
|
-
|
|
29
|
-
GATE=""
|
|
30
|
-
DETAILS=""
|
|
31
|
-
SEVERITY="error"
|
|
32
|
-
WORKFLOW=""
|
|
33
|
-
|
|
34
|
-
# ── Parse arguments ─────────────────────────────────────────────────────────
|
|
35
|
-
usage() {
|
|
36
|
-
cat <<EOF
|
|
37
|
-
Usage: ci-issue-reporter.sh --gate NAME --details TEXT [OPTIONS]
|
|
38
|
-
|
|
39
|
-
Required:
|
|
40
|
-
--gate CI gate name (e.g. "Code Quality", "Self-Health")
|
|
41
|
-
--details Human-readable failure description
|
|
42
|
-
|
|
43
|
-
Optional:
|
|
44
|
-
--severity "error" (default) or "warning"
|
|
45
|
-
--workflow Workflow name for the issue title
|
|
46
|
-
--repo owner/repo (default: \$GITHUB_REPOSITORY)
|
|
47
|
-
--run-url URL to the CI run (auto-detected from env)
|
|
48
|
-
--token Gitea API token (default: \$GITEA_TOKEN)
|
|
49
|
-
--url Gitea base URL (default: \$GITEA_URL)
|
|
50
|
-
EOF
|
|
51
|
-
exit 1
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
while [[ $# -gt 0 ]]; do
|
|
55
|
-
case "$1" in
|
|
56
|
-
--gate) GATE="$2"; shift 2 ;;
|
|
57
|
-
--details) DETAILS="$2"; shift 2 ;;
|
|
58
|
-
--severity) SEVERITY="$2"; shift 2 ;;
|
|
59
|
-
--workflow) WORKFLOW="$2"; shift 2 ;;
|
|
60
|
-
--repo) REPO="$2"; shift 2 ;;
|
|
61
|
-
--run-url) RUN_URL="$2"; shift 2 ;;
|
|
62
|
-
--token) GITEA_TOKEN="$2"; shift 2 ;;
|
|
63
|
-
--url) GITEA_URL="$2"; shift 2 ;;
|
|
64
|
-
-h|--help) usage ;;
|
|
65
|
-
*) echo "Unknown option: $1"; usage ;;
|
|
66
|
-
esac
|
|
67
|
-
done
|
|
68
|
-
|
|
69
|
-
[[ -z "$GATE" ]] && { echo "ERROR: --gate is required"; usage; }
|
|
70
|
-
[[ -z "$DETAILS" ]] && { echo "ERROR: --details is required"; usage; }
|
|
71
|
-
[[ -z "$GITEA_TOKEN" ]] && { echo "ERROR: GITEA_TOKEN not set"; exit 1; }
|
|
72
|
-
[[ -z "$REPO" ]] && { echo "ERROR: GITHUB_REPOSITORY not set"; exit 1; }
|
|
73
|
-
|
|
74
|
-
API="${GITEA_URL}/api/v1/repos/${REPO}"
|
|
75
|
-
|
|
76
|
-
# ── Build title ─────────────────────────────────────────────────────────────
|
|
77
|
-
if [[ -n "$WORKFLOW" ]]; then
|
|
78
|
-
TITLE="[CI] ${WORKFLOW}: ${GATE} failed"
|
|
79
|
-
else
|
|
80
|
-
TITLE="[CI] ${GATE} failed"
|
|
81
|
-
fi
|
|
82
|
-
|
|
83
|
-
# ── Ensure label exists ─────────────────────────────────────────────────────
|
|
84
|
-
ensure_label() {
|
|
85
|
-
local exists
|
|
86
|
-
exists=$(curl -sf -o /dev/null -w '%{http_code}' \
|
|
87
|
-
-H "Authorization: token ${GITEA_TOKEN}" \
|
|
88
|
-
"${API}/labels" 2>/dev/null || echo "000")
|
|
89
|
-
|
|
90
|
-
if [[ "$exists" == "200" ]]; then
|
|
91
|
-
# Check if label already exists
|
|
92
|
-
local found
|
|
93
|
-
found=$(curl -sf \
|
|
94
|
-
-H "Authorization: token ${GITEA_TOKEN}" \
|
|
95
|
-
"${API}/labels" 2>/dev/null \
|
|
96
|
-
| grep -o "\"name\":\"${LABEL_NAME}\"" || true)
|
|
97
|
-
|
|
98
|
-
if [[ -z "$found" ]]; then
|
|
99
|
-
curl -sf -X POST \
|
|
100
|
-
-H "Authorization: token ${GITEA_TOKEN}" \
|
|
101
|
-
-H "Content-Type: application/json" \
|
|
102
|
-
"${API}/labels" \
|
|
103
|
-
-d "{\"name\":\"${LABEL_NAME}\",\"color\":\"${LABEL_COLOR}\",\"description\":\"Auto-created by CI issue reporter\"}" \
|
|
104
|
-
> /dev/null 2>&1 || true
|
|
105
|
-
fi
|
|
106
|
-
fi
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
# ── Search for existing open issue ──────────────────────────────────────────
|
|
110
|
-
find_existing_issue() {
|
|
111
|
-
# URL-encode the gate name for the query
|
|
112
|
-
local query
|
|
113
|
-
query=$(printf '%s' "[CI] ${GATE}" | sed 's/ /%20/g; s/\[/%5B/g; s/\]/%5D/g')
|
|
114
|
-
|
|
115
|
-
local response
|
|
116
|
-
response=$(curl -sf \
|
|
117
|
-
-H "Authorization: token ${GITEA_TOKEN}" \
|
|
118
|
-
"${API}/issues?type=issues&state=open&labels=${LABEL_NAME}&q=${query}&limit=5" \
|
|
119
|
-
2>/dev/null || echo "[]")
|
|
120
|
-
|
|
121
|
-
# Extract the first matching issue number
|
|
122
|
-
echo "$response" \
|
|
123
|
-
| grep -oP '"number":\s*\K[0-9]+' \
|
|
124
|
-
| head -1
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
# ── Build issue body ────────────────────────────────────────────────────────
|
|
128
|
-
build_body() {
|
|
129
|
-
local severity_badge
|
|
130
|
-
if [[ "$SEVERITY" == "error" ]]; then
|
|
131
|
-
severity_badge="**Severity:** Error"
|
|
132
|
-
else
|
|
133
|
-
severity_badge="**Severity:** Warning"
|
|
134
|
-
fi
|
|
135
|
-
|
|
136
|
-
cat <<BODY
|
|
137
|
-
## CI Gate Failure: ${GATE}
|
|
138
|
-
|
|
139
|
-
${severity_badge}
|
|
140
|
-
**Workflow:** ${WORKFLOW:-unknown}
|
|
141
|
-
**Branch:** ${GITHUB_REF_NAME:-unknown}
|
|
142
|
-
**Commit:** \`${GITHUB_SHA:0:8}\`
|
|
143
|
-
**Run:** [View CI run](${RUN_URL})
|
|
144
|
-
|
|
145
|
-
### Details
|
|
146
|
-
|
|
147
|
-
${DETAILS}
|
|
148
|
-
|
|
149
|
-
### Resolution
|
|
150
|
-
|
|
151
|
-
Fix the issue described above and push a new commit. This issue will be closed automatically when the gate passes, or can be closed manually.
|
|
152
|
-
|
|
153
|
-
---
|
|
154
|
-
*Auto-created by [ci-issue-reporter](${GITEA_URL}/${REPO}/src/branch/main/automation/ci-issue-reporter.sh)*
|
|
155
|
-
BODY
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
# ── Build comment body (for existing issues) ────────────────────────────────
|
|
159
|
-
build_comment() {
|
|
160
|
-
cat <<COMMENT
|
|
161
|
-
### CI failure recurrence
|
|
162
|
-
|
|
163
|
-
**Branch:** ${GITHUB_REF_NAME:-unknown}
|
|
164
|
-
**Commit:** \`${GITHUB_SHA:0:8}\`
|
|
165
|
-
**Run:** [View CI run](${RUN_URL})
|
|
166
|
-
|
|
167
|
-
${DETAILS}
|
|
168
|
-
COMMENT
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
# ── Main ────────────────────────────────────────────────────────────────────
|
|
172
|
-
ensure_label
|
|
173
|
-
|
|
174
|
-
EXISTING=$(find_existing_issue)
|
|
175
|
-
|
|
176
|
-
if [[ -n "$EXISTING" ]]; then
|
|
177
|
-
# Append comment to existing issue
|
|
178
|
-
COMMENT_BODY=$(build_comment)
|
|
179
|
-
COMMENT_JSON=$(printf '%s' "$COMMENT_BODY" | python3 -c "
|
|
180
|
-
import sys, json
|
|
181
|
-
print(json.dumps({'body': sys.stdin.read()}))" 2>/dev/null)
|
|
182
|
-
|
|
183
|
-
HTTP=$(curl -sf -o /dev/null -w '%{http_code}' -X POST \
|
|
184
|
-
-H "Authorization: token ${GITEA_TOKEN}" \
|
|
185
|
-
-H "Content-Type: application/json" \
|
|
186
|
-
"${API}/issues/${EXISTING}/comments" \
|
|
187
|
-
-d "${COMMENT_JSON}" 2>/dev/null || echo "000")
|
|
188
|
-
|
|
189
|
-
if [[ "$HTTP" == "201" ]]; then
|
|
190
|
-
echo "Commented on existing issue #${EXISTING}"
|
|
191
|
-
else
|
|
192
|
-
echo "WARNING: Failed to comment on issue #${EXISTING} (HTTP ${HTTP})"
|
|
193
|
-
fi
|
|
194
|
-
else
|
|
195
|
-
# Create new issue
|
|
196
|
-
ISSUE_BODY=$(build_body)
|
|
197
|
-
ISSUE_JSON=$(python3 -c "
|
|
198
|
-
import sys, json
|
|
199
|
-
body = sys.stdin.read()
|
|
200
|
-
print(json.dumps({
|
|
201
|
-
'title': sys.argv[1],
|
|
202
|
-
'body': body,
|
|
203
|
-
'labels': []
|
|
204
|
-
}))" "$TITLE" <<< "$ISSUE_BODY" 2>/dev/null)
|
|
205
|
-
|
|
206
|
-
# Create the issue
|
|
207
|
-
RESPONSE=$(curl -sf -X POST \
|
|
208
|
-
-H "Authorization: token ${GITEA_TOKEN}" \
|
|
209
|
-
-H "Content-Type: application/json" \
|
|
210
|
-
"${API}/issues" \
|
|
211
|
-
-d "${ISSUE_JSON}" 2>/dev/null || echo "{}")
|
|
212
|
-
|
|
213
|
-
ISSUE_NUM=$(echo "$RESPONSE" | grep -oP '"number":\s*\K[0-9]+' | head -1)
|
|
214
|
-
|
|
215
|
-
if [[ -n "$ISSUE_NUM" ]]; then
|
|
216
|
-
# Apply label (separate call — more reliable across Gitea versions)
|
|
217
|
-
LABEL_ID=$(curl -sf \
|
|
218
|
-
-H "Authorization: token ${GITEA_TOKEN}" \
|
|
219
|
-
"${API}/labels" 2>/dev/null \
|
|
220
|
-
| grep -oP "\"id\":\s*\K[0-9]+(?=[^}]*\"name\":\s*\"${LABEL_NAME}\")" \
|
|
221
|
-
| head -1 || true)
|
|
222
|
-
|
|
223
|
-
if [[ -n "$LABEL_ID" ]]; then
|
|
224
|
-
curl -sf -X POST \
|
|
225
|
-
-H "Authorization: token ${GITEA_TOKEN}" \
|
|
226
|
-
-H "Content-Type: application/json" \
|
|
227
|
-
"${API}/issues/${ISSUE_NUM}/labels" \
|
|
228
|
-
-d "{\"labels\":[${LABEL_ID}]}" \
|
|
229
|
-
> /dev/null 2>&1 || true
|
|
230
|
-
fi
|
|
231
|
-
|
|
232
|
-
echo "Created issue #${ISSUE_NUM}: ${TITLE}"
|
|
233
|
-
else
|
|
234
|
-
echo "WARNING: Failed to create issue"
|
|
235
|
-
echo "Response: ${RESPONSE}"
|
|
236
|
-
fi
|
|
237
|
-
fi
|
package/scripts/setup.mjs
DELETED
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/* Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
|
3
|
-
*
|
|
4
|
-
* This file is part of a Moko Consulting project.
|
|
5
|
-
*
|
|
6
|
-
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
7
|
-
*
|
|
8
|
-
* FILE INFORMATION
|
|
9
|
-
* DEFGROUP: mcp_windows.Scripts
|
|
10
|
-
* INGROUP: mcp_windows
|
|
11
|
-
* REPO: https://git.mokoconsulting.tech/MokoConsulting/mcp_windows
|
|
12
|
-
* PATH: /scripts/setup.mjs
|
|
13
|
-
* VERSION: 01.00.00
|
|
14
|
-
* BRIEF: Interactive setup — prompts for API connection details and writes config
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
import { createInterface } from 'node:readline/promises';
|
|
18
|
-
import { readFile, writeFile } from 'node:fs/promises';
|
|
19
|
-
import { resolve } from 'node:path';
|
|
20
|
-
import { homedir } from 'node:os';
|
|
21
|
-
|
|
22
|
-
// ── Customize these ─────────────────────────────────────────────────────
|
|
23
|
-
const PROJECT_NAME = 'mcp_windows';
|
|
24
|
-
const CONFIG_PATH = resolve(homedir(), `.${PROJECT_NAME}.json`);
|
|
25
|
-
const API_LABEL = 'Windows Desktop'; // e.g. "Dolibarr", "Joomla"
|
|
26
|
-
const AUTH_FIELD = 'apiKey'; // field name in config
|
|
27
|
-
const AUTH_PROMPT = 'API key'; // what to ask the user for
|
|
28
|
-
// ────────────────────────────────────────────────────────────────────────
|
|
29
|
-
|
|
30
|
-
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
31
|
-
|
|
32
|
-
async function prompt(question, defaultValue) {
|
|
33
|
-
const suffix = defaultValue ? ` [${defaultValue}]` : '';
|
|
34
|
-
const answer = await rl.question(`${question}${suffix}: `);
|
|
35
|
-
return answer.trim() || defaultValue || '';
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
async function promptRequired(question) {
|
|
39
|
-
let answer = '';
|
|
40
|
-
while (!answer) {
|
|
41
|
-
answer = (await rl.question(`${question}: `)).trim();
|
|
42
|
-
if (!answer) {
|
|
43
|
-
console.log(' This field is required.');
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
return answer;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
async function main() {
|
|
50
|
-
console.log('');
|
|
51
|
-
console.log(`=== ${PROJECT_NAME} Setup ===`);
|
|
52
|
-
console.log('');
|
|
53
|
-
console.log('This will create your configuration file at:');
|
|
54
|
-
console.log(` ${CONFIG_PATH}`);
|
|
55
|
-
console.log('');
|
|
56
|
-
|
|
57
|
-
let existing = null;
|
|
58
|
-
try {
|
|
59
|
-
const raw = await readFile(CONFIG_PATH, 'utf-8');
|
|
60
|
-
existing = JSON.parse(raw);
|
|
61
|
-
console.log('Existing config found. You can add a new connection or overwrite.');
|
|
62
|
-
console.log(` Current connections: ${Object.keys(existing.connections).join(', ')}`);
|
|
63
|
-
console.log('');
|
|
64
|
-
} catch {
|
|
65
|
-
// No existing config
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
const connectionName = await prompt('Connection name', 'production');
|
|
69
|
-
const baseUrl = await promptRequired(`${API_LABEL} URL (e.g. https://api.example.com)`);
|
|
70
|
-
const authValue = await promptRequired(`${API_LABEL} ${AUTH_PROMPT}`);
|
|
71
|
-
|
|
72
|
-
const cleanUrl = baseUrl.replace(/\/+$/, '');
|
|
73
|
-
|
|
74
|
-
const insecureAnswer = await prompt('Skip TLS verification for self-signed certs? (y/N)', 'N');
|
|
75
|
-
const insecure = insecureAnswer.toLowerCase() === 'y';
|
|
76
|
-
|
|
77
|
-
const connection = { baseUrl: cleanUrl, [AUTH_FIELD]: authValue };
|
|
78
|
-
if (insecure) {
|
|
79
|
-
connection.insecure = true;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
let config;
|
|
83
|
-
if (existing) {
|
|
84
|
-
config = existing;
|
|
85
|
-
config.connections[connectionName] = connection;
|
|
86
|
-
const setDefault = await prompt(`Set "${connectionName}" as default connection? (y/N)`, 'N');
|
|
87
|
-
if (setDefault.toLowerCase() === 'y') {
|
|
88
|
-
config.defaultConnection = connectionName;
|
|
89
|
-
}
|
|
90
|
-
} else {
|
|
91
|
-
config = {
|
|
92
|
-
defaultConnection: connectionName,
|
|
93
|
-
connections: {
|
|
94
|
-
[connectionName]: connection,
|
|
95
|
-
},
|
|
96
|
-
};
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
await writeFile(CONFIG_PATH, JSON.stringify(config, null, '\t') + '\n', 'utf-8');
|
|
100
|
-
|
|
101
|
-
console.log('');
|
|
102
|
-
console.log(`Config written to ${CONFIG_PATH}`);
|
|
103
|
-
console.log(` Connection "${connectionName}" configured for ${cleanUrl}`);
|
|
104
|
-
console.log('');
|
|
105
|
-
|
|
106
|
-
const addAnother = await prompt('Add another connection? (y/N)', 'N');
|
|
107
|
-
if (addAnother.toLowerCase() === 'y') {
|
|
108
|
-
rl.close();
|
|
109
|
-
const { execFileSync } = await import('node:child_process');
|
|
110
|
-
execFileSync('node', [new URL(import.meta.url).pathname], { stdio: 'inherit' });
|
|
111
|
-
return;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
console.log('Setup complete. You can now use the MCP server.');
|
|
115
|
-
console.log('');
|
|
116
|
-
rl.close();
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
main().catch((err) => {
|
|
120
|
-
console.error(`Setup failed: ${err.message}`);
|
|
121
|
-
rl.close();
|
|
122
|
-
process.exit(1);
|
|
123
|
-
});
|