@house365/comate 0.2.8 → 0.2.9
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/bin/init-run.mjs +31 -0
- package/bin/init.mjs +9 -3
- package/package.json +1 -1
- package/skills/comate/scripts/comate.sh +18 -0
package/bin/init-run.mjs
CHANGED
|
@@ -3,8 +3,10 @@ import { spawn } from 'node:child_process';
|
|
|
3
3
|
import { existsSync, readFileSync } from 'node:fs';
|
|
4
4
|
import { join, resolve } from 'node:path';
|
|
5
5
|
|
|
6
|
+
import { findBash } from './doctor.mjs';
|
|
6
7
|
import {
|
|
7
8
|
NPM_TIMEOUT_MS,
|
|
9
|
+
capture,
|
|
8
10
|
SKILLS_TIMEOUT_MS,
|
|
9
11
|
npmInvocation,
|
|
10
12
|
openSpecState,
|
|
@@ -55,6 +57,19 @@ export async function init(pkgRoot) {
|
|
|
55
57
|
return 1;
|
|
56
58
|
}
|
|
57
59
|
|
|
60
|
+
// comate's skills are bash scripts needing associative arrays (bash 4+), and
|
|
61
|
+
// macOS ships 3.2. Fail here rather than installing everything and letting the
|
|
62
|
+
// first /comate call die inside a sourced library.
|
|
63
|
+
const bash = bashVersion();
|
|
64
|
+
if (bash !== null && bash < 4) {
|
|
65
|
+
console.error(
|
|
66
|
+
`\ncomate 的脚本需要 bash >= 4,当前 ${bash === 0 ? '未知版本' : `bash ${bash}.x`}。\n` +
|
|
67
|
+
'macOS 自带 bash 3.2(授权原因),装一个新的:\n\n brew install bash\n\n' +
|
|
68
|
+
'装好后重跑 comate init。',
|
|
69
|
+
);
|
|
70
|
+
return 3;
|
|
71
|
+
}
|
|
72
|
+
|
|
58
73
|
const stopSpinner = startSpinner('Initializing…');
|
|
59
74
|
|
|
60
75
|
// 1. OpenSpec CLI — a PATH command, so always global.
|
|
@@ -236,6 +251,22 @@ export function banner(version, { ci = isCI() } = {}) {
|
|
|
236
251
|
].join('\n');
|
|
237
252
|
}
|
|
238
253
|
|
|
254
|
+
// Major version of the bash that comate's scripts will actually run under, or
|
|
255
|
+
// null when there is no bash at all — that is doctor's diagnosis to deliver, not
|
|
256
|
+
// a reason to block the install. Windows resolves through findBash so a Git Bash
|
|
257
|
+
// install is not mistaken for the WSL launcher.
|
|
258
|
+
// Parsed from --version rather than `-c 'echo $BASH_VERSINFO'`: capture() runs
|
|
259
|
+
// through a shell on Windows, which swallows the variable before bash sees it.
|
|
260
|
+
export function bashVersion(probe = (bin) => capture(bin, ['--version'])) {
|
|
261
|
+
const bin = process.platform === 'win32' ? findBash() : 'bash';
|
|
262
|
+
if (!bin) return null;
|
|
263
|
+
const out = probe(bin);
|
|
264
|
+
if (out === null) return null;
|
|
265
|
+
// "GNU bash, version 5.2.26(1)-release ..." / macOS: "... version 3.2.57(1)"
|
|
266
|
+
const major = out.match(/version (\d+)\./)?.[1];
|
|
267
|
+
return major === undefined ? 0 : Number(major);
|
|
268
|
+
}
|
|
269
|
+
|
|
239
270
|
// Every major CI sets CI=true; GITHUB_ACTIONS covers the Actions runner even in
|
|
240
271
|
// the odd config that doesn't.
|
|
241
272
|
function isCI() {
|
package/bin/init.mjs
CHANGED
|
@@ -98,12 +98,16 @@ function run({ command, args, shell }, timeout, { quiet = false } = {}) {
|
|
|
98
98
|
return { ok: true };
|
|
99
99
|
}
|
|
100
100
|
|
|
101
|
-
|
|
101
|
+
// shell defaults to off: passing args with shell:true is deprecated in Node 24
|
|
102
|
+
// and is an injection surface, since the args are concatenated rather than
|
|
103
|
+
// escaped. Callers that genuinely need cmd.exe resolution (a bare `openspec`
|
|
104
|
+
// that only exists as openspec.cmd) opt in explicitly.
|
|
105
|
+
function capture(command, args, { shell = false } = {}) {
|
|
102
106
|
const { status, stdout: out } = spawnSync(command, args, {
|
|
103
107
|
encoding: 'utf8',
|
|
104
108
|
stdio: ['ignore', 'pipe', 'ignore'],
|
|
105
109
|
timeout: 15_000,
|
|
106
|
-
shell:
|
|
110
|
+
...(shell ? { shell: true } : {}),
|
|
107
111
|
});
|
|
108
112
|
return status === 0 ? out.trim() : null;
|
|
109
113
|
}
|
|
@@ -138,7 +142,9 @@ function skillsInvocation(pkgRoot, args) {
|
|
|
138
142
|
}
|
|
139
143
|
|
|
140
144
|
function openSpecState() {
|
|
141
|
-
|
|
145
|
+
// shell:true on Windows: npm installs this as openspec.cmd, which cannot be
|
|
146
|
+
// spawned directly. bashVersion needs no shell — it has a real executable path.
|
|
147
|
+
const version = capture('openspec', ['--version'], { shell: process.platform === 'win32' });
|
|
142
148
|
if (version === null) return { status: 'missing' };
|
|
143
149
|
return { status: atLeast(version, MIN_OPENSPEC) ? 'ready' : 'outdated', version };
|
|
144
150
|
}
|
package/package.json
CHANGED
|
@@ -25,6 +25,24 @@
|
|
|
25
25
|
|
|
26
26
|
set -euo pipefail
|
|
27
27
|
|
|
28
|
+
# Must come before sourcing the lib. comate-lib.sh declares associative arrays
|
|
29
|
+
# at load time, which bash 3.2 (what macOS ships as /bin/bash) parses as an
|
|
30
|
+
# ordinary array assignment — the subscript is then evaluated as arithmetic and
|
|
31
|
+
# `set -u` aborts with "schema_version: unbound variable". doctor has its own
|
|
32
|
+
# bash>=4 check, but it never got to run: the source above it already died.
|
|
33
|
+
if [ "${BASH_VERSINFO[0]:-0}" -lt 4 ]; then
|
|
34
|
+
cat >&2 <<EOF
|
|
35
|
+
comate needs bash >= 4 (associative arrays), found ${BASH_VERSION:-unknown}.
|
|
36
|
+
|
|
37
|
+
macOS ships bash 3.2 for licensing reasons. Install a current one:
|
|
38
|
+
brew install bash
|
|
39
|
+
|
|
40
|
+
Then re-run through it, e.g.:
|
|
41
|
+
$(command -v brew >/dev/null 2>&1 && echo "\$(brew --prefix)/bin/bash" || echo /opt/homebrew/bin/bash) $0 $*
|
|
42
|
+
EOF
|
|
43
|
+
exit 3
|
|
44
|
+
fi
|
|
45
|
+
|
|
28
46
|
SCRIPT_DIR="$(cd "$(dirname "$(readlink -f "$0" 2>/dev/null || echo "$0")")" && pwd)"
|
|
29
47
|
# shellcheck source=comate-lib.sh
|
|
30
48
|
. "$SCRIPT_DIR/comate-lib.sh"
|