@enterpriseai/cli 3.15.9 → 3.15.11
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/README.md +45 -11
- package/dist/commands/classifier.d.ts.map +1 -1
- package/dist/commands/classifier.js +4 -1
- package/dist/commands/classifier.js.map +1 -1
- package/dist/commands/docs.d.ts.map +1 -1
- package/dist/commands/docs.js +88 -31
- package/dist/commands/docs.js.map +1 -1
- package/dist/commands/init.d.ts +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +15 -10
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/start.d.ts +15 -0
- package/dist/commands/start.d.ts.map +1 -1
- package/dist/commands/start.js +111 -29
- package/dist/commands/start.js.map +1 -1
- package/dist/lib/agent-guide.js +2 -2
- package/dist/lib/agent-guide.js.map +1 -1
- package/dist/lib/ai-surface-installer.d.ts +38 -0
- package/dist/lib/ai-surface-installer.d.ts.map +1 -0
- package/dist/lib/ai-surface-installer.js +160 -0
- package/dist/lib/ai-surface-installer.js.map +1 -0
- package/dist/lib/ai-surfaces.d.ts +257 -6
- package/dist/lib/ai-surfaces.d.ts.map +1 -1
- package/dist/lib/ai-surfaces.js +3182 -170
- package/dist/lib/ai-surfaces.js.map +1 -1
- package/dist/lib/api.d.ts +16 -2
- package/dist/lib/api.d.ts.map +1 -1
- package/dist/lib/api.js +43 -8
- package/dist/lib/api.js.map +1 -1
- package/dist/lib/gofer-installer.js +1 -1
- package/package.json +2 -2
- package/resources/gofer/.gofer-version +17 -1
- package/resources/gofer/bash-scripts/install-optional-tools.sh +357 -16
- package/resources/gofer/bash-scripts/sync-implementation-status.sh +3 -4
- package/resources/gofer/powershell-scripts/install-optional-tools.ps1 +419 -11
- package/resources/gofer/references/platform/eai-service-patterns.md +84 -1
- package/resources/gofer/templates/visuals/capability-heatmap-template.md +2 -2
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
2
|
|
|
3
|
-
set -
|
|
3
|
+
set -uo pipefail
|
|
4
4
|
|
|
5
5
|
WORKSPACE_PATH=""
|
|
6
6
|
TOOLS_CSV=""
|
|
@@ -8,16 +8,24 @@ TOOLS_CSV=""
|
|
|
8
8
|
while [[ $# -gt 0 ]]; do
|
|
9
9
|
case "$1" in
|
|
10
10
|
--workspace-path)
|
|
11
|
-
|
|
11
|
+
if [[ $# -lt 2 || "$2" == --* ]]; then
|
|
12
|
+
echo "Missing value for --workspace-path." >&2
|
|
13
|
+
exit 64
|
|
14
|
+
fi
|
|
15
|
+
WORKSPACE_PATH="$2"
|
|
12
16
|
shift 2
|
|
13
17
|
;;
|
|
14
18
|
--tools)
|
|
15
|
-
|
|
19
|
+
if [[ $# -lt 2 || "$2" == --* ]]; then
|
|
20
|
+
echo "Missing value for --tools." >&2
|
|
21
|
+
exit 64
|
|
22
|
+
fi
|
|
23
|
+
TOOLS_CSV="$2"
|
|
16
24
|
shift 2
|
|
17
25
|
;;
|
|
18
26
|
*)
|
|
19
|
-
echo "Unknown argument
|
|
20
|
-
|
|
27
|
+
echo "Unknown argument. Expected --workspace-path or --tools." >&2
|
|
28
|
+
exit 64
|
|
21
29
|
;;
|
|
22
30
|
esac
|
|
23
31
|
done
|
|
@@ -36,6 +44,43 @@ IFS=',' read -r -a TOOLS <<< "$TOOLS_CSV"
|
|
|
36
44
|
REPO_ROOT="$WORKSPACE_PATH"
|
|
37
45
|
|
|
38
46
|
HAS_FAILURE=0
|
|
47
|
+
TEMP_INSTALLERS=()
|
|
48
|
+
ACTIVE_INSTALLER_PID=""
|
|
49
|
+
INSTALLER_TIMEOUT_SECONDS=900
|
|
50
|
+
|
|
51
|
+
terminate_process_tree() {
|
|
52
|
+
local target_pid="$1"
|
|
53
|
+
local signal_name="$2"
|
|
54
|
+
local child_pid
|
|
55
|
+
|
|
56
|
+
[[ "$target_pid" =~ ^[1-9][0-9]*$ ]] || return 0
|
|
57
|
+
if [[ -x /usr/bin/pgrep ]]; then
|
|
58
|
+
while IFS= read -r child_pid; do
|
|
59
|
+
if [[ "$child_pid" =~ ^[1-9][0-9]*$ ]]; then
|
|
60
|
+
terminate_process_tree "$child_pid" "$signal_name"
|
|
61
|
+
fi
|
|
62
|
+
done < <(/usr/bin/pgrep -P "$target_pid" 2>/dev/null || true)
|
|
63
|
+
fi
|
|
64
|
+
kill "-$signal_name" "$target_pid" 2>/dev/null || true
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
cleanup_temp_installers() {
|
|
68
|
+
local installer_path
|
|
69
|
+
if [[ -n "$ACTIVE_INSTALLER_PID" ]]; then
|
|
70
|
+
terminate_process_tree "$ACTIVE_INSTALLER_PID" TERM
|
|
71
|
+
terminate_process_tree "$ACTIVE_INSTALLER_PID" KILL
|
|
72
|
+
fi
|
|
73
|
+
for installer_path in "${TEMP_INSTALLERS[@]-}"; do
|
|
74
|
+
if [[ -n "$installer_path" ]]; then
|
|
75
|
+
rm -f -- "$installer_path"
|
|
76
|
+
fi
|
|
77
|
+
done
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
trap cleanup_temp_installers EXIT
|
|
81
|
+
trap 'exit 129' HUP
|
|
82
|
+
trap 'exit 130' INT
|
|
83
|
+
trap 'exit 143' TERM
|
|
39
84
|
|
|
40
85
|
log_info() {
|
|
41
86
|
printf '[gofer] %s\n' "$1"
|
|
@@ -139,6 +184,238 @@ install_with_npm_global() {
|
|
|
139
184
|
run_command "Installing $package_name globally with npm" npm install --global "$package_name"
|
|
140
185
|
}
|
|
141
186
|
|
|
187
|
+
validate_installed_cli() {
|
|
188
|
+
local tool_name="$1"
|
|
189
|
+
local command_path="$2"
|
|
190
|
+
if [[ ! -f "$command_path" || ! -x "$command_path" ]]; then
|
|
191
|
+
HAS_FAILURE=1
|
|
192
|
+
log_error "$tool_name installation did not produce its expected executable"
|
|
193
|
+
return 1
|
|
194
|
+
fi
|
|
195
|
+
log_info "$tool_name installer produced its provider-defined executable"
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
install_pinned_copilot_cli() {
|
|
199
|
+
local package_spec='@github/copilot@1.0.83'
|
|
200
|
+
local expected_integrity='sha512-M8uZI0V0dahYV1KZij3nGDxaXEGG7I7YUZzQPI7NEZkL/83Nl/tNTbPdxKtdWZbOmWoXsPKXty/eEYoj6RHDhA=='
|
|
201
|
+
local registry='https://registry.npmjs.org/'
|
|
202
|
+
local npm_path
|
|
203
|
+
npm_path="$(type -P npm 2>/dev/null || true)"
|
|
204
|
+
if [[ -z "$npm_path" || ! -f "$npm_path" || ! -x "$npm_path" ]]; then
|
|
205
|
+
HAS_FAILURE=1
|
|
206
|
+
log_warn "npm is required to install $package_spec globally"
|
|
207
|
+
return 1
|
|
208
|
+
fi
|
|
209
|
+
|
|
210
|
+
log_info "Verifying the pinned GitHub Copilot CLI package"
|
|
211
|
+
local actual_integrity
|
|
212
|
+
if ! actual_integrity="$("$npm_path" view "$package_spec" dist.integrity --json --registry="$registry" 2>/dev/null)"; then
|
|
213
|
+
HAS_FAILURE=1
|
|
214
|
+
log_error "Could not resolve the pinned GitHub Copilot CLI package"
|
|
215
|
+
return 1
|
|
216
|
+
fi
|
|
217
|
+
actual_integrity="${actual_integrity#\"}"
|
|
218
|
+
actual_integrity="${actual_integrity%\"}"
|
|
219
|
+
if [[ "$actual_integrity" != "$expected_integrity" ]]; then
|
|
220
|
+
HAS_FAILURE=1
|
|
221
|
+
log_error "Refusing GitHub Copilot CLI because its npm integrity changed"
|
|
222
|
+
return 1
|
|
223
|
+
fi
|
|
224
|
+
|
|
225
|
+
log_info "Installing the pinned GitHub Copilot CLI"
|
|
226
|
+
if ! "$npm_path" install --global "$package_spec" --registry="$registry" \
|
|
227
|
+
--ignore-scripts --no-audit --no-fund >/dev/null 2>&1; then
|
|
228
|
+
HAS_FAILURE=1
|
|
229
|
+
log_error "Failed: Installing the pinned GitHub Copilot CLI"
|
|
230
|
+
return 1
|
|
231
|
+
fi
|
|
232
|
+
if ! "$npm_path" list --global --depth=0 "$package_spec" >/dev/null 2>&1; then
|
|
233
|
+
HAS_FAILURE=1
|
|
234
|
+
log_error "The installed GitHub Copilot CLI package did not match the pinned version"
|
|
235
|
+
return 1
|
|
236
|
+
fi
|
|
237
|
+
|
|
238
|
+
local npm_prefix
|
|
239
|
+
npm_prefix="$("$npm_path" prefix --global 2>/dev/null || true)"
|
|
240
|
+
case "$npm_prefix" in
|
|
241
|
+
/*) ;;
|
|
242
|
+
*)
|
|
243
|
+
HAS_FAILURE=1
|
|
244
|
+
log_error "Could not resolve an absolute npm prefix for GitHub Copilot CLI"
|
|
245
|
+
return 1
|
|
246
|
+
;;
|
|
247
|
+
esac
|
|
248
|
+
validate_installed_cli "GitHub Copilot CLI" "$npm_prefix/bin/copilot"
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
compute_sha256() {
|
|
252
|
+
local target_path="$1"
|
|
253
|
+
|
|
254
|
+
if [[ -x /usr/bin/shasum ]]; then
|
|
255
|
+
/usr/bin/shasum -a 256 "$target_path" | /usr/bin/awk '{print $1}'
|
|
256
|
+
return
|
|
257
|
+
fi
|
|
258
|
+
|
|
259
|
+
if [[ -x /usr/bin/sha256sum ]]; then
|
|
260
|
+
/usr/bin/sha256sum "$target_path" | /usr/bin/awk '{print $1}'
|
|
261
|
+
return
|
|
262
|
+
fi
|
|
263
|
+
|
|
264
|
+
if [[ -x /usr/bin/openssl ]]; then
|
|
265
|
+
/usr/bin/openssl dgst -sha256 "$target_path" | /usr/bin/awk '{print $NF}'
|
|
266
|
+
return
|
|
267
|
+
fi
|
|
268
|
+
|
|
269
|
+
return 1
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
run_sanitized_installer() {
|
|
273
|
+
local shell_name="$1"
|
|
274
|
+
local installer_fd_path="$2"
|
|
275
|
+
local shell_path
|
|
276
|
+
case "$shell_name" in
|
|
277
|
+
bash) shell_path=/bin/bash ;;
|
|
278
|
+
sh) shell_path=/bin/sh ;;
|
|
279
|
+
*)
|
|
280
|
+
log_error "Refusing an unsupported installer interpreter"
|
|
281
|
+
return 1
|
|
282
|
+
;;
|
|
283
|
+
esac
|
|
284
|
+
[[ -x "$shell_path" ]] || {
|
|
285
|
+
log_error "The required installer interpreter is unavailable"
|
|
286
|
+
return 1
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/usr/bin/env -i \
|
|
290
|
+
HOME="${HOME:-}" \
|
|
291
|
+
USER="${USER:-}" \
|
|
292
|
+
LOGNAME="${LOGNAME:-}" \
|
|
293
|
+
SHELL="${SHELL:-/bin/sh}" \
|
|
294
|
+
PATH="/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/opt/homebrew/bin" \
|
|
295
|
+
TMPDIR="${TMPDIR:-/tmp}" \
|
|
296
|
+
LANG="${LANG:-C}" \
|
|
297
|
+
LC_ALL="${LC_ALL:-}" \
|
|
298
|
+
XDG_CONFIG_HOME="${XDG_CONFIG_HOME:-}" \
|
|
299
|
+
XDG_DATA_HOME="${XDG_DATA_HOME:-}" \
|
|
300
|
+
XDG_CACHE_HOME="${XDG_CACHE_HOME:-}" \
|
|
301
|
+
CODEX_NON_INTERACTIVE=1 \
|
|
302
|
+
"$shell_path" "$installer_fd_path" &
|
|
303
|
+
ACTIVE_INSTALLER_PID=$!
|
|
304
|
+
|
|
305
|
+
local deadline=$((SECONDS + INSTALLER_TIMEOUT_SECONDS))
|
|
306
|
+
while kill -0 "$ACTIVE_INSTALLER_PID" 2>/dev/null; do
|
|
307
|
+
if (( SECONDS >= deadline )); then
|
|
308
|
+
terminate_process_tree "$ACTIVE_INSTALLER_PID" TERM
|
|
309
|
+
/bin/sleep 2
|
|
310
|
+
terminate_process_tree "$ACTIVE_INSTALLER_PID" KILL
|
|
311
|
+
wait "$ACTIVE_INSTALLER_PID" 2>/dev/null || true
|
|
312
|
+
ACTIVE_INSTALLER_PID=""
|
|
313
|
+
log_error "The provider installer exceeded its bounded execution time"
|
|
314
|
+
return 124
|
|
315
|
+
fi
|
|
316
|
+
/bin/sleep 1
|
|
317
|
+
done
|
|
318
|
+
|
|
319
|
+
local installer_status=0
|
|
320
|
+
wait "$ACTIVE_INSTALLER_PID" || installer_status=$?
|
|
321
|
+
ACTIVE_INSTALLER_PID=""
|
|
322
|
+
return "$installer_status"
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
install_from_official_script() {
|
|
326
|
+
local tool_name="$1"
|
|
327
|
+
local script_url="$2"
|
|
328
|
+
local shell_name="$3"
|
|
329
|
+
local expected_sha256="$4"
|
|
330
|
+
local allowed_final_origin="$5"
|
|
331
|
+
|
|
332
|
+
if [[ ! -x /usr/bin/curl ]]; then
|
|
333
|
+
HAS_FAILURE=1
|
|
334
|
+
log_warn "curl is required to install $tool_name from its official provider"
|
|
335
|
+
return 1
|
|
336
|
+
fi
|
|
337
|
+
|
|
338
|
+
local installer_path
|
|
339
|
+
installer_path="$(/usr/bin/mktemp "${TMPDIR:-/tmp}/gofer-installer.XXXXXX" 2>/dev/null)" || {
|
|
340
|
+
HAS_FAILURE=1
|
|
341
|
+
log_error "Could not create a temporary installer for $tool_name"
|
|
342
|
+
return 1
|
|
343
|
+
}
|
|
344
|
+
TEMP_INSTALLERS+=("$installer_path")
|
|
345
|
+
|
|
346
|
+
log_info "Installing or updating $tool_name from $script_url"
|
|
347
|
+
local effective_url
|
|
348
|
+
if ! effective_url="$(/usr/bin/curl --fail --silent --show-error --location \
|
|
349
|
+
--proto '=https' --proto-redir '=https' --tlsv1.2 \
|
|
350
|
+
--max-redirs 5 --connect-timeout 15 --max-time 120 --max-filesize 1048576 \
|
|
351
|
+
--output "$installer_path" --write-out '%{url_effective}' "$script_url" 2>/dev/null)"; then
|
|
352
|
+
HAS_FAILURE=1
|
|
353
|
+
log_error "Failed to download the official $tool_name installer"
|
|
354
|
+
rm -f -- "$installer_path"
|
|
355
|
+
return 1
|
|
356
|
+
fi
|
|
357
|
+
|
|
358
|
+
case "$effective_url" in
|
|
359
|
+
"$allowed_final_origin"|"$allowed_final_origin"/*)
|
|
360
|
+
;;
|
|
361
|
+
*)
|
|
362
|
+
HAS_FAILURE=1
|
|
363
|
+
log_error "Refusing $tool_name installer from an unexpected redirect origin"
|
|
364
|
+
rm -f -- "$installer_path"
|
|
365
|
+
return 1
|
|
366
|
+
;;
|
|
367
|
+
esac
|
|
368
|
+
|
|
369
|
+
if [[ ! -s "$installer_path" ]]; then
|
|
370
|
+
HAS_FAILURE=1
|
|
371
|
+
log_error "Refusing an empty $tool_name installer"
|
|
372
|
+
rm -f -- "$installer_path"
|
|
373
|
+
return 1
|
|
374
|
+
fi
|
|
375
|
+
|
|
376
|
+
# Open two independent descriptors, then unlink the pathname. The hash and
|
|
377
|
+
# interpreter now consume the same unreachable inode without a path-based
|
|
378
|
+
# replacement window between verification and execution.
|
|
379
|
+
if ! exec 8<"$installer_path" || ! exec 9<"$installer_path"; then
|
|
380
|
+
HAS_FAILURE=1
|
|
381
|
+
log_error "Could not secure the downloaded $tool_name installer"
|
|
382
|
+
rm -f -- "$installer_path"
|
|
383
|
+
exec 8<&- 2>/dev/null || true
|
|
384
|
+
exec 9<&- 2>/dev/null || true
|
|
385
|
+
return 1
|
|
386
|
+
fi
|
|
387
|
+
rm -f -- "$installer_path"
|
|
388
|
+
|
|
389
|
+
local actual_sha256
|
|
390
|
+
if ! actual_sha256="$(compute_sha256 /dev/fd/8 2>/dev/null)"; then
|
|
391
|
+
HAS_FAILURE=1
|
|
392
|
+
log_error "No supported SHA-256 tool is available to verify $tool_name"
|
|
393
|
+
exec 8<&-
|
|
394
|
+
exec 9<&-
|
|
395
|
+
return 1
|
|
396
|
+
fi
|
|
397
|
+
exec 8<&-
|
|
398
|
+
|
|
399
|
+
if [[ "$actual_sha256" != "$expected_sha256" ]]; then
|
|
400
|
+
HAS_FAILURE=1
|
|
401
|
+
log_error "Refusing $tool_name installer because its SHA-256 digest changed"
|
|
402
|
+
exec 9<&-
|
|
403
|
+
return 1
|
|
404
|
+
fi
|
|
405
|
+
|
|
406
|
+
# Provider output is intentionally not relayed: verified installers can still
|
|
407
|
+
# print local paths or inherited account data. Emit only bounded Gofer-owned
|
|
408
|
+
# status messages around the isolated child process.
|
|
409
|
+
if ! run_sanitized_installer "$shell_name" /dev/fd/9 >/dev/null 2>&1; then
|
|
410
|
+
HAS_FAILURE=1
|
|
411
|
+
log_error "Failed: Installing or updating $tool_name"
|
|
412
|
+
exec 9<&-
|
|
413
|
+
return 1
|
|
414
|
+
fi
|
|
415
|
+
exec 9<&-
|
|
416
|
+
return 0
|
|
417
|
+
}
|
|
418
|
+
|
|
142
419
|
install_gh_cli() {
|
|
143
420
|
if has_command gh; then
|
|
144
421
|
log_info "GitHub CLI is already installed"
|
|
@@ -191,20 +468,41 @@ install_azure_cli() {
|
|
|
191
468
|
fi
|
|
192
469
|
|
|
193
470
|
if has_command apt-get; then
|
|
194
|
-
|
|
471
|
+
if ! has_command apt-cache || ! apt-cache show azure-cli >/dev/null 2>&1; then
|
|
472
|
+
HAS_FAILURE=1
|
|
473
|
+
log_warn "Azure CLI is unavailable from the configured apt repositories"
|
|
474
|
+
log_warn "Configure Microsoft's signed Azure CLI apt repository, then rerun Gofer"
|
|
475
|
+
return 1
|
|
476
|
+
fi
|
|
477
|
+
run_command "Updating apt package index for Azure CLI" sudo apt-get update
|
|
478
|
+
run_command "Installing Azure CLI with apt-get" sudo apt-get install --yes azure-cli
|
|
195
479
|
return
|
|
196
480
|
fi
|
|
197
481
|
|
|
198
482
|
if has_command dnf; then
|
|
483
|
+
local rhel_release
|
|
484
|
+
rhel_release="$(rpm -E %rhel)"
|
|
485
|
+
if [[ ! "$rhel_release" =~ ^[0-9]+$ ]]; then
|
|
486
|
+
HAS_FAILURE=1
|
|
487
|
+
log_warn "Could not determine a safe RHEL release for the Azure CLI feed"
|
|
488
|
+
return
|
|
489
|
+
fi
|
|
199
490
|
run_command "Registering Microsoft package feed for Azure CLI" sudo rpm --import https://packages.microsoft.com/keys/microsoft.asc
|
|
200
|
-
run_command "Installing Microsoft package feed for Azure CLI"
|
|
491
|
+
run_command "Installing Microsoft package feed for Azure CLI" sudo dnf install --assumeyes "https://packages.microsoft.com/config/rhel/$rhel_release/packages-microsoft-prod.rpm"
|
|
201
492
|
run_command "Installing Azure CLI with dnf" sudo dnf install --assumeyes azure-cli
|
|
202
493
|
return
|
|
203
494
|
fi
|
|
204
495
|
|
|
205
496
|
if has_command yum; then
|
|
497
|
+
local rhel_release
|
|
498
|
+
rhel_release="$(rpm -E %rhel)"
|
|
499
|
+
if [[ ! "$rhel_release" =~ ^[0-9]+$ ]]; then
|
|
500
|
+
HAS_FAILURE=1
|
|
501
|
+
log_warn "Could not determine a safe RHEL release for the Azure CLI feed"
|
|
502
|
+
return
|
|
503
|
+
fi
|
|
206
504
|
run_command "Registering Microsoft package feed for Azure CLI" sudo rpm --import https://packages.microsoft.com/keys/microsoft.asc
|
|
207
|
-
run_command "Installing Microsoft package feed for Azure CLI"
|
|
505
|
+
run_command "Installing Microsoft package feed for Azure CLI" sudo yum install --assumeyes "https://packages.microsoft.com/config/rhel/$rhel_release/packages-microsoft-prod.rpm"
|
|
208
506
|
run_command "Installing Azure CLI with yum" sudo yum install --assumeyes azure-cli
|
|
209
507
|
return
|
|
210
508
|
fi
|
|
@@ -213,7 +511,30 @@ install_azure_cli() {
|
|
|
213
511
|
log_warn "No supported package manager found to install Azure CLI"
|
|
214
512
|
}
|
|
215
513
|
|
|
216
|
-
|
|
514
|
+
NORMALIZED_TOOLS=()
|
|
515
|
+
NORMALIZED_TOOLS_CSV=""
|
|
516
|
+
for raw_tool in "${TOOLS[@]}"; do
|
|
517
|
+
normalized_tool="${raw_tool#"${raw_tool%%[![:space:]]*}"}"
|
|
518
|
+
normalized_tool="${normalized_tool%"${normalized_tool##*[![:space:]]}"}"
|
|
519
|
+
case "$normalized_tool" in
|
|
520
|
+
agy|gemini) normalized_tool="antigravity" ;;
|
|
521
|
+
esac
|
|
522
|
+
case "$normalized_tool" in
|
|
523
|
+
"") continue ;;
|
|
524
|
+
*[!a-z0-9-]*) normalized_tool="invalid-tool-id" ;;
|
|
525
|
+
esac
|
|
526
|
+
case ",$NORMALIZED_TOOLS_CSV," in
|
|
527
|
+
*,"$normalized_tool",*) ;;
|
|
528
|
+
*)
|
|
529
|
+
NORMALIZED_TOOLS+=("$normalized_tool")
|
|
530
|
+
NORMALIZED_TOOLS_CSV="${NORMALIZED_TOOLS_CSV:+$NORMALIZED_TOOLS_CSV,}$normalized_tool"
|
|
531
|
+
;;
|
|
532
|
+
esac
|
|
533
|
+
done
|
|
534
|
+
TOOLS=("${NORMALIZED_TOOLS[@]}")
|
|
535
|
+
TOOLS_CSV="$NORMALIZED_TOOLS_CSV"
|
|
536
|
+
|
|
537
|
+
log_info "Workspace selected"
|
|
217
538
|
log_info "Selected tools: $TOOLS_CSV"
|
|
218
539
|
|
|
219
540
|
PACKAGE_MANAGER="$(detect_js_package_manager)"
|
|
@@ -228,16 +549,35 @@ for tool in "${TOOLS[@]}"; do
|
|
|
228
549
|
install_playwright_browsers
|
|
229
550
|
;;
|
|
230
551
|
claude)
|
|
231
|
-
|
|
552
|
+
if install_from_official_script "Claude Code" "https://claude.ai/install.sh" bash \
|
|
553
|
+
"3a68d3406cf674e17bed1733a4dcf37805e2e47d87417700007d7e1aa766a944" \
|
|
554
|
+
"https://downloads.claude.ai"; then
|
|
555
|
+
validate_installed_cli "Claude Code" "${HOME:?HOME is required}/.local/bin/claude"
|
|
556
|
+
fi
|
|
232
557
|
;;
|
|
233
558
|
codex)
|
|
234
|
-
|
|
559
|
+
if install_from_official_script "Codex CLI" "https://chatgpt.com/codex/install.sh" sh \
|
|
560
|
+
"ba92dd27e5c06f0d3bbc58bfa4b9cfb6599cd2742fbb1f92a2765e6c07dedb5a" \
|
|
561
|
+
"https://releases.openai.com"; then
|
|
562
|
+
validate_installed_cli "Codex CLI" "${HOME:?HOME is required}/.local/bin/codex"
|
|
563
|
+
fi
|
|
235
564
|
;;
|
|
236
565
|
copilot)
|
|
237
|
-
|
|
566
|
+
install_pinned_copilot_cli
|
|
567
|
+
;;
|
|
568
|
+
antigravity)
|
|
569
|
+
if install_from_official_script "Antigravity CLI (agy)" "https://antigravity.google/cli/install.sh" bash \
|
|
570
|
+
"ee1ea43ce4e9e56356c4ab6dad907ef357ae4bdfcaadb682735909fb57c9c640" \
|
|
571
|
+
"https://antigravity.google"; then
|
|
572
|
+
validate_installed_cli "Antigravity CLI" "${HOME:?HOME is required}/.local/bin/agy"
|
|
573
|
+
fi
|
|
238
574
|
;;
|
|
239
|
-
|
|
240
|
-
|
|
575
|
+
grok)
|
|
576
|
+
if install_from_official_script "Grok Build" "https://x.ai/cli/install.sh" bash \
|
|
577
|
+
"7fd6fdc75d9418b2e58356726fcbf1ae849416f773925da07d0ccc7a60d3e791" \
|
|
578
|
+
"https://x.ai"; then
|
|
579
|
+
validate_installed_cli "Grok Build" "${HOME:?HOME is required}/.grok/bin/grok"
|
|
580
|
+
fi
|
|
241
581
|
;;
|
|
242
582
|
gh)
|
|
243
583
|
install_gh_cli
|
|
@@ -255,10 +595,11 @@ for tool in "${TOOLS[@]}"; do
|
|
|
255
595
|
done
|
|
256
596
|
|
|
257
597
|
log_info "Suggested next steps:"
|
|
258
|
-
log_info " claude login"
|
|
598
|
+
log_info " claude auth login"
|
|
259
599
|
log_info " codex login"
|
|
260
600
|
log_info " copilot login"
|
|
261
|
-
log_info "
|
|
601
|
+
log_info " agy"
|
|
602
|
+
log_info " grok"
|
|
262
603
|
log_info " gh auth login"
|
|
263
604
|
log_info " az login"
|
|
264
605
|
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
|
-
#
|
|
2
|
+
# Report implementation status across feature branches
|
|
3
3
|
#
|
|
4
|
-
# This script
|
|
5
|
-
# and updates tasks.md to reflect the actual implementation state.
|
|
4
|
+
# This script reports related commits. It never changes tasks.md.
|
|
6
5
|
#
|
|
7
6
|
# Usage: sync-implementation-status.sh <feature-dir>
|
|
8
7
|
# Example: sync-implementation-status.sh .specify/specs/025-ai-usage-tracking
|
|
@@ -37,7 +36,7 @@ fi
|
|
|
37
36
|
# This requires reading tasks.md, extracting file paths from task descriptions,
|
|
38
37
|
# and checking if those files were modified in the commits
|
|
39
38
|
|
|
40
|
-
echo "✓
|
|
39
|
+
echo "✓ Report complete. No task state was changed."
|
|
41
40
|
echo ""
|
|
42
41
|
echo "MANUAL STEP REQUIRED:"
|
|
43
42
|
echo "1. Review git commits for this feature"
|