browser-automation-skill 0.71.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/LICENSE +21 -0
- package/README.md +144 -0
- package/SECURITY.md +39 -0
- package/SKILL.md +206 -0
- package/bin/cli.mjs +55 -0
- package/install.sh +143 -0
- package/package.json +54 -0
- package/references/adapter-candidates.md +40 -0
- package/references/browser-mcp-cheatsheet.md +132 -0
- package/references/browser-stats-cheatsheet.md +155 -0
- package/references/chrome-devtools-mcp-cheatsheet.md +232 -0
- package/references/midscene-integration.md +359 -0
- package/references/obscura-cheatsheet.md +103 -0
- package/references/playwright-cli-cheatsheet.md +64 -0
- package/references/playwright-lib-cheatsheet.md +90 -0
- package/references/recipes/add-a-tool-adapter.md +134 -0
- package/references/recipes/agent-workflows/README.md +37 -0
- package/references/recipes/agent-workflows/cache-driven-bulk-operation.md +110 -0
- package/references/recipes/agent-workflows/flow-record-and-replay.md +102 -0
- package/references/recipes/agent-workflows/incremental-pattern-discovery.md +125 -0
- package/references/recipes/agent-workflows/login-then-scrape.md +100 -0
- package/references/recipes/anti-patterns-tool-extension.md +182 -0
- package/references/recipes/body-bytes-not-body.md +139 -0
- package/references/recipes/cache-write-security.md +210 -0
- package/references/recipes/fingerprint-rescue.md +154 -0
- package/references/recipes/model-routing.md +143 -0
- package/references/recipes/path-security.md +138 -0
- package/references/recipes/privacy-canary.md +96 -0
- package/references/recipes/visual-rescue-hook.md +182 -0
- package/references/stats-prices.json +42 -0
- package/references/stats-schema.json +77 -0
- package/references/tool-versions.md +8 -0
- package/scripts/browser-add-site.sh +113 -0
- package/scripts/browser-assert.sh +106 -0
- package/scripts/browser-audit.sh +68 -0
- package/scripts/browser-baseline.sh +135 -0
- package/scripts/browser-click.sh +100 -0
- package/scripts/browser-creds-add.sh +254 -0
- package/scripts/browser-creds-list.sh +67 -0
- package/scripts/browser-creds-migrate.sh +122 -0
- package/scripts/browser-creds-remove.sh +69 -0
- package/scripts/browser-creds-rotate-totp.sh +109 -0
- package/scripts/browser-creds-show.sh +82 -0
- package/scripts/browser-creds-totp.sh +94 -0
- package/scripts/browser-do.sh +630 -0
- package/scripts/browser-doctor.sh +365 -0
- package/scripts/browser-drag.sh +90 -0
- package/scripts/browser-extract.sh +192 -0
- package/scripts/browser-fill.sh +142 -0
- package/scripts/browser-flow.sh +316 -0
- package/scripts/browser-history.sh +187 -0
- package/scripts/browser-hover.sh +92 -0
- package/scripts/browser-inspect.sh +188 -0
- package/scripts/browser-list-sessions.sh +78 -0
- package/scripts/browser-list-sites.sh +42 -0
- package/scripts/browser-login.sh +279 -0
- package/scripts/browser-mcp.sh +65 -0
- package/scripts/browser-migrate.sh +195 -0
- package/scripts/browser-open.sh +134 -0
- package/scripts/browser-press.sh +80 -0
- package/scripts/browser-remove-session.sh +72 -0
- package/scripts/browser-remove-site.sh +68 -0
- package/scripts/browser-replay.sh +206 -0
- package/scripts/browser-route.sh +174 -0
- package/scripts/browser-select.sh +122 -0
- package/scripts/browser-show-session.sh +57 -0
- package/scripts/browser-show-site.sh +37 -0
- package/scripts/browser-snapshot.sh +176 -0
- package/scripts/browser-stats.sh +522 -0
- package/scripts/browser-tab-close.sh +112 -0
- package/scripts/browser-tab-list.sh +70 -0
- package/scripts/browser-tab-switch.sh +111 -0
- package/scripts/browser-upload.sh +132 -0
- package/scripts/browser-use.sh +60 -0
- package/scripts/browser-vlm.sh +707 -0
- package/scripts/browser-wait.sh +97 -0
- package/scripts/install-git-hooks.sh +16 -0
- package/scripts/lib/capture.sh +356 -0
- package/scripts/lib/common.sh +262 -0
- package/scripts/lib/credential.sh +237 -0
- package/scripts/lib/fingerprint-rescue.js +123 -0
- package/scripts/lib/flow.sh +448 -0
- package/scripts/lib/flow_record.sh +210 -0
- package/scripts/lib/mask.sh +49 -0
- package/scripts/lib/memory.sh +427 -0
- package/scripts/lib/migrate.sh +390 -0
- package/scripts/lib/migrators/README.md +23 -0
- package/scripts/lib/migrators/memory/v1_to_v2.sh +15 -0
- package/scripts/lib/migrators/recent_urls/README.md +13 -0
- package/scripts/lib/migrators/stats/README.md +24 -0
- package/scripts/lib/node/chrome-devtools-bridge.mjs +1812 -0
- package/scripts/lib/node/mcp-server.mjs +531 -0
- package/scripts/lib/node/mcp-tools.json +68 -0
- package/scripts/lib/node/playwright-driver.mjs +1104 -0
- package/scripts/lib/node/totp-core.mjs +52 -0
- package/scripts/lib/node/totp.mjs +52 -0
- package/scripts/lib/node/url-pattern-cluster.mjs +102 -0
- package/scripts/lib/node/url-pattern-resolver.mjs +77 -0
- package/scripts/lib/output.sh +79 -0
- package/scripts/lib/router.sh +342 -0
- package/scripts/lib/sanitize.sh +107 -0
- package/scripts/lib/secret/keychain.sh +91 -0
- package/scripts/lib/secret/libsecret.sh +74 -0
- package/scripts/lib/secret/plaintext.sh +75 -0
- package/scripts/lib/secret_backend_select.sh +57 -0
- package/scripts/lib/session.sh +153 -0
- package/scripts/lib/site.sh +126 -0
- package/scripts/lib/stats.sh +419 -0
- package/scripts/lib/tool/.gitkeep +0 -0
- package/scripts/lib/tool/chrome-devtools-mcp.sh +349 -0
- package/scripts/lib/tool/obscura.sh +249 -0
- package/scripts/lib/tool/playwright-cli.sh +155 -0
- package/scripts/lib/tool/playwright-lib.sh +106 -0
- package/scripts/lib/verb_helpers.sh +222 -0
- package/scripts/lib/visual-rescue-default.sh +145 -0
- package/scripts/regenerate-docs.sh +99 -0
- package/uninstall.sh +51 -0
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# scripts/browser-tab-list.sh — enumerate tabs/pages currently held by the daemon.
|
|
3
|
+
# Usage: bash scripts/browser-tab-list.sh [--site NAME] [--tool NAME]
|
|
4
|
+
# [--dry-run] [--raw]
|
|
5
|
+
#
|
|
6
|
+
# Routes to chrome-devtools-mcp by default (Phase 6 part 8-i). Daemon-required:
|
|
7
|
+
# the verb caches the result in the daemon's `tabs` slot so 8-ii (tab-switch)
|
|
8
|
+
# and 8-iii (tab-close) can reference the same `tab_id` shape. Without daemon
|
|
9
|
+
# → exit 41 with hint.
|
|
10
|
+
#
|
|
11
|
+
# Read-only — no flags, no state mutation. The daemon dispatch calls upstream
|
|
12
|
+
# MCP `list_pages` (best-effort name; real upstream may differ) and normalizes
|
|
13
|
+
# to `[{tab_id, url, title}]`. `tab_id` is bridge-assigned (1-based, stable for
|
|
14
|
+
# the lifetime of one list_pages call); upstream's CDP target id never escapes
|
|
15
|
+
# the bridge.
|
|
16
|
+
|
|
17
|
+
set -euo pipefail
|
|
18
|
+
IFS=$'\n\t'
|
|
19
|
+
|
|
20
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
21
|
+
# shellcheck source=lib/common.sh
|
|
22
|
+
# shellcheck disable=SC1091
|
|
23
|
+
source "${SCRIPT_DIR}/lib/common.sh"
|
|
24
|
+
# shellcheck source=lib/output.sh
|
|
25
|
+
# shellcheck disable=SC1091
|
|
26
|
+
source "${SCRIPT_DIR}/lib/output.sh"
|
|
27
|
+
# shellcheck source=lib/router.sh
|
|
28
|
+
# shellcheck disable=SC1091
|
|
29
|
+
source "${SCRIPT_DIR}/lib/router.sh"
|
|
30
|
+
# shellcheck source=lib/verb_helpers.sh
|
|
31
|
+
# shellcheck disable=SC1091
|
|
32
|
+
source "${SCRIPT_DIR}/lib/verb_helpers.sh"
|
|
33
|
+
|
|
34
|
+
init_paths
|
|
35
|
+
|
|
36
|
+
SUMMARY_T0="$(now_ms)"; export SUMMARY_T0
|
|
37
|
+
|
|
38
|
+
parse_verb_globals "$@"
|
|
39
|
+
|
|
40
|
+
resolve_session_storage_state
|
|
41
|
+
|
|
42
|
+
# tab-list takes no required flags; pass remaining argv straight through so
|
|
43
|
+
# routing/capability checks still see globals like --tool.
|
|
44
|
+
verb_argv=("${REMAINING_ARGV[@]}")
|
|
45
|
+
|
|
46
|
+
if [ "${ARG_DRY_RUN:-0}" = "1" ]; then
|
|
47
|
+
ok "dry-run: would enumerate tabs via daemon"
|
|
48
|
+
emit_summary verb=tab-list tool=none why=dry-run status=ok dry_run=true
|
|
49
|
+
exit 0
|
|
50
|
+
fi
|
|
51
|
+
|
|
52
|
+
picked="$(pick_tool tab-list "${verb_argv[@]}")"
|
|
53
|
+
tool_name="${picked%%$'\t'*}"
|
|
54
|
+
why="${picked#*$'\t'}"
|
|
55
|
+
|
|
56
|
+
source_picked_adapter "${tool_name}"
|
|
57
|
+
|
|
58
|
+
set +e
|
|
59
|
+
adapter_out="$(invoke_with_retry tab-list "${verb_argv[@]}")"
|
|
60
|
+
adapter_rc=$?
|
|
61
|
+
set -e
|
|
62
|
+
|
|
63
|
+
[ -n "${adapter_out}" ] && printf '%s\n' "${adapter_out}"
|
|
64
|
+
|
|
65
|
+
if [ "${adapter_rc}" -eq 0 ]; then
|
|
66
|
+
emit_summary verb=tab-list tool="${tool_name}" why="${why}" status=ok
|
|
67
|
+
exit 0
|
|
68
|
+
fi
|
|
69
|
+
emit_summary verb=tab-list tool="${tool_name}" why="${why}" status=error
|
|
70
|
+
exit "${adapter_rc}"
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# scripts/browser-tab-switch.sh — switch the daemon's active tab.
|
|
3
|
+
# Usage: bash scripts/browser-tab-switch.sh [--site NAME] [--tool NAME]
|
|
4
|
+
# [--dry-run] [--raw]
|
|
5
|
+
# (--by-index N | --by-url-pattern STR)
|
|
6
|
+
#
|
|
7
|
+
# Routes to chrome-devtools-mcp by default (Phase 6 part 8-ii). Daemon-required:
|
|
8
|
+
# the daemon updates its `currentTab` pointer (added in this sub-part) and asks
|
|
9
|
+
# the upstream MCP to focus the corresponding page. Without daemon → exit 41.
|
|
10
|
+
#
|
|
11
|
+
# Mutex: exactly one of --by-index / --by-url-pattern. --by-index is 1-based
|
|
12
|
+
# (matches `tab_id` from tab-list). --by-url-pattern is substring-contains
|
|
13
|
+
# (case-sensitive, first match wins).
|
|
14
|
+
#
|
|
15
|
+
# If the daemon's tabs[] cache is empty (no preceding tab-list call), the
|
|
16
|
+
# daemon transparently auto-calls list_pages before resolving the selector.
|
|
17
|
+
|
|
18
|
+
set -euo pipefail
|
|
19
|
+
IFS=$'\n\t'
|
|
20
|
+
|
|
21
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
22
|
+
# shellcheck source=lib/common.sh
|
|
23
|
+
# shellcheck disable=SC1091
|
|
24
|
+
source "${SCRIPT_DIR}/lib/common.sh"
|
|
25
|
+
# shellcheck source=lib/output.sh
|
|
26
|
+
# shellcheck disable=SC1091
|
|
27
|
+
source "${SCRIPT_DIR}/lib/output.sh"
|
|
28
|
+
# shellcheck source=lib/router.sh
|
|
29
|
+
# shellcheck disable=SC1091
|
|
30
|
+
source "${SCRIPT_DIR}/lib/router.sh"
|
|
31
|
+
# shellcheck source=lib/verb_helpers.sh
|
|
32
|
+
# shellcheck disable=SC1091
|
|
33
|
+
source "${SCRIPT_DIR}/lib/verb_helpers.sh"
|
|
34
|
+
|
|
35
|
+
init_paths
|
|
36
|
+
|
|
37
|
+
SUMMARY_T0="$(now_ms)"; export SUMMARY_T0
|
|
38
|
+
|
|
39
|
+
parse_verb_globals "$@"
|
|
40
|
+
|
|
41
|
+
resolve_session_storage_state
|
|
42
|
+
|
|
43
|
+
by_index="" by_url_pattern=""
|
|
44
|
+
verb_argv=()
|
|
45
|
+
i=0
|
|
46
|
+
while [ "${i}" -lt "${#REMAINING_ARGV[@]}" ]; do
|
|
47
|
+
case "${REMAINING_ARGV[i]}" in
|
|
48
|
+
--by-index)
|
|
49
|
+
by_index="${REMAINING_ARGV[i+1]:-}"
|
|
50
|
+
[ -n "${by_index}" ] || die "${EXIT_USAGE_ERROR}" "--by-index requires a value"
|
|
51
|
+
verb_argv+=(--by-index "${by_index}")
|
|
52
|
+
i=$((i + 2))
|
|
53
|
+
;;
|
|
54
|
+
--by-url-pattern)
|
|
55
|
+
by_url_pattern="${REMAINING_ARGV[i+1]:-}"
|
|
56
|
+
[ -n "${by_url_pattern}" ] || die "${EXIT_USAGE_ERROR}" "--by-url-pattern requires a value"
|
|
57
|
+
verb_argv+=(--by-url-pattern "${by_url_pattern}")
|
|
58
|
+
i=$((i + 2))
|
|
59
|
+
;;
|
|
60
|
+
*)
|
|
61
|
+
verb_argv+=("${REMAINING_ARGV[i]}")
|
|
62
|
+
i=$((i + 1))
|
|
63
|
+
;;
|
|
64
|
+
esac
|
|
65
|
+
done
|
|
66
|
+
|
|
67
|
+
# Mutex + presence: exactly one selector required.
|
|
68
|
+
if [ -n "${by_index}" ] && [ -n "${by_url_pattern}" ]; then
|
|
69
|
+
die "${EXIT_USAGE_ERROR}" "--by-index and --by-url-pattern are mutually exclusive"
|
|
70
|
+
fi
|
|
71
|
+
if [ -z "${by_index}" ] && [ -z "${by_url_pattern}" ]; then
|
|
72
|
+
die "${EXIT_USAGE_ERROR}" "tab-switch requires exactly one of --by-index N or --by-url-pattern STR"
|
|
73
|
+
fi
|
|
74
|
+
|
|
75
|
+
# Validate by-index is a positive integer (1-based).
|
|
76
|
+
if [ -n "${by_index}" ]; then
|
|
77
|
+
if ! printf '%s' "${by_index}" | grep -Eq '^[1-9][0-9]*$'; then
|
|
78
|
+
die "${EXIT_USAGE_ERROR}" "--by-index must be a positive integer (1-based); got: ${by_index}"
|
|
79
|
+
fi
|
|
80
|
+
fi
|
|
81
|
+
|
|
82
|
+
if [ "${ARG_DRY_RUN:-0}" = "1" ]; then
|
|
83
|
+
if [ -n "${by_index}" ]; then
|
|
84
|
+
ok "dry-run: would switch to tab #${by_index}"
|
|
85
|
+
emit_summary verb=tab-switch tool=none why=dry-run status=ok by_index="${by_index}" dry_run=true
|
|
86
|
+
else
|
|
87
|
+
ok "dry-run: would switch to first tab matching ${by_url_pattern}"
|
|
88
|
+
emit_summary verb=tab-switch tool=none why=dry-run status=ok by_url_pattern="${by_url_pattern}" dry_run=true
|
|
89
|
+
fi
|
|
90
|
+
exit 0
|
|
91
|
+
fi
|
|
92
|
+
|
|
93
|
+
picked="$(pick_tool tab-switch "${verb_argv[@]}")"
|
|
94
|
+
tool_name="${picked%%$'\t'*}"
|
|
95
|
+
why="${picked#*$'\t'}"
|
|
96
|
+
|
|
97
|
+
source_picked_adapter "${tool_name}"
|
|
98
|
+
|
|
99
|
+
set +e
|
|
100
|
+
adapter_out="$(invoke_with_retry tab-switch "${verb_argv[@]}")"
|
|
101
|
+
adapter_rc=$?
|
|
102
|
+
set -e
|
|
103
|
+
|
|
104
|
+
[ -n "${adapter_out}" ] && printf '%s\n' "${adapter_out}"
|
|
105
|
+
|
|
106
|
+
if [ "${adapter_rc}" -eq 0 ]; then
|
|
107
|
+
emit_summary verb=tab-switch tool="${tool_name}" why="${why}" status=ok
|
|
108
|
+
exit 0
|
|
109
|
+
fi
|
|
110
|
+
emit_summary verb=tab-switch tool="${tool_name}" why="${why}" status=error
|
|
111
|
+
exit "${adapter_rc}"
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# scripts/browser-upload.sh — fill <input type=file> by --ref + --path.
|
|
3
|
+
# Usage: bash scripts/browser-upload.sh [--site NAME] [--tool NAME] [--dry-run]
|
|
4
|
+
# [--raw] --ref eN --path PATH
|
|
5
|
+
# [--allow-sensitive]
|
|
6
|
+
#
|
|
7
|
+
# Routes to chrome-devtools-mcp by default (Phase 6 part 6). Stateful —
|
|
8
|
+
# requires running daemon (refMap precondition).
|
|
9
|
+
#
|
|
10
|
+
# SECURITY (path validation, performed bash-side BEFORE invoking adapter):
|
|
11
|
+
# 1. Path must exist and be a regular file (not dir, not device, not symlink-to-elsewhere).
|
|
12
|
+
# 2. Path must be readable by the current user.
|
|
13
|
+
# 3. Path must NOT match common sensitive patterns (~/.ssh/*, ~/.aws/*,
|
|
14
|
+
# ~/.config/*credentials*, *.env). Override via --allow-sensitive
|
|
15
|
+
# (typed acknowledgment that the agent is uploading sensitive material
|
|
16
|
+
# intentionally — covers legit use cases like "upload my GPG key").
|
|
17
|
+
# Path is then resolved (`readlink -f` / `realpath`) and forwarded to MCP.
|
|
18
|
+
|
|
19
|
+
set -euo pipefail
|
|
20
|
+
IFS=$'\n\t'
|
|
21
|
+
|
|
22
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
23
|
+
# shellcheck source=lib/common.sh
|
|
24
|
+
# shellcheck disable=SC1091
|
|
25
|
+
source "${SCRIPT_DIR}/lib/common.sh"
|
|
26
|
+
# shellcheck source=lib/output.sh
|
|
27
|
+
# shellcheck disable=SC1091
|
|
28
|
+
source "${SCRIPT_DIR}/lib/output.sh"
|
|
29
|
+
# shellcheck source=lib/router.sh
|
|
30
|
+
# shellcheck disable=SC1091
|
|
31
|
+
source "${SCRIPT_DIR}/lib/router.sh"
|
|
32
|
+
# shellcheck source=lib/verb_helpers.sh
|
|
33
|
+
# shellcheck disable=SC1091
|
|
34
|
+
source "${SCRIPT_DIR}/lib/verb_helpers.sh"
|
|
35
|
+
|
|
36
|
+
init_paths
|
|
37
|
+
|
|
38
|
+
SUMMARY_T0="$(now_ms)"; export SUMMARY_T0
|
|
39
|
+
|
|
40
|
+
parse_verb_globals "$@"
|
|
41
|
+
|
|
42
|
+
resolve_session_storage_state
|
|
43
|
+
|
|
44
|
+
ref="" path="" allow_sensitive=0
|
|
45
|
+
verb_argv=()
|
|
46
|
+
i=0
|
|
47
|
+
while [ "${i}" -lt "${#REMAINING_ARGV[@]}" ]; do
|
|
48
|
+
case "${REMAINING_ARGV[i]}" in
|
|
49
|
+
--ref)
|
|
50
|
+
ref="${REMAINING_ARGV[i+1]:-}"
|
|
51
|
+
[ -n "${ref}" ] || die "${EXIT_USAGE_ERROR}" "--ref requires a value"
|
|
52
|
+
verb_argv+=(--ref "${ref}")
|
|
53
|
+
i=$((i + 2))
|
|
54
|
+
;;
|
|
55
|
+
--path)
|
|
56
|
+
path="${REMAINING_ARGV[i+1]:-}"
|
|
57
|
+
[ -n "${path}" ] || die "${EXIT_USAGE_ERROR}" "--path requires a value"
|
|
58
|
+
i=$((i + 2))
|
|
59
|
+
;;
|
|
60
|
+
--allow-sensitive)
|
|
61
|
+
allow_sensitive=1
|
|
62
|
+
i=$((i + 1))
|
|
63
|
+
;;
|
|
64
|
+
*)
|
|
65
|
+
verb_argv+=("${REMAINING_ARGV[i]}")
|
|
66
|
+
i=$((i + 1))
|
|
67
|
+
;;
|
|
68
|
+
esac
|
|
69
|
+
done
|
|
70
|
+
|
|
71
|
+
[ -n "${ref}" ] || die "${EXIT_USAGE_ERROR}" "upload requires --ref eN"
|
|
72
|
+
[ -n "${path}" ] || die "${EXIT_USAGE_ERROR}" "upload requires --path PATH"
|
|
73
|
+
|
|
74
|
+
# Path security validation (bash-side, before adapter dispatch).
|
|
75
|
+
# 1. File must exist + be a regular file.
|
|
76
|
+
if [ ! -e "${path}" ]; then
|
|
77
|
+
die "${EXIT_USAGE_ERROR}" "upload: path does not exist: ${path}"
|
|
78
|
+
fi
|
|
79
|
+
if [ ! -f "${path}" ]; then
|
|
80
|
+
die "${EXIT_USAGE_ERROR}" "upload: path is not a regular file (directory, device, or other): ${path}"
|
|
81
|
+
fi
|
|
82
|
+
# 2. File must be readable.
|
|
83
|
+
if [ ! -r "${path}" ]; then
|
|
84
|
+
die "${EXIT_USAGE_ERROR}" "upload: path is not readable by the current user: ${path}"
|
|
85
|
+
fi
|
|
86
|
+
# 3. Sensitive-pattern reject. Common locations agents shouldn't accidentally
|
|
87
|
+
# upload from. Override with --allow-sensitive when intentional.
|
|
88
|
+
if [ "${allow_sensitive}" -ne 1 ]; then
|
|
89
|
+
case "${path}" in
|
|
90
|
+
*.ssh/*|*/.ssh/*|*.aws/credentials|*/.aws/credentials|*/.env|*.env|\
|
|
91
|
+
*/credentials|*/credentials.json|*/secrets.json|*/private_key*|*/id_rsa*|\
|
|
92
|
+
*/id_ed25519*|*/id_ecdsa*)
|
|
93
|
+
die "${EXIT_USAGE_ERROR}" "upload: path '${path}' matches a sensitive pattern (SSH key / AWS / .env / private_key); pass --allow-sensitive to override"
|
|
94
|
+
;;
|
|
95
|
+
esac
|
|
96
|
+
fi
|
|
97
|
+
|
|
98
|
+
# Resolve to canonical path (eliminate symlink shenanigans). Cross-platform:
|
|
99
|
+
# `readlink -f` is GNU; macOS BSD has it via Xcode 11+ but `realpath` is more
|
|
100
|
+
# portable. Try realpath first, fall back to readlink -f.
|
|
101
|
+
canonical_path="$(realpath "${path}" 2>/dev/null || readlink -f "${path}" 2>/dev/null || printf '%s' "${path}")"
|
|
102
|
+
|
|
103
|
+
verb_argv+=(--path "${canonical_path}")
|
|
104
|
+
|
|
105
|
+
if [ "${ARG_DRY_RUN:-0}" = "1" ]; then
|
|
106
|
+
ok "dry-run: would upload ${canonical_path} to ${ref}"
|
|
107
|
+
emit_summary verb=upload tool=none why=dry-run status=ok \
|
|
108
|
+
ref="${ref}" path="${canonical_path}" dry_run=true
|
|
109
|
+
exit 0
|
|
110
|
+
fi
|
|
111
|
+
|
|
112
|
+
picked="$(pick_tool upload "${verb_argv[@]}")"
|
|
113
|
+
tool_name="${picked%%$'\t'*}"
|
|
114
|
+
why="${picked#*$'\t'}"
|
|
115
|
+
|
|
116
|
+
source_picked_adapter "${tool_name}"
|
|
117
|
+
|
|
118
|
+
set +e
|
|
119
|
+
adapter_out="$(invoke_with_retry upload "${verb_argv[@]}")"
|
|
120
|
+
adapter_rc=$?
|
|
121
|
+
set -e
|
|
122
|
+
|
|
123
|
+
[ -n "${adapter_out}" ] && printf '%s\n' "${adapter_out}"
|
|
124
|
+
|
|
125
|
+
if [ "${adapter_rc}" -eq 0 ]; then
|
|
126
|
+
emit_summary verb=upload tool="${tool_name}" why="${why}" status=ok \
|
|
127
|
+
ref="${ref}" path="${canonical_path}"
|
|
128
|
+
exit 0
|
|
129
|
+
fi
|
|
130
|
+
emit_summary verb=upload tool="${tool_name}" why="${why}" status=error \
|
|
131
|
+
ref="${ref}" path="${canonical_path}"
|
|
132
|
+
exit "${adapter_rc}"
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# use — get / set / clear the current site (CURRENT_FILE).
|
|
3
|
+
set -euo pipefail
|
|
4
|
+
IFS=$'\n\t'
|
|
5
|
+
umask 077
|
|
6
|
+
|
|
7
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
8
|
+
# shellcheck source=lib/common.sh
|
|
9
|
+
# shellcheck disable=SC1091
|
|
10
|
+
source "${SCRIPT_DIR}/lib/common.sh"
|
|
11
|
+
# shellcheck source=lib/site.sh
|
|
12
|
+
# shellcheck disable=SC1091
|
|
13
|
+
source "${SCRIPT_DIR}/lib/site.sh"
|
|
14
|
+
init_paths
|
|
15
|
+
|
|
16
|
+
mode=""; arg=""
|
|
17
|
+
usage() {
|
|
18
|
+
cat <<'USAGE'
|
|
19
|
+
Usage: use --set NAME | --show | --clear
|
|
20
|
+
USAGE
|
|
21
|
+
}
|
|
22
|
+
while [ $# -gt 0 ]; do
|
|
23
|
+
case "$1" in
|
|
24
|
+
--set) mode=set; arg="$2"; shift 2 ;;
|
|
25
|
+
--show) mode=show; shift ;;
|
|
26
|
+
--clear) mode=clear; shift ;;
|
|
27
|
+
-h|--help) usage; exit 0 ;;
|
|
28
|
+
*) die "${EXIT_USAGE_ERROR}" "unknown flag: $1" ;;
|
|
29
|
+
esac
|
|
30
|
+
done
|
|
31
|
+
[ -n "${mode}" ] || { usage; die "${EXIT_USAGE_ERROR}" "specify --set NAME, --show, or --clear"; }
|
|
32
|
+
|
|
33
|
+
started_at_ms="$(now_ms)"
|
|
34
|
+
|
|
35
|
+
case "${mode}" in
|
|
36
|
+
set)
|
|
37
|
+
[ -n "${arg}" ] || die "${EXIT_USAGE_ERROR}" "--set requires NAME"
|
|
38
|
+
current_set "${arg}"
|
|
39
|
+
ok "current site: ${arg}"
|
|
40
|
+
why="set"
|
|
41
|
+
;;
|
|
42
|
+
show)
|
|
43
|
+
why="show"
|
|
44
|
+
;;
|
|
45
|
+
clear)
|
|
46
|
+
current_clear
|
|
47
|
+
ok "current site cleared"
|
|
48
|
+
why="clear"
|
|
49
|
+
;;
|
|
50
|
+
esac
|
|
51
|
+
|
|
52
|
+
current="$(current_get)"
|
|
53
|
+
duration_ms=$(( $(now_ms) - started_at_ms ))
|
|
54
|
+
if [ -z "${current}" ]; then
|
|
55
|
+
jq -cn --arg w "${why}" --argjson d "${duration_ms}" \
|
|
56
|
+
'{verb: "use", tool: "none", why: $w, status: "ok", current: null, duration_ms: $d}'
|
|
57
|
+
else
|
|
58
|
+
jq -cn --arg w "${why}" --arg c "${current}" --argjson d "${duration_ms}" \
|
|
59
|
+
'{verb: "use", tool: "none", why: $w, status: "ok", current: $c, duration_ms: $d}'
|
|
60
|
+
fi
|