ai-consultants 3.2.0 → 3.4.0
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/.env.example +14 -2
- package/CLAUDE.md +29 -6
- package/README.md +9 -6
- package/SKILL.md +7 -2
- package/docs/COST_RATES.md +13 -13
- package/docs/JSON_SCHEMA.md +4 -0
- package/docs/RECIPES.md +17 -7
- package/docs/cost_rates.json +52 -23
- package/docs/releases/v3.3.0.md +80 -0
- package/docs/releases/v3.4.0.md +102 -0
- package/package.json +1 -1
- package/references/configuration.md +8 -3
- package/scripts/config.sh +9 -9
- package/scripts/configure.sh +9 -0
- package/scripts/doctor.sh +8 -2
- package/scripts/lib/api.sh +3 -3
- package/scripts/lib/common.sh +28 -3
- package/scripts/lib/schema.json +9 -0
- package/scripts/query_claude.sh +30 -9
- package/scripts/query_codex.sh +116 -18
- package/scripts/query_gemini.sh +32 -7
- package/scripts/query_grok.sh +161 -46
- package/scripts/query_kimi.sh +46 -0
- package/scripts/update_clis.sh +7 -1
package/scripts/query_grok.sh
CHANGED
|
@@ -36,6 +36,9 @@ START_TIME=$(get_timestamp_ms)
|
|
|
36
36
|
TEMP_OUTPUT=$(mktemp)
|
|
37
37
|
GROK_RUNTIME_DIR=""
|
|
38
38
|
TRANSPORT="cli"
|
|
39
|
+
GROK_CLI_VERSION=""
|
|
40
|
+
GROK_CLI_COMPATIBILITY=""
|
|
41
|
+
GROK_SUPPORTS_NO_AUTO_UPDATE=false
|
|
39
42
|
exit_code=1
|
|
40
43
|
|
|
41
44
|
cleanup() {
|
|
@@ -67,6 +70,93 @@ run_grok_api() {
|
|
|
67
70
|
fi
|
|
68
71
|
}
|
|
69
72
|
|
|
73
|
+
observe_grok_cli_version() {
|
|
74
|
+
local version
|
|
75
|
+
version=$("$GROK_CMD" --version 2>/dev/null | head -1 || true)
|
|
76
|
+
if [[ "$version" =~ ^grok[[:space:]]+([^[:space:]]+) ]]; then
|
|
77
|
+
printf '%s\n' "${BASH_REMATCH[1]}"
|
|
78
|
+
elif [[ -n "$version" ]]; then
|
|
79
|
+
printf '%s\n' "$version"
|
|
80
|
+
else
|
|
81
|
+
printf 'unknown\n'
|
|
82
|
+
fi
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
grok_cli_supports_required_interface() {
|
|
86
|
+
local probe_home="$1"
|
|
87
|
+
local probe_grok_home="$2"
|
|
88
|
+
local probe_workspace="$3"
|
|
89
|
+
local help flag
|
|
90
|
+
|
|
91
|
+
help=$(env HOME="$probe_home" GROK_HOME="$probe_grok_home" \
|
|
92
|
+
"$GROK_CMD" --help 2>&1 || true)
|
|
93
|
+
for flag in \
|
|
94
|
+
--prompt-file --model --cwd --output-format --no-plan --no-subagents \
|
|
95
|
+
--no-memory --disable-web-search --max-turns --permission-mode \
|
|
96
|
+
--sandbox --tools --deny --verbatim; do
|
|
97
|
+
grep -q -- "$flag" <<< "$help" || return 1
|
|
98
|
+
done
|
|
99
|
+
grep -Eq '^[[:space:]]+models([[:space:]]|$)' <<< "$help" || return 1
|
|
100
|
+
|
|
101
|
+
# Exercise the complete headless argument surface under --help. This checks
|
|
102
|
+
# parser compatibility without starting a session or sending a prompt.
|
|
103
|
+
env HOME="$probe_home" GROK_HOME="$probe_grok_home" \
|
|
104
|
+
"$GROK_CMD" \
|
|
105
|
+
--prompt-file /dev/null \
|
|
106
|
+
-m "$GROK_MODEL" \
|
|
107
|
+
--cwd "$probe_workspace" \
|
|
108
|
+
--output-format plain \
|
|
109
|
+
--no-plan \
|
|
110
|
+
--no-subagents \
|
|
111
|
+
--no-memory \
|
|
112
|
+
--disable-web-search \
|
|
113
|
+
--max-turns 1 \
|
|
114
|
+
--permission-mode dontAsk \
|
|
115
|
+
--sandbox strict \
|
|
116
|
+
--tools "" \
|
|
117
|
+
--deny Bash \
|
|
118
|
+
--deny Edit \
|
|
119
|
+
--deny Read \
|
|
120
|
+
--deny Grep \
|
|
121
|
+
--deny MCPTool \
|
|
122
|
+
--deny WebFetch \
|
|
123
|
+
--deny WebSearch \
|
|
124
|
+
--verbatim \
|
|
125
|
+
--help >/dev/null 2>&1 || return 1
|
|
126
|
+
|
|
127
|
+
if grep -q -- '--no-auto-update' <<< "$help"; then
|
|
128
|
+
GROK_SUPPORTS_NO_AUTO_UPDATE=true
|
|
129
|
+
else
|
|
130
|
+
GROK_SUPPORTS_NO_AUTO_UPDATE=false
|
|
131
|
+
fi
|
|
132
|
+
GROK_CLI_COMPATIBILITY="capability-probed"
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
grok_cli_exposes_requested_model() {
|
|
136
|
+
local isolated_home="$1"
|
|
137
|
+
local isolated_grok_home="$2"
|
|
138
|
+
local models
|
|
139
|
+
|
|
140
|
+
if ! models=$(env HOME="$isolated_home" GROK_HOME="$isolated_grok_home" \
|
|
141
|
+
"$GROK_CMD" models 2>&1); then
|
|
142
|
+
printf '%s\n' "$models"
|
|
143
|
+
return 1
|
|
144
|
+
fi
|
|
145
|
+
grep -Fq "You are logged in with grok.com." <<< "$models" || {
|
|
146
|
+
printf '%s\n' "$models"
|
|
147
|
+
return 1
|
|
148
|
+
}
|
|
149
|
+
awk -v requested="$GROK_MODEL" '
|
|
150
|
+
{
|
|
151
|
+
line = $0
|
|
152
|
+
sub(/^[[:space:]*]+/, "", line)
|
|
153
|
+
split(line, fields, /[[:space:]]+/)
|
|
154
|
+
if (fields[1] == requested) found = 1
|
|
155
|
+
}
|
|
156
|
+
END { exit(found ? 0 : 1) }
|
|
157
|
+
' <<< "$models"
|
|
158
|
+
}
|
|
159
|
+
|
|
70
160
|
grok_cli_is_unavailable() {
|
|
71
161
|
local cli_exit_code="$1"
|
|
72
162
|
local error_file="$2"
|
|
@@ -85,7 +175,7 @@ grok_cli_is_unavailable() {
|
|
|
85
175
|
# model errors, timeouts, empty output, or other post-launch failures here;
|
|
86
176
|
# those must surface instead of silently creating a billable API request.
|
|
87
177
|
grep -Eiq \
|
|
88
|
-
'not authenticated|authentication( is)? required|authentication failed|unauthorized|run .?grok login|please .*log ?in|no (valid )?(credentials|access token)|missing .*credential|token.*expired|(^|[^0-9])401([^0-9]|$)|permission denied|cannot execute|exec format error|no such file or directory|failed to (start|launch|spawn)|could not (start|launch|spawn)' \
|
|
178
|
+
'not authenticated|authentication( is)? required|authentication failed|unauthorized|run .?grok login|please .*log ?in|no (valid )?(credentials|access token)|missing .*credential|token.*expired|(^|[^0-9])401([^0-9]|$)|permission denied|cannot execute|exec format error|no such file or directory|failed to (start|launch|spawn)|could not (start|launch|spawn)|lacks the required capabilities|does not expose the requested model' \
|
|
89
179
|
"$error_file"
|
|
90
180
|
}
|
|
91
181
|
|
|
@@ -128,51 +218,66 @@ else
|
|
|
128
218
|
fi
|
|
129
219
|
fi
|
|
130
220
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
--no-plan
|
|
145
|
-
--no-subagents
|
|
146
|
-
--no-memory
|
|
147
|
-
--disable-web-search
|
|
148
|
-
--max-turns 1
|
|
149
|
-
--permission-mode dontAsk
|
|
150
|
-
--sandbox strict
|
|
151
|
-
--tools ""
|
|
152
|
-
--deny Bash
|
|
153
|
-
--deny Edit
|
|
154
|
-
--deny Read
|
|
155
|
-
--deny Grep
|
|
156
|
-
--deny MCPTool
|
|
157
|
-
--deny WebFetch
|
|
158
|
-
--deny WebSearch
|
|
159
|
-
--verbatim
|
|
160
|
-
)
|
|
161
|
-
|
|
162
|
-
# Newer Grok Build releases document --no-auto-update for automation;
|
|
163
|
-
# keep compatibility with older installed builds that do not expose it.
|
|
164
|
-
if "$GROK_CMD" --help 2>&1 | grep -q -- '--no-auto-update'; then
|
|
165
|
-
GROK_ARGS+=("--no-auto-update")
|
|
166
|
-
fi
|
|
167
|
-
|
|
168
|
-
if run_query \
|
|
169
|
-
"$CONSULTANT_NAME" \
|
|
170
|
-
"$TEMP_OUTPUT" \
|
|
171
|
-
"$GROK_TIMEOUT_SECONDS" \
|
|
172
|
-
"${GROK_ARGS[@]}" </dev/null; then
|
|
173
|
-
exit_code=0
|
|
221
|
+
GROK_CLI_VERSION=$(observe_grok_cli_version)
|
|
222
|
+
if ! grok_cli_supports_required_interface \
|
|
223
|
+
"$isolated_home" "$isolated_grok_home" "$isolated_workspace"; then
|
|
224
|
+
GROK_CLI_COMPATIBILITY="incompatible"
|
|
225
|
+
printf 'Grok Build CLI lacks the required capabilities\n' > "${TEMP_OUTPUT}.err"
|
|
226
|
+
log_warn "[$CONSULTANT_NAME] Grok Build CLI is capability-incompatible (reported version: $GROK_CLI_VERSION)"
|
|
227
|
+
exit_code=69
|
|
228
|
+
elif ! grok_cli_exposes_requested_model \
|
|
229
|
+
"$isolated_home" "$isolated_grok_home" > "${TEMP_OUTPUT}.err"; then
|
|
230
|
+
printf 'Grok Build CLI does not expose the requested model %s\n' \
|
|
231
|
+
"$GROK_MODEL" >> "${TEMP_OUTPUT}.err"
|
|
232
|
+
log_warn "[$CONSULTANT_NAME] Grok Build CLI does not expose $GROK_MODEL"
|
|
233
|
+
exit_code=69
|
|
174
234
|
else
|
|
175
|
-
|
|
235
|
+
# Official Grok Build headless contract:
|
|
236
|
+
# --prompt-file avoids argv size/process-list exposure, -m pins the
|
|
237
|
+
# model, and plain output contains the final assistant text.
|
|
238
|
+
# dontAsk + strict sandbox make every unapproved tool fail closed.
|
|
239
|
+
GROK_ARGS=(
|
|
240
|
+
env
|
|
241
|
+
HOME="$isolated_home"
|
|
242
|
+
GROK_HOME="$isolated_grok_home"
|
|
243
|
+
"$GROK_CMD"
|
|
244
|
+
--prompt-file "$prompt_file"
|
|
245
|
+
-m "$GROK_MODEL"
|
|
246
|
+
--cwd "$isolated_workspace"
|
|
247
|
+
--output-format plain
|
|
248
|
+
--no-plan
|
|
249
|
+
--no-subagents
|
|
250
|
+
--no-memory
|
|
251
|
+
--disable-web-search
|
|
252
|
+
--max-turns 1
|
|
253
|
+
--permission-mode dontAsk
|
|
254
|
+
--sandbox strict
|
|
255
|
+
--tools ""
|
|
256
|
+
--deny Bash
|
|
257
|
+
--deny Edit
|
|
258
|
+
--deny Read
|
|
259
|
+
--deny Grep
|
|
260
|
+
--deny MCPTool
|
|
261
|
+
--deny WebFetch
|
|
262
|
+
--deny WebSearch
|
|
263
|
+
--verbatim
|
|
264
|
+
)
|
|
265
|
+
|
|
266
|
+
# --no-auto-update is a useful optional capability, not a version
|
|
267
|
+
# requirement. Compatible older or vendor-custom builds may omit it.
|
|
268
|
+
if [[ "$GROK_SUPPORTS_NO_AUTO_UPDATE" == "true" ]]; then
|
|
269
|
+
GROK_ARGS+=("--no-auto-update")
|
|
270
|
+
fi
|
|
271
|
+
|
|
272
|
+
if run_query \
|
|
273
|
+
"$CONSULTANT_NAME" \
|
|
274
|
+
"$TEMP_OUTPUT" \
|
|
275
|
+
"$GROK_TIMEOUT_SECONDS" \
|
|
276
|
+
"${GROK_ARGS[@]}" </dev/null; then
|
|
277
|
+
exit_code=0
|
|
278
|
+
else
|
|
279
|
+
exit_code=$?
|
|
280
|
+
fi
|
|
176
281
|
fi
|
|
177
282
|
else
|
|
178
283
|
log_warn "[$CONSULTANT_NAME] Grok Build CLI not found: $GROK_CMD"
|
|
@@ -214,7 +319,17 @@ fi
|
|
|
214
319
|
# Preserve which route actually answered without changing the shared schema.
|
|
215
320
|
if [[ -s "$OUTPUT_FILE" ]]; then
|
|
216
321
|
response_tmp=$(mktemp)
|
|
217
|
-
if jq --arg transport "$TRANSPORT"
|
|
322
|
+
if jq --arg transport "$TRANSPORT" \
|
|
323
|
+
--arg cli_version "$GROK_CLI_VERSION" \
|
|
324
|
+
--arg cli_compatibility "$GROK_CLI_COMPATIBILITY" '
|
|
325
|
+
.metadata.transport = $transport |
|
|
326
|
+
if $transport == "cli" and $cli_version != "" then
|
|
327
|
+
.metadata.cli_version = $cli_version |
|
|
328
|
+
.metadata.cli_compatibility = $cli_compatibility
|
|
329
|
+
else
|
|
330
|
+
.
|
|
331
|
+
end
|
|
332
|
+
' \
|
|
218
333
|
"$OUTPUT_FILE" > "$response_tmp"; then
|
|
219
334
|
mv "$response_tmp" "$OUTPUT_FILE"
|
|
220
335
|
else
|
package/scripts/query_kimi.sh
CHANGED
|
@@ -40,9 +40,43 @@ START_TIME=$(get_timestamp_ms)
|
|
|
40
40
|
|
|
41
41
|
# --- Execution ---
|
|
42
42
|
TEMP_OUTPUT=$(mktemp)
|
|
43
|
+
KIMI_CLI_VERSION=""
|
|
44
|
+
|
|
45
|
+
observe_kimi_cli_version() {
|
|
46
|
+
local version
|
|
47
|
+
version=$("$KIMI_CMD" --version 2>/dev/null | head -1 || true)
|
|
48
|
+
printf '%s\n' "${version:-unknown}"
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
kimi_cli_supports_required_interface() {
|
|
52
|
+
local help providers flag
|
|
53
|
+
|
|
54
|
+
help=$("$KIMI_CMD" --help 2>&1 || true)
|
|
55
|
+
for flag in --model --prompt --output-format; do
|
|
56
|
+
grep -q -- "$flag" <<< "$help" || return 1
|
|
57
|
+
done
|
|
58
|
+
grep -Eq '^[[:space:]]+provider([[:space:]]|$)' <<< "$help" || return 1
|
|
59
|
+
|
|
60
|
+
# Check the complete prompt-mode parser without running a model request.
|
|
61
|
+
"$KIMI_CMD" \
|
|
62
|
+
--model "$KIMI_MODEL" \
|
|
63
|
+
--prompt "" \
|
|
64
|
+
--output-format stream-json \
|
|
65
|
+
--help >/dev/null 2>&1 || return 1
|
|
66
|
+
|
|
67
|
+
providers=$("$KIMI_CMD" provider list --json 2>/dev/null || true)
|
|
68
|
+
jq -e --arg model "$KIMI_MODEL" '
|
|
69
|
+
.models[$model] != null
|
|
70
|
+
' <<< "$providers" >/dev/null 2>&1
|
|
71
|
+
}
|
|
43
72
|
|
|
44
73
|
# Check CLI prerequisite
|
|
45
74
|
check_command "$KIMI_CMD" "Kimi CLI" "curl -L code.kimi.com/install.sh | bash" || exit 1
|
|
75
|
+
KIMI_CLI_VERSION=$(observe_kimi_cli_version)
|
|
76
|
+
kimi_cli_supports_required_interface || {
|
|
77
|
+
log_error "[Kimi] Kimi CLI lacks the required capabilities for model $KIMI_MODEL (reported version: $KIMI_CLI_VERSION)"
|
|
78
|
+
exit 1
|
|
79
|
+
}
|
|
46
80
|
|
|
47
81
|
# Kimi takes the prompt as the -p argument (it does NOT read stdin). The old
|
|
48
82
|
# `--quiet --input-format text` were NOT real flags on kimi 0.23.6 — commander
|
|
@@ -89,5 +123,17 @@ PERSONA_NAME=$(get_persona_name "$CONSULTANT_NAME")
|
|
|
89
123
|
process_consultant_response "$CONSULTANT_NAME" "$MODEL_USED" "$PERSONA_NAME" \
|
|
90
124
|
"$TEMP_OUTPUT" "$OUTPUT_FILE" "$exit_code" "$LATENCY_MS" "" "$FULL_QUERY"
|
|
91
125
|
|
|
126
|
+
if [[ -s "$OUTPUT_FILE" ]]; then
|
|
127
|
+
response_tmp=$(mktemp)
|
|
128
|
+
if jq --arg cli_version "$KIMI_CLI_VERSION" '
|
|
129
|
+
.metadata.cli_version = $cli_version |
|
|
130
|
+
.metadata.cli_compatibility = "capability-probed"
|
|
131
|
+
' "$OUTPUT_FILE" > "$response_tmp"; then
|
|
132
|
+
mv "$response_tmp" "$OUTPUT_FILE"
|
|
133
|
+
else
|
|
134
|
+
rm -f "$response_tmp"
|
|
135
|
+
fi
|
|
136
|
+
fi
|
|
137
|
+
|
|
92
138
|
cat "$OUTPUT_FILE"
|
|
93
139
|
exit $exit_code
|
package/scripts/update_clis.sh
CHANGED
|
@@ -200,7 +200,13 @@ main() {
|
|
|
200
200
|
continue
|
|
201
201
|
fi
|
|
202
202
|
|
|
203
|
-
|
|
203
|
+
# agy under SSH must not see SSH_* markers (Keychain credential store).
|
|
204
|
+
# AGY_ENV_PREFIX is exec-safe under GNU timeout (see lib/common.sh).
|
|
205
|
+
if [[ "$default_bin" == "agy" ]]; then
|
|
206
|
+
ver="$(run_with_timeout 8 "${AGY_ENV_PREFIX[@]}" "$cmd" --version </dev/null 2>/dev/null | head -1 || true)"
|
|
207
|
+
else
|
|
208
|
+
ver="$(run_with_timeout 8 "$cmd" --version </dev/null 2>/dev/null | head -1 || true)"
|
|
209
|
+
fi
|
|
204
210
|
detect_method "$default_bin" "$cmd"
|
|
205
211
|
log_info "$display ($cmd): installed [${ver:-version n/a}] -- install method: $DETECT_METHOD"
|
|
206
212
|
|