bigpowers 2.88.6 → 2.88.8
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.
- package/.gemini/extensions/bigpowers/gemini-extension.json +1 -1
- package/.pi/package.json +1 -1
- package/CHANGELOG.md +14 -0
- package/package.json +1 -1
- package/scripts/lib/__pycache__/link_utils.cpython-312.pyc +0 -0
- package/scripts/lib/__pycache__/srp_engine_links.cpython-312.pyc +0 -0
- package/scripts/lib/skill-common.sh +3 -1
- package/scripts/lib/srp-engine.py +3 -1
- package/scripts/mcp-server.js +34 -14
- package/scripts/test-resolve-repo-root.sh +44 -0
package/.pi/package.json
CHANGED
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
## [2.88.8](https://github.com/danielvm-git/bigpowers/compare/v2.88.7...v2.88.8) (2026-09-21)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* **mcp:** switch stdio transport to newline-delimited JSON per MCP spec ([#132](https://github.com/danielvm-git/bigpowers/issues/132)) ([2e07b81](https://github.com/danielvm-git/bigpowers/commit/2e07b81e6a19ee8cad12001114193e22cf224511)), closes [#131](https://github.com/danielvm-git/bigpowers/issues/131)
|
|
7
|
+
|
|
8
|
+
## [2.88.7](https://github.com/danielvm-git/bigpowers/compare/v2.88.6...v2.88.7) (2026-09-17)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
* **scripts:** resolve repo root in projects without skills/ ([093fef7](https://github.com/danielvm-git/bigpowers/commit/093fef72eb9f3be4c8cc61431df421752ed1ed44)), closes [#130](https://github.com/danielvm-git/bigpowers/issues/130)
|
|
14
|
+
|
|
1
15
|
## [2.88.6](https://github.com/danielvm-git/bigpowers/compare/v2.88.5...v2.88.6) (2026-09-13)
|
|
2
16
|
|
|
3
17
|
|
package/package.json
CHANGED
|
Binary file
|
|
Binary file
|
|
@@ -16,7 +16,9 @@ resolve_repo_root() {
|
|
|
16
16
|
# Library is at REPO/scripts/lib/skill-common.sh → two levels up
|
|
17
17
|
local repo_candidate
|
|
18
18
|
repo_candidate="$(cd "$lib_dir/../.." 2>/dev/null && pwd)"
|
|
19
|
-
if [ -n "$repo_candidate" ] &&
|
|
19
|
+
if [ -n "$repo_candidate" ] && {
|
|
20
|
+
[ -d "$repo_candidate/scripts/lib" ] || [ -d "$repo_candidate/skills" ]
|
|
21
|
+
}; then
|
|
20
22
|
REPO_ROOT="$repo_candidate"
|
|
21
23
|
else
|
|
22
24
|
repo_candidate="$(cd "$lib_dir/.." 2>/dev/null && pwd)"
|
|
@@ -31,7 +31,9 @@ def resolve_repo_root():
|
|
|
31
31
|
lib_dir = os.path.dirname(os.path.abspath(__file__))
|
|
32
32
|
# scripts/lib/srp-engine.py -> two levels up is REPO_ROOT
|
|
33
33
|
repo_candidate = os.path.dirname(os.path.dirname(lib_dir))
|
|
34
|
-
if os.path.isdir(os.path.join(repo_candidate, "
|
|
34
|
+
if os.path.isdir(os.path.join(repo_candidate, "scripts", "lib")) or os.path.isdir(
|
|
35
|
+
os.path.join(repo_candidate, "skills")
|
|
36
|
+
):
|
|
35
37
|
return repo_candidate
|
|
36
38
|
return os.path.dirname(lib_dir)
|
|
37
39
|
|
package/scripts/mcp-server.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
// bigpowers MCP server — exposes 68 skills as MCP tools via stdio transport
|
|
3
|
-
// Zero dependencies — raw JSON-RPC over stdio
|
|
3
|
+
// Zero dependencies — raw JSON-RPC over stdio (newline-delimited, per MCP spec)
|
|
4
4
|
|
|
5
5
|
'use strict';
|
|
6
6
|
|
|
@@ -154,6 +154,7 @@ const TOOLS = {
|
|
|
154
154
|
// ─── MCP stdio transport ──────────────────────────────────────────────────────
|
|
155
155
|
|
|
156
156
|
let inputBuffer = Buffer.alloc(0);
|
|
157
|
+
let useLspFraming = false;
|
|
157
158
|
|
|
158
159
|
process.stdin.on('data', chunk => {
|
|
159
160
|
inputBuffer = Buffer.concat([inputBuffer, chunk]);
|
|
@@ -163,28 +164,47 @@ process.stdin.on('data', chunk => {
|
|
|
163
164
|
process.stdin.on('end', () => process.exit(0));
|
|
164
165
|
|
|
165
166
|
function processBuffer() {
|
|
166
|
-
while (
|
|
167
|
-
|
|
168
|
-
if (
|
|
167
|
+
while (inputBuffer.length) {
|
|
168
|
+
// Legacy: LSP-style Content-Length framing (kept for backwards compatibility)
|
|
169
|
+
if (/^\s*Content-Length:/i.test(inputBuffer.toString('utf8', 0, Math.min(inputBuffer.length, 20)))) {
|
|
170
|
+
const headerEnd = inputBuffer.indexOf('\r\n\r\n');
|
|
171
|
+
if (headerEnd === -1) break;
|
|
169
172
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
+
const header = inputBuffer.slice(0, headerEnd).toString();
|
|
174
|
+
const match = header.match(/Content-Length:\s*(\d+)/i);
|
|
175
|
+
if (!match) { inputBuffer = inputBuffer.slice(headerEnd + 4); continue; }
|
|
173
176
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
+
const contentLength = parseInt(match[1], 10);
|
|
178
|
+
const bodyStart = headerEnd + 4;
|
|
179
|
+
if (inputBuffer.length < bodyStart + contentLength) break;
|
|
177
180
|
|
|
178
|
-
|
|
179
|
-
|
|
181
|
+
const body = inputBuffer.slice(bodyStart, bodyStart + contentLength).toString();
|
|
182
|
+
inputBuffer = inputBuffer.slice(bodyStart + contentLength);
|
|
180
183
|
|
|
181
|
-
|
|
184
|
+
useLspFraming = true;
|
|
185
|
+
try { handleMessage(JSON.parse(body)); } catch (_) {}
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// MCP stdio standard: newline-delimited JSON
|
|
190
|
+
const nl = inputBuffer.indexOf('\n');
|
|
191
|
+
if (nl === -1) break;
|
|
192
|
+
|
|
193
|
+
const line = inputBuffer.slice(0, nl).toString().trim();
|
|
194
|
+
inputBuffer = inputBuffer.slice(nl + 1);
|
|
195
|
+
|
|
196
|
+
useLspFraming = false;
|
|
197
|
+
if (line) try { handleMessage(JSON.parse(line)); } catch (_) {}
|
|
182
198
|
}
|
|
183
199
|
}
|
|
184
200
|
|
|
185
201
|
function send(msg) {
|
|
186
202
|
const body = JSON.stringify(msg);
|
|
187
|
-
|
|
203
|
+
if (useLspFraming) {
|
|
204
|
+
process.stdout.write(`Content-Length: ${Buffer.byteLength(body, 'utf8')}\r\n\r\n${body}`);
|
|
205
|
+
} else {
|
|
206
|
+
process.stdout.write(body + '\n');
|
|
207
|
+
}
|
|
188
208
|
}
|
|
189
209
|
|
|
190
210
|
function handleInitialize(id) {
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Regression test for resolve_repo_root() in consumer layouts without skills/.
|
|
3
|
+
# See: https://github.com/danielvm-git/bigpowers/issues/130
|
|
4
|
+
set -euo pipefail
|
|
5
|
+
|
|
6
|
+
TA_PASS=0
|
|
7
|
+
TA_FAIL=0
|
|
8
|
+
TA_TMPDIR=""
|
|
9
|
+
|
|
10
|
+
source "$(dirname "${BASH_SOURCE[0]}")/lib/test-assertions.sh"
|
|
11
|
+
trap ta_cleanup EXIT
|
|
12
|
+
|
|
13
|
+
echo "=== test-resolve-repo-root.sh ==="
|
|
14
|
+
|
|
15
|
+
# Consumer project: scripts/lib present, no local skills/ directory.
|
|
16
|
+
TA_TMPDIR="$(mktemp -d)"
|
|
17
|
+
mkdir -p "$TA_TMPDIR/scripts/lib"
|
|
18
|
+
cp "$(dirname "${BASH_SOURCE[0]}")/lib/skill-common.sh" "$TA_TMPDIR/scripts/lib/"
|
|
19
|
+
|
|
20
|
+
set +e
|
|
21
|
+
out=$(bash -c "source '$TA_TMPDIR/scripts/lib/skill-common.sh' && resolve_repo_root && printf '%s|%s' \"\$REPO_ROOT\" \"\$SKILLS_ROOT\"")
|
|
22
|
+
rc=$?
|
|
23
|
+
set -e
|
|
24
|
+
|
|
25
|
+
if [[ $rc -ne 0 ]]; then
|
|
26
|
+
ta_fail "consumer layout: resolve_repo_root exited $rc"
|
|
27
|
+
elif [[ "$out" == "$TA_TMPDIR|$TA_TMPDIR" ]]; then
|
|
28
|
+
ta_pass "consumer layout without skills/ resolves repo root (not scripts/)"
|
|
29
|
+
else
|
|
30
|
+
ta_fail "consumer layout: expected REPO_ROOT=$TA_TMPDIR, got: $out"
|
|
31
|
+
fi
|
|
32
|
+
|
|
33
|
+
# bigpowers repo: skills/ and scripts/lib both present.
|
|
34
|
+
source "$(dirname "${BASH_SOURCE[0]}")/lib/skill-common.sh"
|
|
35
|
+
resolve_repo_root
|
|
36
|
+
expected_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
37
|
+
if [[ "$REPO_ROOT" == "$expected_root" && -d "$REPO_ROOT/skills" ]]; then
|
|
38
|
+
ta_pass "bigpowers repo resolves REPO_ROOT with skills/"
|
|
39
|
+
else
|
|
40
|
+
ta_fail "bigpowers repo: REPO_ROOT=$REPO_ROOT expected=$expected_root"
|
|
41
|
+
fi
|
|
42
|
+
|
|
43
|
+
echo "=== $TA_PASS passed, $TA_FAIL failed ==="
|
|
44
|
+
[[ "$TA_FAIL" -eq 0 ]]
|