@larktask/aamp-feishu-task-agent 0.1.0-dev.174 → 0.1.1-dev.3
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 +114 -18
- package/bin/agent-metadata.mjs +54 -0
- package/bin/feishu-task-agent-controller.mjs +1947 -359
- package/bin/runtime-concurrency.mjs +71 -0
- package/bin/runtime-network.mjs +13 -0
- package/bin/runtime-package-executable.mjs +254 -0
- package/bin/traecode-readiness.mjs +173 -0
- package/bootstrap/aamp-feishu-task-agent-bootstrap.sh +1477 -56
- package/package.json +1 -1
|
@@ -5,8 +5,12 @@ umask 077
|
|
|
5
5
|
AGENT=""
|
|
6
6
|
APP_ID=""
|
|
7
7
|
APP_SECRET=""
|
|
8
|
+
APP_TENANT_BRAND="feishu"
|
|
8
9
|
BOT_NAME=""
|
|
9
10
|
LARK_CLI_PROFILE=""
|
|
11
|
+
AGENT_EXECUTION_LOCATION=""
|
|
12
|
+
AGENT_ATTACHMENT_POLICY=""
|
|
13
|
+
AGENT_TASK_DISPATCH_CONCURRENCY=""
|
|
10
14
|
AAMP_HOST="https://meshmail.ai"
|
|
11
15
|
DEBUG_MODE="false"
|
|
12
16
|
AAMP_TASK_START_MODE="install"
|
|
@@ -15,6 +19,7 @@ AAMP_TASK_ENTRY="${AAMP_TASK_ENTRY:-}"
|
|
|
15
19
|
AAMP_TASK_INTERNAL="${AAMP_TASK_INTERNAL:-false}"
|
|
16
20
|
AAMP_TASK_INTERNAL_RESULT_FD="${AAMP_TASK_INTERNAL_RESULT_FD:-3}"
|
|
17
21
|
AAMP_TASK_INTERNAL_INPUT_FD="${AAMP_TASK_INTERNAL_INPUT_FD:-4}"
|
|
22
|
+
AAMP_TASK_INTERNAL_EXECUTION_LOCATION="${AAMP_TASK_INTERNAL_EXECUTION_LOCATION:-}"
|
|
18
23
|
NPM_REGISTRY="${NPM_REGISTRY:-https://registry.npmjs.org/}"
|
|
19
24
|
NPM_CACHE_DIR="${NPM_CONFIG_CACHE:-${npm_config_cache:-${TMPDIR:-/tmp}/aamp-one-click-npm-cache}}"
|
|
20
25
|
NPM_GLOBAL_PREFIX="${NPM_GLOBAL_PREFIX:-$HOME/.aamp/npm-global}"
|
|
@@ -51,22 +56,63 @@ CODEX_CHATGPT_APP_CLI="/Applications/ChatGPT.app/Contents/Resources/codex"
|
|
|
51
56
|
CODEX_APP_CLI="/Applications/Codex.app/Contents/Resources/codex"
|
|
52
57
|
CODEX_AUTO_UPDATE="${CODEX_AUTO_UPDATE:-true}"
|
|
53
58
|
CODEX_NPM_PACKAGE="${CODEX_NPM_PACKAGE:-@openai/codex}"
|
|
59
|
+
CODEX_UPDATE_CACHE_FILE="${CODEX_UPDATE_CACHE_FILE:-$HOME/.aamp/feishu-task-agent/codex-update-cache.json}"
|
|
60
|
+
CODEX_UPDATE_CACHE_TTL_SECONDS="${CODEX_UPDATE_CACHE_TTL_SECONDS:-86400}"
|
|
54
61
|
CODEX_ACP_PKG="${CODEX_ACP_PKG:-@agentclientprotocol/codex-acp@1.0.2}"
|
|
62
|
+
AAMP_TRAE_CLI_BIN="${AAMP_TRAE_CLI_BIN:-}"
|
|
63
|
+
AAMP_TRAE_LOGIN_STATUS_TIMEOUT_SECONDS="${AAMP_TRAE_LOGIN_STATUS_TIMEOUT_SECONDS:-10}"
|
|
64
|
+
AAMP_TRAECODE_CLI_BIN="${AAMP_TRAECODE_CLI_BIN:-}"
|
|
65
|
+
AAMP_TRAECODE_CHECK_TIMEOUT_SECONDS="${AAMP_TRAECODE_CHECK_TIMEOUT_SECONDS:-10}"
|
|
66
|
+
AAMP_TRAECODE_READINESS_HELPER="${AAMP_TRAECODE_READINESS_HELPER:-}"
|
|
67
|
+
AAMP_TRAECODE_UPDATE_TTY="${AAMP_TRAECODE_UPDATE_TTY:-/dev/tty}"
|
|
68
|
+
TRAEX_INSTALLER_URL="${TRAEX_INSTALLER_URL:-https://code.byted.org/api/tos-proxy/download/traex_install.sh}"
|
|
69
|
+
WORKBUDDY_APP_CLI="/Applications/WorkBuddy.app/Contents/Resources/app.asar.unpacked/cli/bin/codebuddy"
|
|
70
|
+
WORKBUDDY_AI_APP_CLI="/Applications/WorkBuddy AI.app/Contents/Resources/app.asar.unpacked/cli/bin/codebuddy"
|
|
55
71
|
LARK_REGISTER_APP_SDK="${LARK_REGISTER_APP_SDK:-@larksuiteoapi/node-sdk@1.68.0}"
|
|
56
72
|
LARK_CLI_MIN_VERSION="${LARK_CLI_MIN_VERSION:-1.0.64}"
|
|
57
|
-
|
|
58
|
-
|
|
73
|
+
AAMP_FEISHU_APP_SCOPES_TENANT_OVERRIDE="${FEISHU_APP_SCOPES_TENANT-}"
|
|
74
|
+
AAMP_FEISHU_APP_SCOPES_USER_OVERRIDE="${FEISHU_APP_SCOPES_USER-}"
|
|
75
|
+
AAMP_FEISHU_USER_AUTH_REQUIRED_SCOPES_OVERRIDE="${FEISHU_USER_AUTH_REQUIRED_SCOPES-}"
|
|
76
|
+
AAMP_FEISHU_USER_AUTH_REQUESTED_SCOPES_OVERRIDE="${FEISHU_USER_AUTH_REQUESTED_SCOPES-}"
|
|
77
|
+
AAMP_FEISHU_USER_AUTH_EXCLUDES_OVERRIDE="${FEISHU_USER_AUTH_EXCLUDES-}"
|
|
78
|
+
FEISHU_APP_SCOPES_TENANT="$AAMP_FEISHU_APP_SCOPES_TENANT_OVERRIDE"
|
|
79
|
+
FEISHU_APP_SCOPES_USER="$AAMP_FEISHU_APP_SCOPES_USER_OVERRIDE"
|
|
59
80
|
FEISHU_APP_EVENTS_TENANT="${FEISHU_APP_EVENTS_TENANT:-task.task.update_user_access_v2}"
|
|
60
81
|
FEISHU_APP_EVENTS_USER="${FEISHU_APP_EVENTS_USER:-task.task.update_user_access_v2}"
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
82
|
+
FEISHU_USER_AUTH_EXCLUDES="$AAMP_FEISHU_USER_AUTH_EXCLUDES_OVERRIDE"
|
|
83
|
+
FEISHU_USER_AUTH_REQUIRED_SCOPES="$AAMP_FEISHU_USER_AUTH_REQUIRED_SCOPES_OVERRIDE"
|
|
84
|
+
FEISHU_USER_AUTH_REQUESTED_SCOPES="$AAMP_FEISHU_USER_AUTH_REQUESTED_SCOPES_OVERRIDE"
|
|
85
|
+
FEISHU_USER_AUTH_CORE_SCOPES="${FEISHU_USER_AUTH_CORE_SCOPES:-}"
|
|
86
|
+
FEISHU_USER_AUTH_OPTIONAL_SCOPES="${FEISHU_USER_AUTH_OPTIONAL_SCOPES:-}"
|
|
87
|
+
FEISHU_USER_AUTH_MODE="${FEISHU_USER_AUTH_MODE:-optional}"
|
|
88
|
+
FEISHU_TASK_PROFILE_DOMAINS="${FEISHU_TASK_PROFILE_DOMAINS:-task}"
|
|
89
|
+
AAMP_FEISHU_AUTH_STATE_DIR="${AAMP_FEISHU_AUTH_STATE_DIR:-$HOME/.aamp/feishu-bridge/auth-capabilities}"
|
|
90
|
+
AAMP_TASK_ALLOW_PACKAGE_OVERRIDES="${AAMP_TASK_ALLOW_PACKAGE_OVERRIDES:-false}"
|
|
91
|
+
if [ "$AAMP_TASK_INTERNAL" = "true" ] \
|
|
92
|
+
&& [ "${AAMP_TASK_PACKAGE_OVERRIDES_RESOLVED:-false}" = "true" ]; then
|
|
93
|
+
AAMP_TASK_REQUESTED_ACP_BRIDGE_PKG="${AAMP_TASK_REQUESTED_ACP_BRIDGE_PKG:-}"
|
|
94
|
+
AAMP_TASK_REQUESTED_FEISHU_BRIDGE_PKG="${AAMP_TASK_REQUESTED_FEISHU_BRIDGE_PKG:-}"
|
|
95
|
+
AAMP_TASK_REQUESTED_AIME_ACP_PKG="${AAMP_TASK_REQUESTED_AIME_ACP_PKG:-}"
|
|
96
|
+
else
|
|
97
|
+
AAMP_TASK_REQUESTED_ACP_BRIDGE_PKG="${ACP_BRIDGE_PKG:-${AAMP_TASK_ACP_BRIDGE_PKG:-}}"
|
|
98
|
+
AAMP_TASK_REQUESTED_FEISHU_BRIDGE_PKG="${FEISHU_BRIDGE_PKG:-${AAMP_TASK_FEISHU_BRIDGE_PKG:-}}"
|
|
99
|
+
AAMP_TASK_REQUESTED_AIME_ACP_PKG="${AIME_ACP_PKG:-${AAMP_TASK_AIME_ACP_PKG:-}}"
|
|
100
|
+
fi
|
|
101
|
+
unset AAMP_TASK_PACKAGE_OVERRIDES_RESOLVED
|
|
102
|
+
unset ACP_BRIDGE_PKG AAMP_TASK_ACP_BRIDGE_PKG
|
|
103
|
+
unset FEISHU_BRIDGE_PKG AAMP_TASK_FEISHU_BRIDGE_PKG
|
|
104
|
+
unset AIME_ACP_PKG AIME_ACP_REGISTRY AAMP_TASK_AIME_ACP_PKG
|
|
105
|
+
ACP_BRIDGE_PKG="${ACP_BRIDGE_PKG:-@luckyterry/aamp-acp-bridge@0.1.29-dev.0}"
|
|
106
|
+
AIME_ACP_PKG="${AIME_ACP_PKG:-@tengchengwei/aime-acp@0.1.1-dev.1}"
|
|
107
|
+
AIME_ACP_REGISTRY="${AIME_ACP_REGISTRY:-https://bnpm.byted.org}"
|
|
65
108
|
CLI_BRIDGE_PKG="${CLI_BRIDGE_PKG:-@zengxingyuan/aamp-cli-bridge@0.1.7-dev.14}"
|
|
66
|
-
FEISHU_BRIDGE_PKG="${FEISHU_BRIDGE_PKG:-@
|
|
109
|
+
FEISHU_BRIDGE_PKG="${FEISHU_BRIDGE_PKG:-@iluolyx/aamp-feishu-bridge@0.1.52-dev.5}"
|
|
110
|
+
AAMP_TASK_DEFAULT_ACP_BRIDGE_PKG="$ACP_BRIDGE_PKG"
|
|
111
|
+
AAMP_TASK_DEFAULT_FEISHU_BRIDGE_PKG="$FEISHU_BRIDGE_PKG"
|
|
112
|
+
AAMP_TASK_DEFAULT_AIME_ACP_PKG="$AIME_ACP_PKG"
|
|
67
113
|
AAMP_TASK_AGENT_NAME="${AAMP_TASK_AGENT_NAME:-@larktask/aamp-feishu-task-agent}"
|
|
68
114
|
AAMP_TASK_AGENT_LEGACY_NAME="${AAMP_TASK_AGENT_LEGACY_NAME:-@zengxingyuan/aamp-feishu-task-agent}"
|
|
69
|
-
AAMP_TASK_AGENT_VERSION="0.1.
|
|
115
|
+
AAMP_TASK_AGENT_VERSION="0.1.1-dev.3"
|
|
70
116
|
AAMP_TASK_AGENT_CHANNEL="${AAMP_TASK_AGENT_CHANNEL:-dev}"
|
|
71
117
|
AAMP_STALE_PROCESS_CLEANUP="${AAMP_STALE_PROCESS_CLEANUP:-false}"
|
|
72
118
|
AAMP_STALE_PROCESS_SECONDS="${AAMP_STALE_PROCESS_SECONDS:-86400}"
|
|
@@ -86,8 +132,12 @@ CODEM_SERVICE_START_OUTPUT=""
|
|
|
86
132
|
CODEM_AUTO_UPDATE_DONE="false"
|
|
87
133
|
CODEM_FORCE_LOGIN_DONE="false"
|
|
88
134
|
CODEM_PROVIDER_RECOVERY_DONE="false"
|
|
135
|
+
TRAE_CLI_BIN=""
|
|
136
|
+
TRAECODE_CLI_BIN=""
|
|
89
137
|
PAIRING_URL=""
|
|
90
138
|
ACP_AGENT_COMMAND=""
|
|
139
|
+
AGENT_PREPARE_CANCELLED="false"
|
|
140
|
+
AGENT_PREPARE_CANCEL_REASON=""
|
|
91
141
|
STARTED_BRIDGE_PID=""
|
|
92
142
|
ONE_CLICK_RUN_ID="$(date +%s)-$$"
|
|
93
143
|
BOT_RESERVED="false"
|
|
@@ -116,6 +166,13 @@ sanitize_inherited_npm_exec_env() {
|
|
|
116
166
|
done < <(env)
|
|
117
167
|
}
|
|
118
168
|
|
|
169
|
+
remote_internal_helper() {
|
|
170
|
+
[ "$AAMP_TASK_INTERNAL" = "true" ] && {
|
|
171
|
+
[ "$AAMP_TASK_INTERNAL_EXECUTION_LOCATION" = "remote" ] \
|
|
172
|
+
|| [ "$AGENT_EXECUTION_LOCATION" = "remote" ]
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
119
176
|
usage() {
|
|
120
177
|
cat <<'USAGE'
|
|
121
178
|
Usage:
|
|
@@ -132,7 +189,8 @@ Running the standalone one-click script without a subcommand is the same as
|
|
|
132
189
|
"feishu-task-agent install".
|
|
133
190
|
|
|
134
191
|
Options:
|
|
135
|
-
--agent codex|cursor
|
|
192
|
+
--agent codex|cursor|coco|traex|traecli|workbuddy|workbuddy_ai|aime
|
|
193
|
+
Use this Agent for every new binding in the command.
|
|
136
194
|
--aamp-host URL AAMP service URL. Default: https://meshmail.ai
|
|
137
195
|
--debug Enable debug mode for bridge processes
|
|
138
196
|
-h, --help Show this help
|
|
@@ -792,6 +850,7 @@ task_agent_global_install_is_complete() {
|
|
|
792
850
|
[ -x "$NPM_GLOBAL_PREFIX/bin/aamp-logs" ] || return 1
|
|
793
851
|
[ -r "$package_dir/bootstrap/aamp-feishu-task-agent-bootstrap.sh" ] || return 1
|
|
794
852
|
[ -r "$package_dir/bin/feishu-task-agent-controller.mjs" ] || return 1
|
|
853
|
+
[ -r "$package_dir/bin/traecode-readiness.mjs" ] || return 1
|
|
795
854
|
}
|
|
796
855
|
|
|
797
856
|
task_agent_global_install_is_current() {
|
|
@@ -816,7 +875,7 @@ ensure_task_agent_global_install_locked() {
|
|
|
816
875
|
fi
|
|
817
876
|
remove_legacy_task_agent_global_install || return 1
|
|
818
877
|
agent_detail "synchronizing task-agent npm package: current=${installed_version:-missing} expected=$expected_version"
|
|
819
|
-
npm_install_global "$AAMP_TASK_AGENT_NAME@$expected_version" >>"$ONE_CLICK_LOG" 2>&1 || return 1
|
|
878
|
+
npm_install_global "$AAMP_TASK_AGENT_NAME@$expected_version" --force >>"$ONE_CLICK_LOG" 2>&1 || return 1
|
|
820
879
|
task_agent_global_install_is_current "$expected_version"
|
|
821
880
|
}
|
|
822
881
|
|
|
@@ -830,12 +889,16 @@ ensure_task_agent_global_install() {
|
|
|
830
889
|
|
|
831
890
|
short_command_is_current() {
|
|
832
891
|
local target="$1"
|
|
892
|
+
local source_file="${2:-}"
|
|
833
893
|
local installed_name installed_version
|
|
834
894
|
[ -x "$target" ] || return 1
|
|
835
895
|
installed_name="$(script_file_task_agent_name "$target" || true)"
|
|
836
896
|
installed_version="$(script_file_task_agent_version "$target" || true)"
|
|
837
897
|
[ "$installed_name" = "$AAMP_TASK_AGENT_NAME" ] || return 1
|
|
838
|
-
[ "$installed_version" = "$AAMP_TASK_AGENT_VERSION" ]
|
|
898
|
+
[ "$installed_version" = "$AAMP_TASK_AGENT_VERSION" ] || return 1
|
|
899
|
+
if [ -n "$source_file" ] && [ -r "$source_file" ]; then
|
|
900
|
+
cmp -s "$source_file" "$target"
|
|
901
|
+
fi
|
|
839
902
|
}
|
|
840
903
|
|
|
841
904
|
write_task_update_cache() {
|
|
@@ -913,13 +976,13 @@ install_short_command_current() {
|
|
|
913
976
|
local target="$1"
|
|
914
977
|
local source_file="${BASH_SOURCE[0]:-}"
|
|
915
978
|
local tmp="${target}.tmp.$$"
|
|
916
|
-
if short_command_is_current "$target"; then
|
|
917
|
-
agent_detail "short command already current: $target"
|
|
918
|
-
return 0
|
|
919
|
-
fi
|
|
920
979
|
case "$source_file" in
|
|
921
980
|
""|/dev/fd/*|/private/dev/fd/*|/proc/*) source_file="" ;;
|
|
922
981
|
esac
|
|
982
|
+
if short_command_is_current "$target" "$source_file"; then
|
|
983
|
+
agent_detail "short command already current: $target"
|
|
984
|
+
return 0
|
|
985
|
+
fi
|
|
923
986
|
if [ -n "$source_file" ] && [ -f "$source_file" ] && [ -r "$source_file" ]; then
|
|
924
987
|
mkdir -p "$(dirname "$target")"
|
|
925
988
|
cp "$source_file" "$tmp" 2>>"$ONE_CLICK_LOG" || return 1
|
|
@@ -950,6 +1013,7 @@ ensure_selected_agent_for_start() {
|
|
|
950
1013
|
select_agent_interactively
|
|
951
1014
|
fi
|
|
952
1015
|
validate_agent_name "$AGENT"
|
|
1016
|
+
ensure_agent_selection_available "$AGENT"
|
|
953
1017
|
}
|
|
954
1018
|
|
|
955
1019
|
resolve_latest_task_agent_version() {
|
|
@@ -1034,12 +1098,109 @@ run_task_agent_update_command() {
|
|
|
1034
1098
|
install_aamp_logs_bin "$installed_version" || agent_fail "failed to synchronize aamp-logs $installed_version"
|
|
1035
1099
|
printf '当前版本:%s\n' "$installed_version"
|
|
1036
1100
|
}
|
|
1037
|
-
|
|
1101
|
+
classify_remote_npm_cache_error() {
|
|
1102
|
+
node -e '
|
|
1103
|
+
let carry = "";
|
|
1104
|
+
let lineSawEnoent = false;
|
|
1105
|
+
let lineSawTarballData = false;
|
|
1106
|
+
let matched = false;
|
|
1107
|
+
const scan = (part, endOfLine) => {
|
|
1108
|
+
const text = (carry + part).toLowerCase();
|
|
1109
|
+
const sawEnoent = lineSawEnoent || text.includes("enoent");
|
|
1110
|
+
const sawTarballData = lineSawTarballData || text.includes("tarball data");
|
|
1111
|
+
if (text.includes("invalid response body")
|
|
1112
|
+
|| text.includes("_cacache")
|
|
1113
|
+
|| (sawEnoent && text.includes("content-v2"))
|
|
1114
|
+
|| (sawTarballData && text.includes("corrupted"))
|
|
1115
|
+
|| text.includes("tar_bad_archive")
|
|
1116
|
+
|| text.includes("zlib: unexpected end of file")) matched = true;
|
|
1117
|
+
lineSawEnoent = sawEnoent;
|
|
1118
|
+
lineSawTarballData = sawTarballData;
|
|
1119
|
+
carry = text.slice(-64);
|
|
1120
|
+
if (endOfLine) {
|
|
1121
|
+
carry = "";
|
|
1122
|
+
lineSawEnoent = false;
|
|
1123
|
+
lineSawTarballData = false;
|
|
1124
|
+
}
|
|
1125
|
+
};
|
|
1126
|
+
process.stdin.on("data", (chunk) => {
|
|
1127
|
+
const parts = chunk.toString("latin1").split(/\r?\n/);
|
|
1128
|
+
parts.forEach((part, index) => scan(part, index < parts.length - 1));
|
|
1129
|
+
});
|
|
1130
|
+
process.stdin.on("end", () => { process.exitCode = matched ? 0 : 1; });
|
|
1131
|
+
process.stdin.on("error", () => { process.exitCode = 2; });
|
|
1132
|
+
'
|
|
1133
|
+
}
|
|
1134
|
+
|
|
1135
|
+
REMOTE_NPM_INSTALL_STATUS=1
|
|
1136
|
+
REMOTE_NPM_CACHE_ERROR=false
|
|
1137
|
+
run_remote_npm_install_attempt() {
|
|
1138
|
+
local registry="$1"
|
|
1139
|
+
shift
|
|
1140
|
+
local pipeline_status=()
|
|
1141
|
+
sanitize_inherited_npm_exec_env
|
|
1142
|
+
set +e
|
|
1143
|
+
"$NPM_BIN" install -g \
|
|
1144
|
+
--registry "$registry" \
|
|
1145
|
+
--cache "$NPM_CACHE_DIR" \
|
|
1146
|
+
--prefix "$NPM_GLOBAL_PREFIX" \
|
|
1147
|
+
"$@" 2>&1 | classify_remote_npm_cache_error
|
|
1148
|
+
pipeline_status=("${PIPESTATUS[@]}")
|
|
1149
|
+
set -e
|
|
1150
|
+
REMOTE_NPM_INSTALL_STATUS="${pipeline_status[0]:-1}"
|
|
1151
|
+
REMOTE_NPM_CACHE_ERROR=false
|
|
1152
|
+
if [ "${pipeline_status[1]:-2}" -eq 0 ]; then
|
|
1153
|
+
REMOTE_NPM_CACHE_ERROR=true
|
|
1154
|
+
fi
|
|
1155
|
+
return 0
|
|
1156
|
+
}
|
|
1157
|
+
|
|
1158
|
+
npm_install_global_from_registry_remote() {
|
|
1159
|
+
local registry="$1"
|
|
1160
|
+
shift
|
|
1161
|
+
finish_remote_npm_install() {
|
|
1162
|
+
trap - EXIT HUP INT TERM
|
|
1163
|
+
unset -f finish_remote_npm_install
|
|
1164
|
+
}
|
|
1165
|
+
trap finish_remote_npm_install EXIT
|
|
1166
|
+
trap 'exit 129' HUP
|
|
1167
|
+
trap 'exit 130' INT
|
|
1168
|
+
trap 'exit 143' TERM
|
|
1169
|
+
run_remote_npm_install_attempt "$registry" "$@"
|
|
1170
|
+
if [ "$REMOTE_NPM_INSTALL_STATUS" -eq 0 ]; then
|
|
1171
|
+
hash -r 2>/dev/null || true
|
|
1172
|
+
finish_remote_npm_install
|
|
1173
|
+
return 0
|
|
1174
|
+
fi
|
|
1175
|
+
|
|
1176
|
+
if [ "$REMOTE_NPM_CACHE_ERROR" != "true" ]; then
|
|
1177
|
+
finish_remote_npm_install
|
|
1178
|
+
return 1
|
|
1179
|
+
fi
|
|
1180
|
+
|
|
1181
|
+
reset_npm_cache_for_retry
|
|
1182
|
+
run_remote_npm_install_attempt "$registry" "$@"
|
|
1183
|
+
if [ "$REMOTE_NPM_INSTALL_STATUS" -ne 0 ]; then
|
|
1184
|
+
finish_remote_npm_install
|
|
1185
|
+
return 1
|
|
1186
|
+
fi
|
|
1187
|
+
hash -r 2>/dev/null || true
|
|
1188
|
+
finish_remote_npm_install
|
|
1189
|
+
}
|
|
1190
|
+
|
|
1191
|
+
npm_install_global_from_registry() {
|
|
1192
|
+
if remote_internal_helper; then
|
|
1193
|
+
npm_install_global_from_registry_remote "$@"
|
|
1194
|
+
return $?
|
|
1195
|
+
fi
|
|
1196
|
+
|
|
1197
|
+
local registry="$1"
|
|
1198
|
+
shift
|
|
1038
1199
|
local npm_log
|
|
1039
1200
|
npm_log="$(mktemp "${TMPDIR:-/tmp}/aamp-npm-install.XXXXXX")"
|
|
1040
1201
|
sanitize_inherited_npm_exec_env
|
|
1041
1202
|
if "$NPM_BIN" install -g \
|
|
1042
|
-
--registry "$
|
|
1203
|
+
--registry "$registry" \
|
|
1043
1204
|
--cache "$NPM_CACHE_DIR" \
|
|
1044
1205
|
--prefix "$NPM_GLOBAL_PREFIX" \
|
|
1045
1206
|
"$@" >"$npm_log" 2>&1; then
|
|
@@ -1057,7 +1218,7 @@ npm_install_global() {
|
|
|
1057
1218
|
npm_log="$(mktemp "${TMPDIR:-/tmp}/aamp-npm-install-retry.XXXXXX")"
|
|
1058
1219
|
sanitize_inherited_npm_exec_env
|
|
1059
1220
|
"$NPM_BIN" install -g \
|
|
1060
|
-
--registry "$
|
|
1221
|
+
--registry "$registry" \
|
|
1061
1222
|
--cache "$NPM_CACHE_DIR" \
|
|
1062
1223
|
--prefix "$NPM_GLOBAL_PREFIX" \
|
|
1063
1224
|
"$@" >"$npm_log" 2>&1 || {
|
|
@@ -1068,6 +1229,10 @@ npm_install_global() {
|
|
|
1068
1229
|
hash -r 2>/dev/null || true
|
|
1069
1230
|
}
|
|
1070
1231
|
|
|
1232
|
+
npm_install_global() {
|
|
1233
|
+
npm_install_global_from_registry "$NPM_REGISTRY" "$@"
|
|
1234
|
+
}
|
|
1235
|
+
|
|
1071
1236
|
npx_package() {
|
|
1072
1237
|
local npm_log
|
|
1073
1238
|
local status
|
|
@@ -1177,13 +1342,32 @@ npm_install_register_helper() {
|
|
|
1177
1342
|
}
|
|
1178
1343
|
}
|
|
1179
1344
|
|
|
1345
|
+
aime_internal_network_reachable() {
|
|
1346
|
+
command -v ping >/dev/null 2>&1 || return 1
|
|
1347
|
+
if is_macos; then
|
|
1348
|
+
ping -c 1 -W 1000 aime.bytedance.net >/dev/null 2>&1
|
|
1349
|
+
else
|
|
1350
|
+
ping -c 1 -W 1 aime.bytedance.net >/dev/null 2>&1
|
|
1351
|
+
fi
|
|
1352
|
+
}
|
|
1353
|
+
|
|
1180
1354
|
validate_agent_name() {
|
|
1181
1355
|
case "$1" in
|
|
1182
|
-
codex|cursor) ;;
|
|
1183
|
-
*) agent_fail "--agent must be codex or
|
|
1356
|
+
codex|cursor|coco|traex|traecli|workbuddy|workbuddy_ai|aime) ;;
|
|
1357
|
+
*) agent_fail "--agent must be codex, cursor, coco, traex, traecli, workbuddy, workbuddy_ai, or aime" ;;
|
|
1184
1358
|
esac
|
|
1185
1359
|
}
|
|
1186
1360
|
|
|
1361
|
+
ensure_agent_selection_available() {
|
|
1362
|
+
[ "$1" = "aime" ] || return 0
|
|
1363
|
+
aime_internal_network_reachable \
|
|
1364
|
+
|| agent_fail "AIME 仅在公司内网可用;当前无法 ping 通 aime.bytedance.net。"
|
|
1365
|
+
}
|
|
1366
|
+
|
|
1367
|
+
agent_display_name() {
|
|
1368
|
+
printf '%s' "$1"
|
|
1369
|
+
}
|
|
1370
|
+
|
|
1187
1371
|
read_tty_line() {
|
|
1188
1372
|
local prompt="$1"
|
|
1189
1373
|
local value
|
|
@@ -1203,6 +1387,24 @@ agent_cli_detected() {
|
|
|
1203
1387
|
cursor)
|
|
1204
1388
|
find_cursor_agent_cli >/dev/null 2>&1
|
|
1205
1389
|
;;
|
|
1390
|
+
traex)
|
|
1391
|
+
find_traex_cli >/dev/null 2>&1
|
|
1392
|
+
;;
|
|
1393
|
+
coco)
|
|
1394
|
+
find_legacy_trae_cli >/dev/null 2>&1
|
|
1395
|
+
;;
|
|
1396
|
+
traecli)
|
|
1397
|
+
find_traecode_cli >/dev/null 2>&1
|
|
1398
|
+
;;
|
|
1399
|
+
workbuddy)
|
|
1400
|
+
find_workbuddy_cli >/dev/null 2>&1
|
|
1401
|
+
;;
|
|
1402
|
+
workbuddy_ai)
|
|
1403
|
+
find_workbuddy_ai_cli >/dev/null 2>&1
|
|
1404
|
+
;;
|
|
1405
|
+
aime)
|
|
1406
|
+
aime_internal_network_reachable
|
|
1407
|
+
;;
|
|
1206
1408
|
*)
|
|
1207
1409
|
return 1
|
|
1208
1410
|
;;
|
|
@@ -1217,9 +1419,25 @@ discover_interactive_agents() {
|
|
|
1217
1419
|
if agent_cli_detected cursor; then
|
|
1218
1420
|
DETECTED_AGENTS+=("cursor")
|
|
1219
1421
|
fi
|
|
1422
|
+
if agent_cli_detected traex; then
|
|
1423
|
+
DETECTED_AGENTS+=("traex")
|
|
1424
|
+
elif agent_cli_detected coco; then
|
|
1425
|
+
DETECTED_AGENTS+=("coco")
|
|
1426
|
+
elif agent_cli_detected traecli; then
|
|
1427
|
+
DETECTED_AGENTS+=("traecli")
|
|
1428
|
+
fi
|
|
1429
|
+
if agent_cli_detected workbuddy; then
|
|
1430
|
+
DETECTED_AGENTS+=("workbuddy")
|
|
1431
|
+
fi
|
|
1432
|
+
if agent_cli_detected workbuddy_ai; then
|
|
1433
|
+
DETECTED_AGENTS+=("workbuddy_ai")
|
|
1434
|
+
fi
|
|
1435
|
+
if agent_cli_detected aime; then
|
|
1436
|
+
DETECTED_AGENTS+=("aime")
|
|
1437
|
+
fi
|
|
1220
1438
|
|
|
1221
1439
|
if [ "${#DETECTED_AGENTS[@]}" -eq 0 ]; then
|
|
1222
|
-
agent_fail "
|
|
1440
|
+
agent_fail "暂未检测到本地智能体。请先安装 Codex、Cursor、Trae CLI、WorkBuddy 或 WorkBuddy AI 后重试。"
|
|
1223
1441
|
fi
|
|
1224
1442
|
}
|
|
1225
1443
|
|
|
@@ -1238,9 +1456,9 @@ render_agent_menu() {
|
|
|
1238
1456
|
for index in "${!DETECTED_AGENTS[@]}"; do
|
|
1239
1457
|
printf '\033[2K\r' >&3
|
|
1240
1458
|
if [ "$index" -eq "$selected" ]; then
|
|
1241
|
-
printf ' > %s\n' "${DETECTED_AGENTS[$index]}" >&3
|
|
1459
|
+
printf ' > %s\n' "$(agent_display_name "${DETECTED_AGENTS[$index]}")" >&3
|
|
1242
1460
|
else
|
|
1243
|
-
printf ' %s\n' "${DETECTED_AGENTS[$index]}" >&3
|
|
1461
|
+
printf ' %s\n' "$(agent_display_name "${DETECTED_AGENTS[$index]}")" >&3
|
|
1244
1462
|
fi
|
|
1245
1463
|
done
|
|
1246
1464
|
printf '\033[2K\r使用 ↑/↓ 选择,回车确认。也可按数字键或 j/k。\n' >&3
|
|
@@ -1254,7 +1472,7 @@ select_agent_interactively() {
|
|
|
1254
1472
|
discover_interactive_agents
|
|
1255
1473
|
|
|
1256
1474
|
if ! exec 3<>/dev/tty; then
|
|
1257
|
-
agent_fail "missing --agent and no interactive terminal is available; pass --agent codex|cursor"
|
|
1475
|
+
agent_fail "missing --agent and no interactive terminal is available; pass --agent codex|cursor|coco|traex|traecli|workbuddy|workbuddy_ai|aime"
|
|
1258
1476
|
fi
|
|
1259
1477
|
|
|
1260
1478
|
tty_state="$(stty -g <&3)"
|
|
@@ -1440,7 +1658,7 @@ parse_args() {
|
|
|
1440
1658
|
fi
|
|
1441
1659
|
|
|
1442
1660
|
case "${1:-}" in
|
|
1443
|
-
install|start|list|add|remove|update|help|__discover-agents|__register-binding|__prepare-agent|__ensure-profile)
|
|
1661
|
+
install|start|list|add|remove|update|help|__discover-agents|__register-binding|__prepare-agent|__probe-profile|__ensure-profile)
|
|
1444
1662
|
AAMP_TASK_ACTION="$1"
|
|
1445
1663
|
shift
|
|
1446
1664
|
;;
|
|
@@ -1598,12 +1816,13 @@ for (const bot of bots) {
|
|
|
1598
1816
|
const profile = String(bot?.profile || "").trim();
|
|
1599
1817
|
const name = String(bot?.display_name || appId).trim();
|
|
1600
1818
|
const appSecret = String(bot?.app_secret || "").trim();
|
|
1819
|
+
const tenantBrand = bot?.tenant_brand === "lark" ? "lark" : "feishu";
|
|
1601
1820
|
if (!appId || !profile || seen.has(appId) || activeAppIds.has(appId)) continue;
|
|
1602
1821
|
if (!appSecret) {
|
|
1603
1822
|
continue;
|
|
1604
1823
|
}
|
|
1605
1824
|
seen.add(appId);
|
|
1606
|
-
console.log([appId, name, profile, appSecret].join("\t"));
|
|
1825
|
+
console.log([appId, name, profile, appSecret, tenantBrand].join("\t"));
|
|
1607
1826
|
}
|
|
1608
1827
|
'
|
|
1609
1828
|
}
|
|
@@ -1786,7 +2005,12 @@ process.exit(bots.some((bot) => String(bot?.app_id || "").trim() && String(bot?.
|
|
|
1786
2005
|
|
|
1787
2006
|
task_profile_name_for_app_id() {
|
|
1788
2007
|
local app_id="$1"
|
|
1789
|
-
|
|
2008
|
+
local tenant_brand="${2:-feishu}"
|
|
2009
|
+
case "$tenant_brand" in
|
|
2010
|
+
feishu) printf 'aamp-feishu-task-%s' "$app_id" ;;
|
|
2011
|
+
lark) printf 'aamp-feishu-task-%s-lark' "$app_id" ;;
|
|
2012
|
+
*) agent_fail "unsupported tenant brand: $tenant_brand" ;;
|
|
2013
|
+
esac
|
|
1790
2014
|
}
|
|
1791
2015
|
|
|
1792
2016
|
save_bot_config() {
|
|
@@ -1794,19 +2018,27 @@ save_bot_config() {
|
|
|
1794
2018
|
local app_id="$2"
|
|
1795
2019
|
local profile="$3"
|
|
1796
2020
|
local app_secret="${4:-}"
|
|
2021
|
+
local tenant_brand="${5:-feishu}"
|
|
1797
2022
|
mkdir -p "$(dirname "$BOT_CONFIG_FILE")"
|
|
1798
|
-
|
|
2023
|
+
case "$tenant_brand" in
|
|
2024
|
+
feishu|lark) ;;
|
|
2025
|
+
*) agent_fail "unsupported tenant brand: $tenant_brand" ;;
|
|
2026
|
+
esac
|
|
2027
|
+
BOT_CONFIG_FILE="$BOT_CONFIG_FILE" BOT_NAME="$bot_name" BOT_APP_ID="$app_id" BOT_PROFILE="$profile" BOT_APP_SECRET="$app_secret" BOT_TENANT_BRAND="$tenant_brand" FEISHU_TASK_PROFILE_DOMAINS="$FEISHU_TASK_PROFILE_DOMAINS" FEISHU_SCOPE_MANIFEST_VERSION="$FEISHU_SCOPE_MANIFEST_VERSION" FEISHU_USER_AUTH_MODE="$FEISHU_USER_AUTH_MODE" node -e '
|
|
1799
2028
|
const fs = require("fs");
|
|
1800
2029
|
const file = process.env.BOT_CONFIG_FILE;
|
|
1801
2030
|
const appSecret = String(process.env.BOT_APP_SECRET || "").trim();
|
|
1802
2031
|
const next = {
|
|
1803
2032
|
display_name: process.env.BOT_NAME || process.env.BOT_APP_ID,
|
|
1804
2033
|
app_id: process.env.BOT_APP_ID,
|
|
2034
|
+
tenant_brand: process.env.BOT_TENANT_BRAND || "feishu",
|
|
1805
2035
|
...(appSecret ? { app_secret: appSecret } : {}),
|
|
1806
2036
|
profile: process.env.BOT_PROFILE,
|
|
1807
2037
|
auth_mode: "lark-cli",
|
|
1808
2038
|
capabilities: ["im", "task"],
|
|
1809
|
-
domains: String(process.env.
|
|
2039
|
+
domains: String(process.env.FEISHU_TASK_PROFILE_DOMAINS || "task").split(",").map((item) => item.trim()).filter(Boolean),
|
|
2040
|
+
scope_manifest_version: Number(process.env.FEISHU_SCOPE_MANIFEST_VERSION || 0),
|
|
2041
|
+
user_auth_mode: process.env.FEISHU_USER_AUTH_MODE || "optional",
|
|
1810
2042
|
updated_at: new Date().toISOString(),
|
|
1811
2043
|
};
|
|
1812
2044
|
let parsed = { version: 1, profiles: [] };
|
|
@@ -2039,15 +2271,65 @@ ensure_lark_cli_min_version() {
|
|
|
2039
2271
|
select_lark_cli_bin
|
|
2040
2272
|
}
|
|
2041
2273
|
|
|
2274
|
+
feishu_scope_manifest_json() {
|
|
2275
|
+
cat <<'JSON'
|
|
2276
|
+
{"version":2,"app":{"tenant":["im:message","im:message:send_as_bot","im:message:readonly","im:resource","cardkit:card:write","task:task","task:comment","task:task:readonly","task:comment:readonly","task:attachment:read","task:attachment:write","task:comment:read","task:comment:write","task:task:read","task:task:write","task:tasklist:read","task:tasklist:write","task:custom_field:read","task:custom_field:write","task:section:read","task:section:write"],"user":["im:message","im:message:readonly","im:resource","cardkit:card:write","task:task","task:comment","task:task:readonly","task:comment:readonly","task:attachment:read","task:attachment:write","task:comment:read","task:comment:write","task:task:read","task:task:write","task:tasklist:read","task:tasklist:write","task:custom_field:read","task:custom_field:write","task:section:read","task:section:write"]},"userAuth":{"core":[],"optional":["task:task","task:comment","task:task:readonly","task:comment:readonly","task:attachment:read","task:attachment:write","task:comment:read","task:comment:write","task:task:read","task:task:write","task:tasklist:read","task:tasklist:write","task:custom_field:read","task:custom_field:write","task:section:read","task:section:write"]}}
|
|
2277
|
+
JSON
|
|
2278
|
+
}
|
|
2279
|
+
|
|
2280
|
+
initialize_feishu_scope_manifest() {
|
|
2281
|
+
local manifest_values=()
|
|
2282
|
+
local value
|
|
2283
|
+
|
|
2284
|
+
while IFS= read -r value; do
|
|
2285
|
+
manifest_values+=("$value")
|
|
2286
|
+
done < <(feishu_scope_manifest_json | node -e '
|
|
2287
|
+
const fs = require("fs");
|
|
2288
|
+
const manifest = JSON.parse(fs.readFileSync(0, "utf8"));
|
|
2289
|
+
console.log(String(manifest.version));
|
|
2290
|
+
console.log(manifest.app.tenant.join(","));
|
|
2291
|
+
console.log(manifest.app.user.join(","));
|
|
2292
|
+
console.log(manifest.userAuth.core.join(" "));
|
|
2293
|
+
console.log(manifest.userAuth.optional.join(" "));
|
|
2294
|
+
')
|
|
2295
|
+
|
|
2296
|
+
[ "${#manifest_values[@]}" -eq 5 ] || agent_fail "invalid embedded Feishu scope manifest"
|
|
2297
|
+
FEISHU_SCOPE_MANIFEST_VERSION="${FEISHU_SCOPE_MANIFEST_VERSION:-${manifest_values[0]}}"
|
|
2298
|
+
FEISHU_APP_SCOPES_TENANT="${FEISHU_APP_SCOPES_TENANT:-${manifest_values[1]}}"
|
|
2299
|
+
FEISHU_APP_SCOPES_USER="${FEISHU_APP_SCOPES_USER:-${manifest_values[2]}}"
|
|
2300
|
+
FEISHU_USER_AUTH_CORE_SCOPES="${FEISHU_USER_AUTH_CORE_SCOPES:-${manifest_values[3]}}"
|
|
2301
|
+
FEISHU_USER_AUTH_OPTIONAL_SCOPES="${FEISHU_USER_AUTH_OPTIONAL_SCOPES:-${manifest_values[4]}}"
|
|
2302
|
+
if [ -n "${FEISHU_USER_AUTH_REQUIRED_SCOPES:-}" ]; then
|
|
2303
|
+
FEISHU_USER_AUTH_CORE_SCOPES="$FEISHU_USER_AUTH_REQUIRED_SCOPES"
|
|
2304
|
+
else
|
|
2305
|
+
FEISHU_USER_AUTH_REQUIRED_SCOPES="$FEISHU_USER_AUTH_CORE_SCOPES"
|
|
2306
|
+
fi
|
|
2307
|
+
if [ -z "${FEISHU_USER_AUTH_REQUESTED_SCOPES:-}" ]; then
|
|
2308
|
+
if [ -n "${AAMP_FEISHU_USER_AUTH_REQUIRED_SCOPES_OVERRIDE:-}" ]; then
|
|
2309
|
+
FEISHU_USER_AUTH_REQUESTED_SCOPES="$FEISHU_USER_AUTH_REQUIRED_SCOPES"
|
|
2310
|
+
else
|
|
2311
|
+
FEISHU_USER_AUTH_REQUESTED_SCOPES="${FEISHU_USER_AUTH_CORE_SCOPES} ${FEISHU_USER_AUTH_OPTIONAL_SCOPES}"
|
|
2312
|
+
fi
|
|
2313
|
+
fi
|
|
2314
|
+
export FEISHU_SCOPE_MANIFEST_VERSION
|
|
2315
|
+
export FEISHU_APP_SCOPES_TENANT FEISHU_APP_SCOPES_USER
|
|
2316
|
+
export FEISHU_USER_AUTH_CORE_SCOPES FEISHU_USER_AUTH_OPTIONAL_SCOPES
|
|
2317
|
+
export FEISHU_USER_AUTH_REQUIRED_SCOPES FEISHU_USER_AUTH_REQUESTED_SCOPES
|
|
2318
|
+
}
|
|
2319
|
+
|
|
2042
2320
|
lark_cli_user_auth_satisfied() {
|
|
2043
2321
|
local profile="$1"
|
|
2322
|
+
local required_scopes="${2:-${FEISHU_USER_AUTH_REQUIRED_SCOPES:-${FEISHU_USER_AUTH_CORE_SCOPES:-}}}"
|
|
2044
2323
|
local status_json auth_check
|
|
2045
2324
|
LARK_CLI_CMD="${LARK_CLI_CMD:-lark-cli}"
|
|
2046
2325
|
|
|
2326
|
+
if [ -z "${required_scopes//[[:space:],]/}" ]; then
|
|
2327
|
+
return 0
|
|
2328
|
+
fi
|
|
2047
2329
|
status_json="$("$LARK_CLI_CMD" --profile "$profile" auth status --json 2>/dev/null)" || return 1
|
|
2048
2330
|
|
|
2049
2331
|
set +e
|
|
2050
|
-
auth_check="$(AUTH_STATUS_JSON="$status_json" FEISHU_USER_AUTH_REQUIRED_SCOPES="$
|
|
2332
|
+
auth_check="$(AUTH_STATUS_JSON="$status_json" FEISHU_USER_AUTH_REQUIRED_SCOPES="$required_scopes" FEISHU_USER_AUTH_EXCLUDES="$FEISHU_USER_AUTH_EXCLUDES" node -e '
|
|
2051
2333
|
function parseJsonOutput(value, label) {
|
|
2052
2334
|
const raw = String(value || "");
|
|
2053
2335
|
const start = raw.indexOf("{");
|
|
@@ -2088,10 +2370,76 @@ console.log("ok");
|
|
|
2088
2370
|
return 1
|
|
2089
2371
|
}
|
|
2090
2372
|
|
|
2373
|
+
write_lark_cli_auth_capability_snapshot() {
|
|
2374
|
+
local profile="$1"
|
|
2375
|
+
local status_json="{}"
|
|
2376
|
+
local state_dir="$AAMP_FEISHU_AUTH_STATE_DIR"
|
|
2377
|
+
local safe_profile state_file temp_file
|
|
2378
|
+
|
|
2379
|
+
set +e
|
|
2380
|
+
status_json="$("$LARK_CLI_CMD" --profile "$profile" auth status --json 2>/dev/null)"
|
|
2381
|
+
local status_code=$?
|
|
2382
|
+
set -e
|
|
2383
|
+
if [ "$status_code" -ne 0 ] || [ -z "$status_json" ]; then
|
|
2384
|
+
status_json="{}"
|
|
2385
|
+
fi
|
|
2386
|
+
|
|
2387
|
+
mkdir -p "$state_dir" || return 1
|
|
2388
|
+
safe_profile="$(PROFILE="$profile" node -e 'process.stdout.write(String(process.env.PROFILE || "profile").replace(/[^A-Za-z0-9._-]/g, "_"))')" || return 1
|
|
2389
|
+
state_file="$state_dir/$safe_profile.json"
|
|
2390
|
+
temp_file="$(mktemp "$state_dir/.auth-capabilities.XXXXXX")" || return 1
|
|
2391
|
+
if ! AUTH_STATUS_JSON="$status_json" \
|
|
2392
|
+
AUTH_PROFILE="$profile" \
|
|
2393
|
+
FEISHU_SCOPE_MANIFEST_VERSION="$FEISHU_SCOPE_MANIFEST_VERSION" \
|
|
2394
|
+
FEISHU_USER_AUTH_CORE_SCOPES="$FEISHU_USER_AUTH_CORE_SCOPES" \
|
|
2395
|
+
FEISHU_USER_AUTH_OPTIONAL_SCOPES="$FEISHU_USER_AUTH_OPTIONAL_SCOPES" \
|
|
2396
|
+
node -e '
|
|
2397
|
+
const raw = String(process.env.AUTH_STATUS_JSON || "{}");
|
|
2398
|
+
const start = raw.indexOf("{");
|
|
2399
|
+
let status = {};
|
|
2400
|
+
try { status = JSON.parse(start >= 0 ? raw.slice(start) : "{}"); } catch {}
|
|
2401
|
+
const user = status?.identities?.user;
|
|
2402
|
+
const usable = Boolean(user?.available) && new Set(["valid", "needs_refresh"]).has(user?.tokenStatus);
|
|
2403
|
+
const split = (value) => [...new Set(String(value || "").split(/[\s,]+/).map((item) => item.trim()).filter(Boolean))];
|
|
2404
|
+
const granted = new Set(split(user?.scope));
|
|
2405
|
+
const core = split(process.env.FEISHU_USER_AUTH_CORE_SCOPES);
|
|
2406
|
+
const optional = split(process.env.FEISHU_USER_AUTH_OPTIONAL_SCOPES);
|
|
2407
|
+
const missingCoreScopes = core.filter((scope) => !granted.has(scope));
|
|
2408
|
+
const missingOptionalScopes = optional.filter((scope) => !granted.has(scope));
|
|
2409
|
+
process.stdout.write(JSON.stringify({
|
|
2410
|
+
schemaVersion: 1,
|
|
2411
|
+
manifestVersion: Number(process.env.FEISHU_SCOPE_MANIFEST_VERSION || 0),
|
|
2412
|
+
profile: process.env.AUTH_PROFILE,
|
|
2413
|
+
tokenStatus: user?.tokenStatus || "missing",
|
|
2414
|
+
grantedScopes: [...granted],
|
|
2415
|
+
missingCoreScopes,
|
|
2416
|
+
missingOptionalScopes,
|
|
2417
|
+
capabilities: { task_user: usable && missingOptionalScopes.length === 0 },
|
|
2418
|
+
checkedAt: new Date().toISOString(),
|
|
2419
|
+
}, null, 2));
|
|
2420
|
+
' >"$temp_file"; then
|
|
2421
|
+
rm -f "$temp_file"
|
|
2422
|
+
return 1
|
|
2423
|
+
fi
|
|
2424
|
+
if ! mv "$temp_file" "$state_file"; then
|
|
2425
|
+
rm -f "$temp_file"
|
|
2426
|
+
return 1
|
|
2427
|
+
fi
|
|
2428
|
+
chmod 600 "$state_file" 2>/dev/null || true
|
|
2429
|
+
}
|
|
2430
|
+
|
|
2431
|
+
persist_lark_cli_auth_capability_snapshot() {
|
|
2432
|
+
local profile="$1"
|
|
2433
|
+
if ! write_lark_cli_auth_capability_snapshot "$profile"; then
|
|
2434
|
+
agent_log "warning: unable to persist optional user capability snapshot for profile: $profile"
|
|
2435
|
+
fi
|
|
2436
|
+
}
|
|
2437
|
+
|
|
2091
2438
|
normalize_lark_cli_auth_excludes() {
|
|
2092
|
-
EXCLUDES="$1" node -e '
|
|
2439
|
+
EXCLUDES="$1" REQUESTED_SCOPES="${2:-${FEISHU_USER_AUTH_REQUESTED_SCOPES:-}}" node -e '
|
|
2093
2440
|
const excludes = String(process.env.EXCLUDES || "").split(",").map((item) => item.trim()).filter(Boolean);
|
|
2094
|
-
|
|
2441
|
+
const requested = new Set(String(process.env.REQUESTED_SCOPES || "").split(/[\s,]+/).map((item) => item.trim()).filter(Boolean));
|
|
2442
|
+
console.log([...new Set(excludes)].filter((scope) => requested.has(scope)).join(","));
|
|
2095
2443
|
'
|
|
2096
2444
|
}
|
|
2097
2445
|
|
|
@@ -2238,12 +2586,14 @@ run_lark_cli_auth_login_with_browser_open() {
|
|
|
2238
2586
|
run_lark_cli_auth_login() {
|
|
2239
2587
|
local profile="$1"
|
|
2240
2588
|
local auth_excludes="$2"
|
|
2589
|
+
local requested_scopes="${FEISHU_USER_AUTH_REQUESTED_SCOPES:-}"
|
|
2241
2590
|
|
|
2242
|
-
|
|
2591
|
+
[ -n "${requested_scopes//[[:space:],]/}" ] || return 0
|
|
2592
|
+
auth_excludes="$(normalize_lark_cli_auth_excludes "$auth_excludes" "$requested_scopes")"
|
|
2243
2593
|
if [ -z "$auth_excludes" ]; then
|
|
2244
|
-
run_lark_cli_auth_login_with_browser_open "$LARK_CLI_CMD" --profile "$profile" auth login --
|
|
2594
|
+
run_lark_cli_auth_login_with_browser_open "$LARK_CLI_CMD" --profile "$profile" auth login --scope "$requested_scopes"
|
|
2245
2595
|
else
|
|
2246
|
-
run_lark_cli_auth_login_with_browser_open "$LARK_CLI_CMD" --profile "$profile" auth login --
|
|
2596
|
+
run_lark_cli_auth_login_with_browser_open "$LARK_CLI_CMD" --profile "$profile" auth login --scope "$requested_scopes" --exclude "$auth_excludes"
|
|
2247
2597
|
fi
|
|
2248
2598
|
}
|
|
2249
2599
|
|
|
@@ -2252,11 +2602,48 @@ ensure_lark_cli_profile() {
|
|
|
2252
2602
|
with_lark_cli_config_lock ensure_lark_cli_profile_locked "$@"
|
|
2253
2603
|
}
|
|
2254
2604
|
|
|
2605
|
+
validate_feishu_user_auth_mode() {
|
|
2606
|
+
case "$FEISHU_USER_AUTH_MODE" in
|
|
2607
|
+
optional|required|disabled) ;;
|
|
2608
|
+
*) agent_fail "FEISHU_USER_AUTH_MODE must be optional, required, or disabled" ;;
|
|
2609
|
+
esac
|
|
2610
|
+
}
|
|
2611
|
+
|
|
2612
|
+
probe_lark_cli_profile_locked() {
|
|
2613
|
+
local profile="$1"
|
|
2614
|
+
local required_scopes
|
|
2615
|
+
|
|
2616
|
+
initialize_feishu_scope_manifest
|
|
2617
|
+
validate_feishu_user_auth_mode
|
|
2618
|
+
"$LARK_CLI_CMD" profile list 2>/dev/null | grep -F "\"$profile\"" >/dev/null 2>&1 \
|
|
2619
|
+
|| return 1
|
|
2620
|
+
if [ "$FEISHU_USER_AUTH_MODE" = "disabled" ]; then
|
|
2621
|
+
persist_lark_cli_auth_capability_snapshot "$profile"
|
|
2622
|
+
return 0
|
|
2623
|
+
fi
|
|
2624
|
+
if [ "$FEISHU_USER_AUTH_MODE" = "required" ]; then
|
|
2625
|
+
required_scopes="$FEISHU_USER_AUTH_REQUESTED_SCOPES"
|
|
2626
|
+
else
|
|
2627
|
+
required_scopes="$FEISHU_USER_AUTH_CORE_SCOPES"
|
|
2628
|
+
fi
|
|
2629
|
+
lark_cli_user_auth_satisfied "$profile" "$required_scopes" || return 1
|
|
2630
|
+
persist_lark_cli_auth_capability_snapshot "$profile"
|
|
2631
|
+
}
|
|
2632
|
+
|
|
2255
2633
|
ensure_lark_cli_profile_locked() {
|
|
2256
2634
|
local app_id="$1"
|
|
2257
2635
|
local app_secret="$2"
|
|
2258
2636
|
local profile="$3"
|
|
2637
|
+
local tenant_brand="${4:-feishu}"
|
|
2259
2638
|
local auth_excludes
|
|
2639
|
+
local required_scopes
|
|
2640
|
+
|
|
2641
|
+
initialize_feishu_scope_manifest
|
|
2642
|
+
validate_feishu_user_auth_mode
|
|
2643
|
+
case "$tenant_brand" in
|
|
2644
|
+
feishu|lark) ;;
|
|
2645
|
+
*) agent_fail "unsupported tenant brand: $tenant_brand" ;;
|
|
2646
|
+
esac
|
|
2260
2647
|
|
|
2261
2648
|
if "$LARK_CLI_CMD" profile list 2>/dev/null | grep -F "\"$profile\"" >/dev/null 2>&1; then
|
|
2262
2649
|
agent_detail "lark-cli profile already exists: $profile"
|
|
@@ -2266,16 +2653,42 @@ ensure_lark_cli_profile_locked() {
|
|
|
2266
2653
|
printf '%s\n' "$app_secret" | "$LARK_CLI_CMD" profile add \
|
|
2267
2654
|
--name "$profile" \
|
|
2268
2655
|
--app-id "$app_id" \
|
|
2656
|
+
--brand "$tenant_brand" \
|
|
2269
2657
|
--app-secret-stdin
|
|
2270
2658
|
fi
|
|
2271
2659
|
|
|
2272
|
-
|
|
2660
|
+
if [ "$FEISHU_USER_AUTH_MODE" = "disabled" ]; then
|
|
2661
|
+
persist_lark_cli_auth_capability_snapshot "$profile"
|
|
2662
|
+
agent_log "Task bridge ready; optional user capabilities disabled for profile: $profile"
|
|
2663
|
+
return 0
|
|
2664
|
+
fi
|
|
2665
|
+
|
|
2273
2666
|
auth_excludes="$FEISHU_USER_AUTH_EXCLUDES"
|
|
2274
|
-
if
|
|
2275
|
-
|
|
2276
|
-
|
|
2667
|
+
if [ "$FEISHU_USER_AUTH_MODE" = "required" ]; then
|
|
2668
|
+
required_scopes="$FEISHU_USER_AUTH_REQUESTED_SCOPES"
|
|
2669
|
+
agent_detail "ensuring explicit lark-cli user auth scopes for profile: $profile"
|
|
2670
|
+
if ! lark_cli_user_auth_satisfied "$profile" "$required_scopes"; then
|
|
2671
|
+
run_lark_cli_auth_login "$profile" "$auth_excludes"
|
|
2672
|
+
lark_cli_user_auth_satisfied "$profile" "$required_scopes" \
|
|
2673
|
+
|| agent_fail "lark-cli user authorization did not grant the required explicit scopes"
|
|
2674
|
+
fi
|
|
2675
|
+
persist_lark_cli_auth_capability_snapshot "$profile"
|
|
2676
|
+
agent_detail "lark-cli user auth has the requested scopes for profile: $profile"
|
|
2677
|
+
return 0
|
|
2678
|
+
fi
|
|
2679
|
+
|
|
2680
|
+
if ! lark_cli_user_auth_satisfied "$profile" "$FEISHU_USER_AUTH_CORE_SCOPES"; then
|
|
2681
|
+
agent_detail "ensuring explicitly configured lark-cli core scopes for profile: $profile"
|
|
2277
2682
|
run_lark_cli_auth_login "$profile" "$auth_excludes"
|
|
2683
|
+
lark_cli_user_auth_satisfied "$profile" "$FEISHU_USER_AUTH_CORE_SCOPES" \
|
|
2684
|
+
|| agent_fail "lark-cli user authorization did not grant the configured core scopes"
|
|
2685
|
+
fi
|
|
2686
|
+
if lark_cli_user_auth_satisfied "$profile" "$FEISHU_USER_AUTH_OPTIONAL_SCOPES"; then
|
|
2687
|
+
agent_detail "lark-cli optional user capabilities are available for profile: $profile"
|
|
2688
|
+
else
|
|
2689
|
+
agent_log "Task bridge ready; optional user capabilities unavailable for profile: $profile"
|
|
2278
2690
|
fi
|
|
2691
|
+
persist_lark_cli_auth_capability_snapshot "$profile"
|
|
2279
2692
|
}
|
|
2280
2693
|
|
|
2281
2694
|
forget_current_bot_after_feishu_start_failure() {
|
|
@@ -2311,17 +2724,19 @@ select_existing_bot_or_create() {
|
|
|
2311
2724
|
local names=()
|
|
2312
2725
|
local profiles=()
|
|
2313
2726
|
local app_secrets=()
|
|
2727
|
+
local tenant_brands=()
|
|
2314
2728
|
local bot_labels=()
|
|
2315
|
-
local app_id name profile app_secret
|
|
2729
|
+
local app_id name profile app_secret tenant_brand
|
|
2316
2730
|
local index create_index selected
|
|
2317
2731
|
|
|
2318
2732
|
acquire_bot_selection_lock
|
|
2319
|
-
while IFS=$'\t' read -r app_id name profile app_secret; do
|
|
2733
|
+
while IFS=$'\t' read -r app_id name profile app_secret tenant_brand; do
|
|
2320
2734
|
[ -n "$app_id" ] || continue
|
|
2321
2735
|
app_ids+=("$app_id")
|
|
2322
2736
|
names+=("${name:-$app_id}")
|
|
2323
2737
|
profiles+=("$profile")
|
|
2324
2738
|
app_secrets+=("$app_secret")
|
|
2739
|
+
tenant_brands+=("${tenant_brand:-feishu}")
|
|
2325
2740
|
bot_labels+=("${name:-$app_id} ($app_id)")
|
|
2326
2741
|
done < <(load_bot_configs)
|
|
2327
2742
|
|
|
@@ -2360,11 +2775,12 @@ select_existing_bot_or_create() {
|
|
|
2360
2775
|
BOT_NAME="${names[$index]}"
|
|
2361
2776
|
LARK_CLI_PROFILE="${profiles[$index]}"
|
|
2362
2777
|
APP_SECRET="${app_secrets[$index]:-}"
|
|
2778
|
+
APP_TENANT_BRAND="${tenant_brands[$index]:-feishu}"
|
|
2363
2779
|
reserve_selected_bot "$APP_ID" "$LARK_CLI_PROFILE" "$BOT_NAME"
|
|
2364
2780
|
release_bot_selection_lock
|
|
2365
2781
|
agent_detail "using Feishu bot: $BOT_NAME ($APP_ID, profile=$LARK_CLI_PROFILE)"
|
|
2366
2782
|
agent_log "正在检查飞书授权..."
|
|
2367
|
-
ensure_lark_cli_profile "$APP_ID" "$APP_SECRET" "$LARK_CLI_PROFILE"
|
|
2783
|
+
ensure_lark_cli_profile "$APP_ID" "$APP_SECRET" "$LARK_CLI_PROFILE" "$APP_TENANT_BRAND"
|
|
2368
2784
|
}
|
|
2369
2785
|
|
|
2370
2786
|
register_feishu_app() {
|
|
@@ -2376,6 +2792,8 @@ register_feishu_app() {
|
|
|
2376
2792
|
local default_name
|
|
2377
2793
|
local bot_name
|
|
2378
2794
|
|
|
2795
|
+
initialize_feishu_scope_manifest
|
|
2796
|
+
|
|
2379
2797
|
workdir="$(mktemp -d "${TMPDIR:-/tmp}/aamp-register-feishu-app.XXXXXX")"
|
|
2380
2798
|
register_script="$workdir/register-app.mjs"
|
|
2381
2799
|
if [ -n "$AAMP_RUN_LOG_DIR" ]; then
|
|
@@ -2412,6 +2830,7 @@ const userScopes = splitList(process.env.FEISHU_APP_SCOPES_USER);
|
|
|
2412
2830
|
const tenantEvents = splitList(process.env.FEISHU_APP_EVENTS_TENANT);
|
|
2413
2831
|
const userEvents = splitList(process.env.FEISHU_APP_EVENTS_USER);
|
|
2414
2832
|
const appName = process.env.FEISHU_APP_PRESET_NAME || '飞书 CLI';
|
|
2833
|
+
let detectedTenantBrand = 'feishu';
|
|
2415
2834
|
|
|
2416
2835
|
function userLog(message) {
|
|
2417
2836
|
writeSync(5, `${message}\n`);
|
|
@@ -2464,15 +2883,24 @@ const result = await lark.registerApp({
|
|
|
2464
2883
|
},
|
|
2465
2884
|
onStatusChange(info) {
|
|
2466
2885
|
if (info.status === 'polling') return;
|
|
2886
|
+
if (info.status === 'domain_switched') detectedTenantBrand = 'lark';
|
|
2467
2887
|
console.log(`[aamp-one-click] registerApp status: ${info.status}`);
|
|
2468
2888
|
},
|
|
2469
2889
|
});
|
|
2470
2890
|
|
|
2471
|
-
|
|
2891
|
+
const reportedTenantBrand = result?.user_info?.tenant_brand;
|
|
2892
|
+
const tenantBrand = reportedTenantBrand === undefined || reportedTenantBrand === null || reportedTenantBrand === ''
|
|
2893
|
+
? detectedTenantBrand
|
|
2894
|
+
: reportedTenantBrand;
|
|
2895
|
+
const tenantBrandIsSupported = tenantBrand === 'feishu' || tenantBrand === 'lark';
|
|
2896
|
+
const openApiDomain = tenantBrand === 'lark' ? lark.Domain.Lark : lark.Domain.Feishu;
|
|
2897
|
+
|
|
2898
|
+
async function fetchRegisteredAppName(appId, appSecret, domain) {
|
|
2472
2899
|
try {
|
|
2473
2900
|
const client = new lark.Client({
|
|
2474
2901
|
appId,
|
|
2475
2902
|
appSecret,
|
|
2903
|
+
domain,
|
|
2476
2904
|
});
|
|
2477
2905
|
const response = await client.application.application.get({
|
|
2478
2906
|
path: { app_id: appId },
|
|
@@ -2486,11 +2914,14 @@ async function fetchRegisteredAppName(appId, appSecret) {
|
|
|
2486
2914
|
}
|
|
2487
2915
|
}
|
|
2488
2916
|
|
|
2489
|
-
const registeredAppName =
|
|
2917
|
+
const registeredAppName = tenantBrandIsSupported
|
|
2918
|
+
? await fetchRegisteredAppName(result.client_id, result.client_secret, openApiDomain)
|
|
2919
|
+
: '';
|
|
2490
2920
|
const resultPayload = {
|
|
2491
2921
|
app_id: result.client_id,
|
|
2492
2922
|
app_secret: result.client_secret,
|
|
2493
2923
|
app_name: registeredAppName || appName,
|
|
2924
|
+
tenant_brand: tenantBrand,
|
|
2494
2925
|
};
|
|
2495
2926
|
await import('node:fs/promises').then(({ writeFile }) => writeFile(process.env.AAMP_REGISTER_APP_RESULT_FILE, JSON.stringify(resultPayload)));
|
|
2496
2927
|
console.log(`[aamp-one-click] Feishu app registration completed: ${result.client_id}`);
|
|
@@ -2518,19 +2949,29 @@ NODE
|
|
|
2518
2949
|
APP_ID="$(node -e 'const fs = require("fs"); const data = JSON.parse(fs.readFileSync(process.argv[1], "utf8")); process.stdout.write(data.app_id || "")' "$register_result_file")"
|
|
2519
2950
|
APP_SECRET="$(node -e 'const fs = require("fs"); const data = JSON.parse(fs.readFileSync(process.argv[1], "utf8")); process.stdout.write(data.app_secret || "")' "$register_result_file")"
|
|
2520
2951
|
bot_name="$(node -e 'const fs = require("fs"); const data = JSON.parse(fs.readFileSync(process.argv[1], "utf8")); process.stdout.write(data.app_name || "")' "$register_result_file")"
|
|
2952
|
+
APP_TENANT_BRAND="$(node -e 'const fs = require("fs"); const data = JSON.parse(fs.readFileSync(process.argv[1], "utf8")); process.stdout.write(data.tenant_brand || "feishu")' "$register_result_file")"
|
|
2521
2953
|
: >"$register_result_file"
|
|
2522
2954
|
[ -n "$APP_ID" ] && [ -n "$APP_SECRET" ] || agent_fail "Feishu app registration returned incomplete credentials"
|
|
2955
|
+
case "$APP_TENANT_BRAND" in
|
|
2956
|
+
feishu|lark) ;;
|
|
2957
|
+
*) agent_fail "Feishu app registration returned unsupported tenant brand: $APP_TENANT_BRAND" ;;
|
|
2958
|
+
esac
|
|
2523
2959
|
|
|
2524
2960
|
bot_name="${bot_name:-$default_name}"
|
|
2525
2961
|
BOT_NAME="$bot_name"
|
|
2526
|
-
|
|
2527
|
-
|
|
2962
|
+
if [ "$AGENT_EXECUTION_LOCATION" = "remote" ]; then
|
|
2963
|
+
LARK_CLI_PROFILE=""
|
|
2964
|
+
else
|
|
2965
|
+
LARK_CLI_PROFILE="$(task_profile_name_for_app_id "$APP_ID" "$APP_TENANT_BRAND")"
|
|
2966
|
+
source_lark_env
|
|
2967
|
+
ensure_lark_cli_profile "$APP_ID" "$APP_SECRET" "$LARK_CLI_PROFILE" "$APP_TENANT_BRAND"
|
|
2968
|
+
fi
|
|
2528
2969
|
if [ "$AAMP_TASK_INTERNAL" = "true" ]; then
|
|
2529
2970
|
agent_detail "Feishu Bot 已授权:$BOT_NAME ($APP_ID)"
|
|
2530
2971
|
return 0
|
|
2531
2972
|
fi
|
|
2532
2973
|
acquire_bot_selection_lock
|
|
2533
|
-
save_bot_config "$bot_name" "$APP_ID" "$LARK_CLI_PROFILE" "$APP_SECRET"
|
|
2974
|
+
save_bot_config "$bot_name" "$APP_ID" "$LARK_CLI_PROFILE" "$APP_SECRET" "$APP_TENANT_BRAND"
|
|
2534
2975
|
reserve_selected_bot "$APP_ID" "$LARK_CLI_PROFILE" "$bot_name"
|
|
2535
2976
|
release_bot_selection_lock
|
|
2536
2977
|
agent_log "saved Feishu task profile config: $bot_name ($APP_ID, profile=$LARK_CLI_PROFILE)"
|
|
@@ -2678,6 +3119,338 @@ find_cursor_agent_cli() {
|
|
|
2678
3119
|
return 1
|
|
2679
3120
|
}
|
|
2680
3121
|
|
|
3122
|
+
resolve_trae_cli_candidate() {
|
|
3123
|
+
local candidate
|
|
3124
|
+
candidate="$1"
|
|
3125
|
+
[ -n "$candidate" ] || return 1
|
|
3126
|
+
if command -v "$candidate" >/dev/null 2>&1; then
|
|
3127
|
+
command -v "$candidate"
|
|
3128
|
+
return 0
|
|
3129
|
+
fi
|
|
3130
|
+
if [ -x "$candidate" ]; then
|
|
3131
|
+
printf '%s\n' "$candidate"
|
|
3132
|
+
return 0
|
|
3133
|
+
fi
|
|
3134
|
+
return 1
|
|
3135
|
+
}
|
|
3136
|
+
|
|
3137
|
+
find_traex_cli_candidates() {
|
|
3138
|
+
local candidate resolved emitted=""
|
|
3139
|
+
local candidates=()
|
|
3140
|
+
if [ -n "$TRAE_CLI_BIN" ] && [ "$(basename "$TRAE_CLI_BIN")" = "traex" ]; then candidates+=("$TRAE_CLI_BIN"); fi
|
|
3141
|
+
if [ -n "$AAMP_TRAE_CLI_BIN" ] && [ "$(basename "$AAMP_TRAE_CLI_BIN")" = "traex" ]; then candidates+=("$AAMP_TRAE_CLI_BIN"); fi
|
|
3142
|
+
candidates+=("traex")
|
|
3143
|
+
|
|
3144
|
+
for candidate in "${candidates[@]}"; do
|
|
3145
|
+
resolved="$(resolve_trae_cli_candidate "$candidate" || true)"
|
|
3146
|
+
[ -n "$resolved" ] || continue
|
|
3147
|
+
case "$emitted" in
|
|
3148
|
+
*"|$resolved|"*) continue ;;
|
|
3149
|
+
esac
|
|
3150
|
+
emitted="${emitted}|$resolved|"
|
|
3151
|
+
printf '%s\n' "$resolved"
|
|
3152
|
+
done
|
|
3153
|
+
}
|
|
3154
|
+
|
|
3155
|
+
find_coco_cli_candidates() {
|
|
3156
|
+
local candidate resolved emitted=""
|
|
3157
|
+
local candidates=()
|
|
3158
|
+
if [ -n "$TRAE_CLI_BIN" ] && [ "$(basename "$TRAE_CLI_BIN")" = "coco" ]; then candidates+=("$TRAE_CLI_BIN"); fi
|
|
3159
|
+
if [ -n "$AAMP_TRAE_CLI_BIN" ] && [ "$(basename "$AAMP_TRAE_CLI_BIN")" = "coco" ]; then candidates+=("$AAMP_TRAE_CLI_BIN"); fi
|
|
3160
|
+
candidates+=("coco")
|
|
3161
|
+
for candidate in "${candidates[@]}"; do
|
|
3162
|
+
resolved="$(resolve_trae_cli_candidate "$candidate" || true)"
|
|
3163
|
+
[ -n "$resolved" ] || continue
|
|
3164
|
+
case "$emitted" in *"|$resolved|"*) continue ;; esac
|
|
3165
|
+
emitted="${emitted}|$resolved|"
|
|
3166
|
+
printf '%s\n' "$resolved"
|
|
3167
|
+
done
|
|
3168
|
+
}
|
|
3169
|
+
|
|
3170
|
+
find_traecode_cli_candidates() {
|
|
3171
|
+
local candidate resolved emitted=""
|
|
3172
|
+
local candidates=()
|
|
3173
|
+
[ -n "$TRAECODE_CLI_BIN" ] && candidates+=("$TRAECODE_CLI_BIN")
|
|
3174
|
+
[ -n "$AAMP_TRAECODE_CLI_BIN" ] && candidates+=("$AAMP_TRAECODE_CLI_BIN")
|
|
3175
|
+
candidates+=("traecli")
|
|
3176
|
+
for candidate in "${candidates[@]}"; do
|
|
3177
|
+
resolved="$(resolve_trae_cli_candidate "$candidate" || true)"
|
|
3178
|
+
[ -n "$resolved" ] || continue
|
|
3179
|
+
case "$emitted" in *"|$resolved|"*) continue ;; esac
|
|
3180
|
+
emitted="${emitted}|$resolved|"
|
|
3181
|
+
printf '%s\n' "$resolved"
|
|
3182
|
+
done
|
|
3183
|
+
}
|
|
3184
|
+
|
|
3185
|
+
real_executable_path() {
|
|
3186
|
+
node -e 'const fs=require("fs"); try { process.stdout.write(fs.realpathSync(process.argv[1])); } catch { process.exit(1); }' "$1" 2>/dev/null
|
|
3187
|
+
}
|
|
3188
|
+
|
|
3189
|
+
find_traex_cli() {
|
|
3190
|
+
local candidate
|
|
3191
|
+
candidate="$(find_traex_cli_candidates | head -n 1)"
|
|
3192
|
+
if [ -n "$candidate" ]; then
|
|
3193
|
+
TRAE_CLI_BIN="$candidate"
|
|
3194
|
+
printf '%s\n' "$candidate"
|
|
3195
|
+
return 0
|
|
3196
|
+
fi
|
|
3197
|
+
return 1
|
|
3198
|
+
}
|
|
3199
|
+
|
|
3200
|
+
find_coco_cli() {
|
|
3201
|
+
local candidate
|
|
3202
|
+
candidate="$(find_coco_cli_candidates | head -n 1)"
|
|
3203
|
+
[ -n "$candidate" ] || return 1
|
|
3204
|
+
TRAE_CLI_BIN="$candidate"
|
|
3205
|
+
printf '%s\n' "$candidate"
|
|
3206
|
+
}
|
|
3207
|
+
|
|
3208
|
+
traecode_cli_conflicts_with_coco() {
|
|
3209
|
+
local traecli_bin="$1" coco_bin traecli_real coco_real
|
|
3210
|
+
coco_bin="$(find_coco_cli || true)"
|
|
3211
|
+
[ -n "$coco_bin" ] || return 1
|
|
3212
|
+
traecli_real="$(real_executable_path "$traecli_bin" || true)"
|
|
3213
|
+
coco_real="$(real_executable_path "$coco_bin" || true)"
|
|
3214
|
+
[ -n "$traecli_real" ] && [ "$traecli_real" = "$coco_real" ]
|
|
3215
|
+
}
|
|
3216
|
+
|
|
3217
|
+
find_traecode_cli() {
|
|
3218
|
+
local candidate explicit_candidate="" conflict_found="false"
|
|
3219
|
+
if [ -n "$TRAECODE_CLI_BIN" ]; then explicit_candidate="$TRAECODE_CLI_BIN"; fi
|
|
3220
|
+
if [ -n "$AAMP_TRAECODE_CLI_BIN" ]; then explicit_candidate="$AAMP_TRAECODE_CLI_BIN"; fi
|
|
3221
|
+
if [ -n "$explicit_candidate" ]; then
|
|
3222
|
+
case "$(basename "$explicit_candidate")" in coco|traex) return 2 ;; esac
|
|
3223
|
+
candidate="$(resolve_trae_cli_candidate "$explicit_candidate" || true)"
|
|
3224
|
+
[ -n "$candidate" ] || return 1
|
|
3225
|
+
if traecode_cli_conflicts_with_coco "$candidate"; then return 2; fi
|
|
3226
|
+
TRAECODE_CLI_BIN="$candidate"
|
|
3227
|
+
printf '%s\n' "$candidate"
|
|
3228
|
+
return 0
|
|
3229
|
+
fi
|
|
3230
|
+
while IFS= read -r candidate; do
|
|
3231
|
+
[ -n "$candidate" ] || continue
|
|
3232
|
+
if traecode_cli_conflicts_with_coco "$candidate"; then
|
|
3233
|
+
if [ -n "$explicit_candidate" ] && [ "$candidate" = "$explicit_candidate" ]; then return 2; fi
|
|
3234
|
+
conflict_found="true"
|
|
3235
|
+
continue
|
|
3236
|
+
fi
|
|
3237
|
+
TRAECODE_CLI_BIN="$candidate"
|
|
3238
|
+
printf '%s\n' "$candidate"
|
|
3239
|
+
return 0
|
|
3240
|
+
done < <(find_traecode_cli_candidates)
|
|
3241
|
+
[ "$conflict_found" != "true" ] || return 2
|
|
3242
|
+
return 1
|
|
3243
|
+
}
|
|
3244
|
+
|
|
3245
|
+
find_legacy_trae_cli() {
|
|
3246
|
+
find_coco_cli
|
|
3247
|
+
}
|
|
3248
|
+
|
|
3249
|
+
resolve_trae_cli() {
|
|
3250
|
+
case "${AGENT:-}" in
|
|
3251
|
+
traex) find_traex_cli ;;
|
|
3252
|
+
coco) find_coco_cli ;;
|
|
3253
|
+
traecli) find_traecode_cli ;;
|
|
3254
|
+
*) return 1 ;;
|
|
3255
|
+
esac
|
|
3256
|
+
}
|
|
3257
|
+
|
|
3258
|
+
find_workbuddy_cli() {
|
|
3259
|
+
is_macos || return 1
|
|
3260
|
+
[ -x "$WORKBUDDY_APP_CLI" ] || return 1
|
|
3261
|
+
printf '%s\n' "$WORKBUDDY_APP_CLI"
|
|
3262
|
+
}
|
|
3263
|
+
|
|
3264
|
+
find_workbuddy_ai_cli() {
|
|
3265
|
+
is_macos || return 1
|
|
3266
|
+
[ -x "$WORKBUDDY_AI_APP_CLI" ] || return 1
|
|
3267
|
+
printf '%s\n' "$WORKBUDDY_AI_APP_CLI"
|
|
3268
|
+
}
|
|
3269
|
+
|
|
3270
|
+
aime_acp_package_spec() {
|
|
3271
|
+
local default_spec registry spec
|
|
3272
|
+
spec="${AIME_ACP_PKG:-}"
|
|
3273
|
+
default_spec="$(aime_acp_default_package_spec)"
|
|
3274
|
+
registry="${AIME_ACP_REGISTRY:-https://bnpm.byted.org}"
|
|
3275
|
+
case "$spec" in
|
|
3276
|
+
@*/aime-acp@?*)
|
|
3277
|
+
if [ "${registry%/}" = 'https://bnpm.byted.org' ]; then
|
|
3278
|
+
printf '%s\n' "$spec"
|
|
3279
|
+
else
|
|
3280
|
+
printf '%s\n' "$default_spec"
|
|
3281
|
+
fi
|
|
3282
|
+
;;
|
|
3283
|
+
*.tgz)
|
|
3284
|
+
if [ -f "$spec" ]; then
|
|
3285
|
+
printf '%s\n' "$spec"
|
|
3286
|
+
else
|
|
3287
|
+
printf '%s\n' "$default_spec"
|
|
3288
|
+
fi
|
|
3289
|
+
;;
|
|
3290
|
+
*) printf '%s\n' "$default_spec" ;;
|
|
3291
|
+
esac
|
|
3292
|
+
}
|
|
3293
|
+
|
|
3294
|
+
aime_acp_default_package_spec() {
|
|
3295
|
+
printf '%s\n' "${AAMP_TASK_DEFAULT_AIME_ACP_PKG:-@tengchengwei/aime-acp@0.1.1-dev.1}"
|
|
3296
|
+
}
|
|
3297
|
+
|
|
3298
|
+
aime_acp_local_package_name() {
|
|
3299
|
+
local spec="$1"
|
|
3300
|
+
tar -xOzf "$spec" package/package.json 2>/dev/null | node -e '
|
|
3301
|
+
let raw = "";
|
|
3302
|
+
process.stdin.setEncoding("utf8");
|
|
3303
|
+
process.stdin.on("data", (chunk) => { raw += chunk; });
|
|
3304
|
+
process.stdin.on("end", () => {
|
|
3305
|
+
try {
|
|
3306
|
+
const value = JSON.parse(raw);
|
|
3307
|
+
if (typeof value.name !== "string" || !/^@[^/]+\/aime-acp$/.test(value.name)) process.exit(1);
|
|
3308
|
+
process.stdout.write(value.name);
|
|
3309
|
+
} catch {
|
|
3310
|
+
process.exit(1);
|
|
3311
|
+
}
|
|
3312
|
+
});
|
|
3313
|
+
'
|
|
3314
|
+
}
|
|
3315
|
+
|
|
3316
|
+
aime_acp_package_name() {
|
|
3317
|
+
local local_name spec
|
|
3318
|
+
spec="$(aime_acp_package_spec)"
|
|
3319
|
+
case "$spec" in
|
|
3320
|
+
*.tgz)
|
|
3321
|
+
local_name="$(aime_acp_local_package_name "$spec" || true)"
|
|
3322
|
+
if [ -n "$local_name" ]; then
|
|
3323
|
+
printf '%s\n' "$local_name"
|
|
3324
|
+
return 0
|
|
3325
|
+
fi
|
|
3326
|
+
spec="$(aime_acp_default_package_spec)"
|
|
3327
|
+
;;
|
|
3328
|
+
esac
|
|
3329
|
+
case "$spec" in
|
|
3330
|
+
@*/aime-acp@?*) printf '%s\n' "${spec%@*}" ;;
|
|
3331
|
+
*) return 1 ;;
|
|
3332
|
+
esac
|
|
3333
|
+
}
|
|
3334
|
+
|
|
3335
|
+
aime_acp_package_version() {
|
|
3336
|
+
local spec
|
|
3337
|
+
spec="$(aime_acp_package_spec)"
|
|
3338
|
+
case "$spec" in
|
|
3339
|
+
*.tgz) return 1 ;;
|
|
3340
|
+
*@?*) printf '%s\n' "${spec##*@}" ;;
|
|
3341
|
+
*) return 1 ;;
|
|
3342
|
+
esac
|
|
3343
|
+
}
|
|
3344
|
+
|
|
3345
|
+
aime_acp_package_spec_is_supported() {
|
|
3346
|
+
case "$(aime_acp_package_spec)" in
|
|
3347
|
+
*.tgz) return 0 ;;
|
|
3348
|
+
@*/aime-acp@?*) return 0 ;;
|
|
3349
|
+
*) return 1 ;;
|
|
3350
|
+
esac
|
|
3351
|
+
}
|
|
3352
|
+
|
|
3353
|
+
aime_acp_registry() {
|
|
3354
|
+
printf '%s\n' 'https://bnpm.byted.org'
|
|
3355
|
+
}
|
|
3356
|
+
|
|
3357
|
+
aime_acp_site() {
|
|
3358
|
+
printf '%s\n' 'cn'
|
|
3359
|
+
}
|
|
3360
|
+
|
|
3361
|
+
aime_acp_cli_path() {
|
|
3362
|
+
printf '%s/dist/bin.js\n' "$(aime_acp_package_dir)"
|
|
3363
|
+
}
|
|
3364
|
+
|
|
3365
|
+
remove_legacy_aime_acp() {
|
|
3366
|
+
local legacy_dir legacy_bin canonical_dir resolved_bin
|
|
3367
|
+
legacy_dir="$NPM_GLOBAL_PREFIX/lib/node_modules/aime-acp"
|
|
3368
|
+
legacy_bin="$NPM_GLOBAL_PREFIX/bin/aime-acp"
|
|
3369
|
+
canonical_dir="$(aime_acp_package_dir)"
|
|
3370
|
+
canonical_dir="$(node -e '
|
|
3371
|
+
const fs = require("node:fs");
|
|
3372
|
+
try { process.stdout.write(fs.realpathSync(process.argv[1])); } catch {}
|
|
3373
|
+
' "$canonical_dir")"
|
|
3374
|
+
if [ -e "$legacy_dir" ] || [ -L "$legacy_dir" ]; then
|
|
3375
|
+
rm -rf -- "$legacy_dir"
|
|
3376
|
+
fi
|
|
3377
|
+
if [ -e "$legacy_bin" ] || [ -L "$legacy_bin" ]; then
|
|
3378
|
+
resolved_bin="$(node -e '
|
|
3379
|
+
const fs = require("node:fs");
|
|
3380
|
+
const path = require("node:path");
|
|
3381
|
+
try { process.stdout.write(fs.realpathSync(process.argv[1])); } catch {}
|
|
3382
|
+
' "$legacy_bin")"
|
|
3383
|
+
if [ -n "$canonical_dir" ] && [ -n "$resolved_bin" ]; then
|
|
3384
|
+
case "$resolved_bin" in
|
|
3385
|
+
"$canonical_dir"/*) return 0 ;;
|
|
3386
|
+
esac
|
|
3387
|
+
fi
|
|
3388
|
+
rm -f -- "$legacy_bin"
|
|
3389
|
+
fi
|
|
3390
|
+
}
|
|
3391
|
+
|
|
3392
|
+
aime_acp_package_dir() {
|
|
3393
|
+
printf '%s/lib/node_modules/%s\n' "$NPM_GLOBAL_PREFIX" "$(aime_acp_package_name)"
|
|
3394
|
+
}
|
|
3395
|
+
|
|
3396
|
+
aime_acp_installed_version() {
|
|
3397
|
+
local package_json
|
|
3398
|
+
package_json="$(aime_acp_package_dir)/package.json"
|
|
3399
|
+
[ -r "$package_json" ] || return 1
|
|
3400
|
+
node -e '
|
|
3401
|
+
const fs = require("node:fs");
|
|
3402
|
+
const value = JSON.parse(fs.readFileSync(process.argv[1], "utf8"));
|
|
3403
|
+
if (typeof value.version !== "string") process.exit(1);
|
|
3404
|
+
process.stdout.write(value.version);
|
|
3405
|
+
' "$package_json"
|
|
3406
|
+
}
|
|
3407
|
+
|
|
3408
|
+
aime_acp_installed_name() {
|
|
3409
|
+
local package_json
|
|
3410
|
+
package_json="$(aime_acp_package_dir)/package.json"
|
|
3411
|
+
[ -r "$package_json" ] || return 1
|
|
3412
|
+
node -e '
|
|
3413
|
+
const fs = require("node:fs");
|
|
3414
|
+
const value = JSON.parse(fs.readFileSync(process.argv[1], "utf8"));
|
|
3415
|
+
if (typeof value.name !== "string") process.exit(1);
|
|
3416
|
+
process.stdout.write(value.name);
|
|
3417
|
+
' "$package_json"
|
|
3418
|
+
}
|
|
3419
|
+
|
|
3420
|
+
aime_acp_install_is_valid() {
|
|
3421
|
+
local installed_version installed_name
|
|
3422
|
+
[ -x "$(aime_acp_cli_path)" ] || return 1
|
|
3423
|
+
installed_name="$(aime_acp_installed_name || true)"
|
|
3424
|
+
[ "$installed_name" = "$(aime_acp_package_name)" ] || return 1
|
|
3425
|
+
installed_version="$(aime_acp_installed_version || true)"
|
|
3426
|
+
[ -n "$installed_version" ] || return 1
|
|
3427
|
+
case "$(aime_acp_package_spec)" in
|
|
3428
|
+
*.tgz) return 0 ;;
|
|
3429
|
+
*) [ "$installed_version" = "$(aime_acp_package_version)" ] ;;
|
|
3430
|
+
esac
|
|
3431
|
+
}
|
|
3432
|
+
|
|
3433
|
+
aime_acp_install_is_current() {
|
|
3434
|
+
case "$(aime_acp_package_spec)" in
|
|
3435
|
+
*.tgz) return 1 ;;
|
|
3436
|
+
*) aime_acp_install_is_valid ;;
|
|
3437
|
+
esac
|
|
3438
|
+
}
|
|
3439
|
+
|
|
3440
|
+
ensure_aime_acp_cli() {
|
|
3441
|
+
aime_acp_package_spec_is_supported \
|
|
3442
|
+
|| agent_fail "AIME_ACP_PACKAGE_INVALID: AIME ACP must use a scoped BNPM package or a local tgz."
|
|
3443
|
+
remove_legacy_aime_acp
|
|
3444
|
+
if aime_acp_install_is_current; then
|
|
3445
|
+
return 0
|
|
3446
|
+
fi
|
|
3447
|
+
agent_log "正在安装固定版本 AIME ACP 到隔离运行环境。"
|
|
3448
|
+
npm_install_global_from_registry "$(aime_acp_registry)" "$(aime_acp_package_spec)" \
|
|
3449
|
+
|| agent_fail "AIME_ACP_INSTALL_FAILED: AIME ACP installation failed. Confirm company network access and retry."
|
|
3450
|
+
aime_acp_install_is_valid \
|
|
3451
|
+
|| agent_fail "AIME_ACP_INSTALL_INVALID: AIME ACP installation validation failed."
|
|
3452
|
+
}
|
|
3453
|
+
|
|
2681
3454
|
resolve_cursor_cli_for_acp() {
|
|
2682
3455
|
command -v cursor
|
|
2683
3456
|
}
|
|
@@ -2720,6 +3493,50 @@ ensure_agent_cli() {
|
|
|
2720
3493
|
return 0
|
|
2721
3494
|
fi
|
|
2722
3495
|
|
|
3496
|
+
if [ "$AGENT" = "traex" ]; then
|
|
3497
|
+
find_traex_cli >/dev/null 2>&1 || agent_fail "未检测到 traex CLI。请先安装 Trae CLI Next(内部版)后重新运行脚本。"
|
|
3498
|
+
return 0
|
|
3499
|
+
fi
|
|
3500
|
+
|
|
3501
|
+
if [ "$AGENT" = "traecli" ]; then
|
|
3502
|
+
local traecode_status
|
|
3503
|
+
set +e
|
|
3504
|
+
find_traecode_cli >/dev/null 2>&1
|
|
3505
|
+
traecode_status=$?
|
|
3506
|
+
set -e
|
|
3507
|
+
[ "$traecode_status" -ne 2 ] || agent_fail "检测到的 traecli 属于 Trae CLI(内部版),不能作为 TraeCode CLI 启动。"
|
|
3508
|
+
[ "$traecode_status" -eq 0 ] || agent_fail "未检测到 TraeCode CLI。请先安装 traecli 后重新运行脚本。"
|
|
3509
|
+
return 0
|
|
3510
|
+
fi
|
|
3511
|
+
|
|
3512
|
+
if [ "$AGENT" = "coco" ]; then
|
|
3513
|
+
if find_traex_cli >/dev/null 2>&1; then return 0; fi
|
|
3514
|
+
if find_coco_cli >/dev/null 2>&1; then return 0; fi
|
|
3515
|
+
if find_traecode_cli >/dev/null 2>&1; then return 0; fi
|
|
3516
|
+
agent_fail "未检测到 Trae CLI(内部版)、Trae CLI Next(内部版)或 TraeCode CLI。"
|
|
3517
|
+
fi
|
|
3518
|
+
|
|
3519
|
+
if [ "$AGENT" = "workbuddy" ]; then
|
|
3520
|
+
is_macos || agent_fail "WorkBuddy 一键探测仅支持 macOS。"
|
|
3521
|
+
find_workbuddy_cli >/dev/null 2>&1 \
|
|
3522
|
+
|| agent_fail "未检测到 WorkBuddy。请确认已安装到 /Applications/WorkBuddy.app 后重新运行脚本。"
|
|
3523
|
+
return 0
|
|
3524
|
+
fi
|
|
3525
|
+
|
|
3526
|
+
if [ "$AGENT" = "workbuddy_ai" ]; then
|
|
3527
|
+
is_macos || agent_fail "WorkBuddy AI 一键探测仅支持 macOS。"
|
|
3528
|
+
find_workbuddy_ai_cli >/dev/null 2>&1 \
|
|
3529
|
+
|| agent_fail "未检测到 WorkBuddy AI CLI:${WORKBUDDY_AI_APP_CLI}。请确认该文件存在且可执行后重新运行脚本。"
|
|
3530
|
+
return 0
|
|
3531
|
+
fi
|
|
3532
|
+
|
|
3533
|
+
if [ "$AGENT" = "aime" ]; then
|
|
3534
|
+
aime_internal_network_reachable \
|
|
3535
|
+
|| agent_fail "AIME 仅在公司内网可用;当前无法 ping 通 aime.bytedance.net。"
|
|
3536
|
+
ensure_aime_acp_cli
|
|
3537
|
+
return 0
|
|
3538
|
+
fi
|
|
3539
|
+
|
|
2723
3540
|
command -v "$AGENT" >/dev/null 2>&1 || agent_fail "未检测到 $AGENT CLI。请先安装后重新运行脚本。"
|
|
2724
3541
|
}
|
|
2725
3542
|
|
|
@@ -2867,6 +3684,68 @@ resolve_latest_codex_cli_version() {
|
|
|
2867
3684
|
--prefix "$NPM_GLOBAL_PREFIX" 2>>"$ONE_CLICK_LOG" | tail -n 1 | tr -d '[:space:]'
|
|
2868
3685
|
}
|
|
2869
3686
|
|
|
3687
|
+
codex_update_cache_latest() {
|
|
3688
|
+
local current_version="$1"
|
|
3689
|
+
[ -n "${CODEX_UPDATE_CACHE_FILE:-}" ] || return 1
|
|
3690
|
+
[ -n "$current_version" ] || return 1
|
|
3691
|
+
[ -f "$CODEX_UPDATE_CACHE_FILE" ] || return 1
|
|
3692
|
+
CACHE_FILE="$CODEX_UPDATE_CACHE_FILE" \
|
|
3693
|
+
TTL="${CODEX_UPDATE_CACHE_TTL_SECONDS:-86400}" \
|
|
3694
|
+
CURRENT_VERSION="$current_version" \
|
|
3695
|
+
NPM_PACKAGE="${CODEX_NPM_PACKAGE:-@openai/codex}" \
|
|
3696
|
+
NPM_REGISTRY_VALUE="${NPM_REGISTRY:-https://registry.npmjs.org/}" \
|
|
3697
|
+
node -e '
|
|
3698
|
+
const fs = require("fs");
|
|
3699
|
+
let data;
|
|
3700
|
+
try { data = JSON.parse(fs.readFileSync(process.env.CACHE_FILE, "utf8")); } catch { process.exit(1); }
|
|
3701
|
+
const checkedAt = Number(data.checked_at || 0);
|
|
3702
|
+
const ttl = Number(process.env.TTL || 86400);
|
|
3703
|
+
const age = Math.floor(Date.now() / 1000) - checkedAt;
|
|
3704
|
+
if (data.version !== 1 || typeof data.checked_at !== "number" || !Number.isFinite(checkedAt) || checkedAt <= 0) process.exit(1);
|
|
3705
|
+
if (!Number.isFinite(ttl) || ttl <= 0 || age < 0 || age >= ttl) process.exit(1);
|
|
3706
|
+
if (typeof data.current_version !== "string" || typeof data.latest_version !== "string") process.exit(1);
|
|
3707
|
+
if (typeof data.package !== "string" || typeof data.registry !== "string") process.exit(1);
|
|
3708
|
+
if (String(data.current_version || "") !== String(process.env.CURRENT_VERSION || "")) process.exit(1);
|
|
3709
|
+
if (String(data.package || "") !== String(process.env.NPM_PACKAGE || "")) process.exit(1);
|
|
3710
|
+
if (String(data.registry || "") !== String(process.env.NPM_REGISTRY_VALUE || "")) process.exit(1);
|
|
3711
|
+
const latest = String(data.latest_version || "").trim();
|
|
3712
|
+
if (!/^v?\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/.test(latest)) process.exit(1);
|
|
3713
|
+
process.stdout.write(latest);
|
|
3714
|
+
' 2>>"${ONE_CLICK_LOG:-/dev/null}"
|
|
3715
|
+
}
|
|
3716
|
+
|
|
3717
|
+
write_codex_update_cache() {
|
|
3718
|
+
local current_version="$1"
|
|
3719
|
+
local latest_version="$2"
|
|
3720
|
+
[ -n "${CODEX_UPDATE_CACHE_FILE:-}" ] || return 0
|
|
3721
|
+
[ -n "$current_version" ] && [ -n "$latest_version" ] || return 0
|
|
3722
|
+
mkdir -p "$(dirname "$CODEX_UPDATE_CACHE_FILE")"
|
|
3723
|
+
CACHE_FILE="$CODEX_UPDATE_CACHE_FILE" \
|
|
3724
|
+
CURRENT_VERSION="$current_version" \
|
|
3725
|
+
LATEST_VERSION="$latest_version" \
|
|
3726
|
+
NPM_PACKAGE="${CODEX_NPM_PACKAGE:-@openai/codex}" \
|
|
3727
|
+
NPM_REGISTRY_VALUE="${NPM_REGISTRY:-https://registry.npmjs.org/}" \
|
|
3728
|
+
node -e '
|
|
3729
|
+
const fs = require("fs");
|
|
3730
|
+
const file = process.env.CACHE_FILE;
|
|
3731
|
+
const temporary = `${file}.tmp.${process.pid}`;
|
|
3732
|
+
const payload = {
|
|
3733
|
+
version: 1,
|
|
3734
|
+
checked_at: Math.floor(Date.now() / 1000),
|
|
3735
|
+
current_version: process.env.CURRENT_VERSION || "",
|
|
3736
|
+
latest_version: process.env.LATEST_VERSION || "",
|
|
3737
|
+
package: process.env.NPM_PACKAGE || "",
|
|
3738
|
+
registry: process.env.NPM_REGISTRY_VALUE || "",
|
|
3739
|
+
};
|
|
3740
|
+
try {
|
|
3741
|
+
fs.writeFileSync(temporary, JSON.stringify(payload, null, 2) + "\n", { mode: 0o600 });
|
|
3742
|
+
fs.renameSync(temporary, file);
|
|
3743
|
+
} finally {
|
|
3744
|
+
try { fs.unlinkSync(temporary); } catch {}
|
|
3745
|
+
}
|
|
3746
|
+
' 2>>"${ONE_CLICK_LOG:-/dev/null}" || true
|
|
3747
|
+
}
|
|
3748
|
+
|
|
2870
3749
|
codex_cli_update_available() {
|
|
2871
3750
|
CODEX_CURRENT_VERSION="$1" CODEX_LATEST_VERSION="$2" node -e '
|
|
2872
3751
|
function parse(value) {
|
|
@@ -3005,7 +3884,13 @@ ensure_codex_cli_updated() {
|
|
|
3005
3884
|
codex_bin="$(resolve_codex_cli_for_acp || true)"
|
|
3006
3885
|
[ -n "$codex_bin" ] || return 0
|
|
3007
3886
|
version_before="$(codex_cli_version_number "$codex_bin" || true)"
|
|
3008
|
-
latest_version="$(
|
|
3887
|
+
latest_version="$(codex_update_cache_latest "$version_before" || true)"
|
|
3888
|
+
if [ -n "$latest_version" ]; then
|
|
3889
|
+
agent_detail "Codex CLI update check cache is fresh: current=${version_before:-unknown} latest=$latest_version"
|
|
3890
|
+
else
|
|
3891
|
+
latest_version="$(resolve_latest_codex_cli_version || true)"
|
|
3892
|
+
write_codex_update_cache "$version_before" "$latest_version"
|
|
3893
|
+
fi
|
|
3009
3894
|
version_line="当前 Codex CLI 版本是:${version_before:-未知},最新版本是:${latest_version:-获取失败}"
|
|
3010
3895
|
write_one_click_log "[aamp-one-click] $version_line"
|
|
3011
3896
|
agent_detail "checking Codex CLI update: path=$codex_bin version=${version_before:-unknown}"
|
|
@@ -3016,7 +3901,6 @@ ensure_codex_cli_updated() {
|
|
|
3016
3901
|
comparison_status=$?
|
|
3017
3902
|
fi
|
|
3018
3903
|
if [ "$comparison_status" -eq 1 ]; then
|
|
3019
|
-
printf '%s\n' "$version_line"
|
|
3020
3904
|
agent_detail "Codex CLI is already current: current=${version_before:-unknown} latest=${latest_version:-unknown}"
|
|
3021
3905
|
return 0
|
|
3022
3906
|
fi
|
|
@@ -3105,6 +3989,142 @@ run_codex_login() {
|
|
|
3105
3989
|
return "$status"
|
|
3106
3990
|
}
|
|
3107
3991
|
|
|
3992
|
+
run_quiet_command_with_timeout() {
|
|
3993
|
+
local timeout_seconds="$1"
|
|
3994
|
+
shift
|
|
3995
|
+
node - "$timeout_seconds" "$@" <<'NODE'
|
|
3996
|
+
const { spawn } = require('node:child_process');
|
|
3997
|
+
|
|
3998
|
+
const timeoutSeconds = Number(process.argv[2] || '10');
|
|
3999
|
+
const timeoutMs = Math.max(1, Number.isFinite(timeoutSeconds) ? timeoutSeconds : 10) * 1000;
|
|
4000
|
+
const [command, ...args] = process.argv.slice(3);
|
|
4001
|
+
if (!command) process.exit(127);
|
|
4002
|
+
|
|
4003
|
+
let finished = false;
|
|
4004
|
+
let timedOut = false;
|
|
4005
|
+
const child = spawn(command, args, { stdio: ['ignore', 'ignore', 'ignore'] });
|
|
4006
|
+
const timer = setTimeout(() => {
|
|
4007
|
+
timedOut = true;
|
|
4008
|
+
child.kill('SIGTERM');
|
|
4009
|
+
setTimeout(() => child.kill('SIGKILL'), 1000).unref();
|
|
4010
|
+
}, timeoutMs);
|
|
4011
|
+
|
|
4012
|
+
child.once('error', (error) => {
|
|
4013
|
+
if (finished) return;
|
|
4014
|
+
finished = true;
|
|
4015
|
+
clearTimeout(timer);
|
|
4016
|
+
process.exit(error && error.code === 'ENOENT' ? 127 : 1);
|
|
4017
|
+
});
|
|
4018
|
+
|
|
4019
|
+
child.once('exit', (code, signal) => {
|
|
4020
|
+
if (finished) return;
|
|
4021
|
+
finished = true;
|
|
4022
|
+
clearTimeout(timer);
|
|
4023
|
+
if (timedOut) process.exit(124);
|
|
4024
|
+
if (typeof code === 'number') process.exit(code);
|
|
4025
|
+
process.exit(signal ? 1 : 0);
|
|
4026
|
+
});
|
|
4027
|
+
NODE
|
|
4028
|
+
}
|
|
4029
|
+
|
|
4030
|
+
run_trae_login_status_for_bin() {
|
|
4031
|
+
local trae_bin="$1"
|
|
4032
|
+
run_quiet_command_with_timeout "$AAMP_TRAE_LOGIN_STATUS_TIMEOUT_SECONDS" "$trae_bin" login status
|
|
4033
|
+
}
|
|
4034
|
+
|
|
4035
|
+
trae_login_status_timeout_message() {
|
|
4036
|
+
printf '%s' "traex login status 超时。请手动执行 'traex login status' 检查登录状态后重新运行脚本。"
|
|
4037
|
+
}
|
|
4038
|
+
|
|
4039
|
+
run_traex_login_status() {
|
|
4040
|
+
local trae_bin status
|
|
4041
|
+
trae_bin="$(find_traex_cli || true)"
|
|
4042
|
+
[ -n "$trae_bin" ] || return 127
|
|
4043
|
+
TRAE_CLI_BIN="$trae_bin"
|
|
4044
|
+
agent_detail "checking Trae CLI login status: $trae_bin"
|
|
4045
|
+
if run_trae_login_status_for_bin "$trae_bin"; then
|
|
4046
|
+
return 0
|
|
4047
|
+
else
|
|
4048
|
+
status=$?
|
|
4049
|
+
fi
|
|
4050
|
+
if [ "$status" -eq 124 ]; then
|
|
4051
|
+
agent_log "Trae CLI login status timed out after ${AAMP_TRAE_LOGIN_STATUS_TIMEOUT_SECONDS}s: $trae_bin"
|
|
4052
|
+
fi
|
|
4053
|
+
return "$status"
|
|
4054
|
+
}
|
|
4055
|
+
|
|
4056
|
+
run_traex_login() {
|
|
4057
|
+
local trae_bin
|
|
4058
|
+
trae_bin="$(resolve_trae_cli || true)"
|
|
4059
|
+
[ -n "$trae_bin" ] || return 127
|
|
4060
|
+
"$trae_bin" login
|
|
4061
|
+
}
|
|
4062
|
+
|
|
4063
|
+
trae_cli_is_traex() {
|
|
4064
|
+
[ -n "$TRAE_CLI_BIN" ] && [ "${TRAE_CLI_BIN##*/}" = "traex" ]
|
|
4065
|
+
}
|
|
4066
|
+
|
|
4067
|
+
confirm_trae_upgrade() {
|
|
4068
|
+
local answer
|
|
4069
|
+
printf '\n检测到 Trae CLI(内部版),飞书任务 Agent 暂不支持使用该版本建立连接。\n' >&2
|
|
4070
|
+
printf '建议升级到 Trae CLI Next(内部版)(traex)后继续。\n' >&2
|
|
4071
|
+
printf '升级过程中可自行选择是否保留 Trae CLI(内部版)。\n' >&2
|
|
4072
|
+
answer="$(read_tty_line "是否现在升级到 traex?[y/N] ")"
|
|
4073
|
+
case "$answer" in
|
|
4074
|
+
y|Y|yes|YES|Yes) return 0 ;;
|
|
4075
|
+
*) return 1 ;;
|
|
4076
|
+
esac
|
|
4077
|
+
}
|
|
4078
|
+
|
|
4079
|
+
run_traex_installer() {
|
|
4080
|
+
agent_log "正在安装/升级 traex..."
|
|
4081
|
+
curl -fsSL "$TRAEX_INSTALLER_URL" | sh
|
|
4082
|
+
}
|
|
4083
|
+
|
|
4084
|
+
maybe_upgrade_legacy_trae_cli() {
|
|
4085
|
+
if trae_cli_is_traex; then
|
|
4086
|
+
AGENT="traex"
|
|
4087
|
+
return 0
|
|
4088
|
+
fi
|
|
4089
|
+
|
|
4090
|
+
if confirm_trae_upgrade; then
|
|
4091
|
+
run_traex_installer || agent_fail "traex 安装失败。请手动执行:curl -fsSL $TRAEX_INSTALLER_URL | sh"
|
|
4092
|
+
hash -r 2>/dev/null || true
|
|
4093
|
+
TRAE_CLI_BIN=""
|
|
4094
|
+
find_traex_cli >/dev/null 2>&1 || agent_fail "traex 安装后仍未检测到。请确认 traex 在 PATH 中,然后重新运行脚本。"
|
|
4095
|
+
AGENT="traex"
|
|
4096
|
+
agent_log "已切换为 traex,继续启动。"
|
|
4097
|
+
return 0
|
|
4098
|
+
fi
|
|
4099
|
+
|
|
4100
|
+
AGENT_PREPARE_CANCELLED="true"
|
|
4101
|
+
AGENT_PREPARE_CANCEL_REASON="用户取消升级。飞书任务 Agent 暂不支持使用 Trae CLI(内部版)建立连接,本次未启动飞书任务连接。如需继续,请先安装 Trae CLI Next(内部版):curl -fsSL $TRAEX_INSTALLER_URL | sh"
|
|
4102
|
+
agent_log "已取消升级,本次未启动飞书任务连接。"
|
|
4103
|
+
}
|
|
4104
|
+
|
|
4105
|
+
ensure_traex_login() {
|
|
4106
|
+
local trae_login_status
|
|
4107
|
+
set +e
|
|
4108
|
+
run_traex_login_status
|
|
4109
|
+
trae_login_status=$?
|
|
4110
|
+
set -e
|
|
4111
|
+
if [ "$trae_login_status" -eq 124 ]; then
|
|
4112
|
+
agent_fail "$(trae_login_status_timeout_message)"
|
|
4113
|
+
fi
|
|
4114
|
+
if [ "$trae_login_status" -ne 0 ]; then
|
|
4115
|
+
agent_log "Trae CLI Next(内部版)未登录,正在启动登录流程。"
|
|
4116
|
+
run_traex_login || agent_fail "Trae CLI Next(内部版)登录失败。请先执行 'traex login' 完成登录后重新运行脚本。"
|
|
4117
|
+
set +e
|
|
4118
|
+
run_traex_login_status
|
|
4119
|
+
trae_login_status=$?
|
|
4120
|
+
set -e
|
|
4121
|
+
if [ "$trae_login_status" -eq 124 ]; then
|
|
4122
|
+
agent_fail "$(trae_login_status_timeout_message)"
|
|
4123
|
+
fi
|
|
4124
|
+
[ "$trae_login_status" -eq 0 ] || agent_fail "Trae CLI Next(内部版)仍未登录。请先执行 'traex login' 完成登录后重新运行脚本。"
|
|
4125
|
+
fi
|
|
4126
|
+
}
|
|
4127
|
+
|
|
3108
4128
|
print_cursor_gatekeeper_help() {
|
|
3109
4129
|
local cursor_bin
|
|
3110
4130
|
local cursor_real
|
|
@@ -3366,6 +4386,144 @@ ensure_codem_provider_ready() {
|
|
|
3366
4386
|
return "$status"
|
|
3367
4387
|
}
|
|
3368
4388
|
|
|
4389
|
+
traecode_readiness_helper_path() {
|
|
4390
|
+
if [ -n "$AAMP_TRAECODE_READINESS_HELPER" ]; then printf '%s\n' "$AAMP_TRAECODE_READINESS_HELPER"; return 0; fi
|
|
4391
|
+
local helper
|
|
4392
|
+
helper="$(task_agent_global_package_dir)/bin/traecode-readiness.mjs"
|
|
4393
|
+
[ -r "$helper" ] || return 1
|
|
4394
|
+
printf '%s\n' "$helper"
|
|
4395
|
+
}
|
|
4396
|
+
|
|
4397
|
+
run_traecode_check() {
|
|
4398
|
+
local action="$1" helper traecode_bin
|
|
4399
|
+
helper="$(traecode_readiness_helper_path)" || return 127
|
|
4400
|
+
traecode_bin="$(find_traecode_cli)" || return $?
|
|
4401
|
+
node "$helper" "$action" "$traecode_bin" "$AAMP_TRAECODE_CHECK_TIMEOUT_SECONDS"
|
|
4402
|
+
}
|
|
4403
|
+
|
|
4404
|
+
confirm_traecode_update() {
|
|
4405
|
+
local answer tty_path
|
|
4406
|
+
tty_path="${AAMP_TRAECODE_UPDATE_TTY:-/dev/tty}"
|
|
4407
|
+
if ! exec 6<>"$tty_path"; then return 2; fi
|
|
4408
|
+
printf '%s' '当前 TraeCode CLI 版本较旧,不支持 ACP。是否执行 `traecli update` 升级?[y/N] ' >&6
|
|
4409
|
+
if ! IFS= read -r answer <&6; then exec 6>&-; return 2; fi
|
|
4410
|
+
exec 6>&-
|
|
4411
|
+
case "$answer" in y|Y|yes|YES|Yes) return 0 ;; *) return 1 ;; esac
|
|
4412
|
+
}
|
|
4413
|
+
|
|
4414
|
+
run_traecode_update() {
|
|
4415
|
+
local traecode_bin="$1"
|
|
4416
|
+
[ -n "$traecode_bin" ] || return 127
|
|
4417
|
+
"$traecode_bin" update
|
|
4418
|
+
}
|
|
4419
|
+
|
|
4420
|
+
ensure_traecode_acp() {
|
|
4421
|
+
local probe_status confirm_status update_bin
|
|
4422
|
+
set +e; run_traecode_check probe-acp >/dev/null; probe_status=$?; set -e
|
|
4423
|
+
[ "$probe_status" -eq 0 ] && return 0
|
|
4424
|
+
[ "$probe_status" -ne 124 ] || agent_fail "TraeCode CLI ACP 能力检查超时,请稍后重试。"
|
|
4425
|
+
[ "$probe_status" -eq 3 ] || agent_fail "无法检查 TraeCode CLI 的 ACP 能力。"
|
|
4426
|
+
|
|
4427
|
+
set +e; confirm_traecode_update; confirm_status=$?; set -e
|
|
4428
|
+
if [ "$confirm_status" -eq 2 ]; then
|
|
4429
|
+
agent_fail "当前 TraeCode CLI 需要升级。请在交互式终端执行 'traecli update' 后重试。"
|
|
4430
|
+
fi
|
|
4431
|
+
if [ "$confirm_status" -ne 0 ]; then
|
|
4432
|
+
AGENT_PREPARE_CANCELLED="true"
|
|
4433
|
+
AGENT_PREPARE_CANCEL_REASON="用户取消升级 TraeCode CLI,本次未启动飞书任务连接。"
|
|
4434
|
+
return 0
|
|
4435
|
+
fi
|
|
4436
|
+
|
|
4437
|
+
update_bin="$(find_traecode_cli)" || agent_fail "升级前无法重新定位 TraeCode CLI,请手动执行 'traecli update' 后重试。"
|
|
4438
|
+
run_traecode_update "$update_bin" || agent_fail "TraeCode CLI 升级失败,请查看上方升级输出,或手动执行 'traecli update' 后重试。"
|
|
4439
|
+
hash -r 2>/dev/null || true
|
|
4440
|
+
TRAECODE_CLI_BIN=""
|
|
4441
|
+
find_traecode_cli >/dev/null 2>&1 || agent_fail "升级后仍未检测到 TraeCode CLI,请检查 PATH 后重试。"
|
|
4442
|
+
set +e; run_traecode_check probe-acp >/dev/null; probe_status=$?; set -e
|
|
4443
|
+
[ "$probe_status" -eq 0 ] || agent_fail "TraeCode CLI 升级后仍不支持 ACP,请确认升级结果后重试。"
|
|
4444
|
+
}
|
|
4445
|
+
|
|
4446
|
+
ensure_traecode_doctor() {
|
|
4447
|
+
local output doctor_status
|
|
4448
|
+
set +e; output="$(run_traecode_check doctor 2>&1)"; doctor_status=$?; set -e
|
|
4449
|
+
case "$doctor_status" in
|
|
4450
|
+
0) [ -z "$output" ] || printf 'TraeCode CLI 诊断警告:%s\n' "$output" ;;
|
|
4451
|
+
10) agent_fail "TraeCode CLI 尚未准备好。请打开 TraeCode CLI,按提示完成登录,并使用 /model 选择模型后重试。" ;;
|
|
4452
|
+
11) agent_fail "TraeCode CLI 诊断未通过:${output:-未知错误}" ;;
|
|
4453
|
+
65) agent_fail "TraeCode CLI 诊断结果无法解析,请执行 'traecli doctor --json' 检查后重试。" ;;
|
|
4454
|
+
124) agent_fail "TraeCode CLI 诊断超时,请稍后重试。" ;;
|
|
4455
|
+
*) agent_fail "TraeCode CLI 诊断执行失败:${output:-请执行 'traecli doctor --json' 检查。}" ;;
|
|
4456
|
+
esac
|
|
4457
|
+
}
|
|
4458
|
+
|
|
4459
|
+
ensure_traecode_ready() {
|
|
4460
|
+
ensure_traecode_acp
|
|
4461
|
+
[ "$AGENT_PREPARE_CANCELLED" = "true" ] && return 0
|
|
4462
|
+
ensure_traecode_doctor
|
|
4463
|
+
}
|
|
4464
|
+
|
|
4465
|
+
run_aime_auth_status() {
|
|
4466
|
+
"$(aime_acp_cli_path)" auth status --site "$(aime_acp_site)" --json
|
|
4467
|
+
}
|
|
4468
|
+
|
|
4469
|
+
run_aime_auth_login() {
|
|
4470
|
+
"$(aime_acp_cli_path)" auth login --site "$(aime_acp_site)"
|
|
4471
|
+
}
|
|
4472
|
+
|
|
4473
|
+
run_aime_doctor() {
|
|
4474
|
+
"$(aime_acp_cli_path)" doctor --site "$(aime_acp_site)" --json
|
|
4475
|
+
}
|
|
4476
|
+
|
|
4477
|
+
ensure_aime_ready() {
|
|
4478
|
+
local auth_output auth_status auth_kind login_status doctor_status
|
|
4479
|
+
set +e
|
|
4480
|
+
auth_output="$(run_aime_auth_status)"
|
|
4481
|
+
auth_status=$?
|
|
4482
|
+
set -e
|
|
4483
|
+
auth_kind="$(printf '%s' "$auth_output" | node -e '
|
|
4484
|
+
let input = "";
|
|
4485
|
+
process.stdin.setEncoding("utf8");
|
|
4486
|
+
process.stdin.on("data", (chunk) => { input += chunk; });
|
|
4487
|
+
process.stdin.on("end", () => {
|
|
4488
|
+
try {
|
|
4489
|
+
const value = JSON.parse(input.trim());
|
|
4490
|
+
if (value?.ok === true && value?.status === "authenticated") process.stdout.write("authenticated");
|
|
4491
|
+
else if (value?.ok === true && value?.status === "unauthenticated") process.stdout.write("unauthenticated");
|
|
4492
|
+
else process.stdout.write("error");
|
|
4493
|
+
} catch {
|
|
4494
|
+
process.stdout.write("error");
|
|
4495
|
+
}
|
|
4496
|
+
});
|
|
4497
|
+
')"
|
|
4498
|
+
if [ "$auth_status" -eq 0 ] && [ "$auth_kind" = "authenticated" ]; then
|
|
4499
|
+
agent_detail "AIME managed-user authentication is ready"
|
|
4500
|
+
elif [ "$auth_status" -eq 1 ] && [ "$auth_kind" = "unauthenticated" ]; then
|
|
4501
|
+
agent_log "AIME 尚未登录,正在启动独立登录流程。"
|
|
4502
|
+
set +e
|
|
4503
|
+
run_aime_auth_login
|
|
4504
|
+
login_status=$?
|
|
4505
|
+
set -e
|
|
4506
|
+
case "$login_status" in
|
|
4507
|
+
0) ;;
|
|
4508
|
+
2)
|
|
4509
|
+
agent_fail "AIME 登录仍在等待完成。请继续完成浏览器授权,或重新执行 'aime-acp auth login --site cn' 后重试。"
|
|
4510
|
+
;;
|
|
4511
|
+
*)
|
|
4512
|
+
agent_fail "AIME 登录失败。请执行 'aime-acp auth login --site cn' 后重试。"
|
|
4513
|
+
;;
|
|
4514
|
+
esac
|
|
4515
|
+
else
|
|
4516
|
+
agent_fail "AIME 认证状态检查失败。请执行 'aime-acp auth status --site cn --json' 查看安全诊断。"
|
|
4517
|
+
fi
|
|
4518
|
+
|
|
4519
|
+
set +e
|
|
4520
|
+
run_aime_doctor >/dev/null
|
|
4521
|
+
doctor_status=$?
|
|
4522
|
+
set -e
|
|
4523
|
+
[ "$doctor_status" -eq 0 ] \
|
|
4524
|
+
|| agent_fail "AIME doctor 未通过。请确认公司内网与账号状态,并执行 'aime-acp doctor --site cn --json' 查看安全诊断。"
|
|
4525
|
+
}
|
|
4526
|
+
|
|
3369
4527
|
ensure_agent_login() {
|
|
3370
4528
|
case "$AGENT" in
|
|
3371
4529
|
codex)
|
|
@@ -3386,6 +4544,35 @@ ensure_agent_login() {
|
|
|
3386
4544
|
run_cursor_login_status || agent_fail "cursor CLI 仍未登录。请先执行 'cursor login' 或 'agent login' 完成登录后重新运行脚本。"
|
|
3387
4545
|
fi
|
|
3388
4546
|
;;
|
|
4547
|
+
traex)
|
|
4548
|
+
ensure_traex_login
|
|
4549
|
+
;;
|
|
4550
|
+
traecli)
|
|
4551
|
+
ensure_traecode_ready
|
|
4552
|
+
;;
|
|
4553
|
+
coco)
|
|
4554
|
+
if find_traex_cli >/dev/null 2>&1; then
|
|
4555
|
+
AGENT="traex"
|
|
4556
|
+
ensure_traex_login
|
|
4557
|
+
elif find_coco_cli >/dev/null 2>&1; then
|
|
4558
|
+
maybe_upgrade_legacy_trae_cli
|
|
4559
|
+
if [ "$AGENT" = "traex" ]; then ensure_traex_login; fi
|
|
4560
|
+
elif find_traecode_cli >/dev/null 2>&1; then
|
|
4561
|
+
AGENT="traecli"
|
|
4562
|
+
ensure_traecode_ready
|
|
4563
|
+
else
|
|
4564
|
+
agent_fail "未检测到 Trae CLI(内部版)、Trae CLI Next(内部版)或 TraeCode CLI。"
|
|
4565
|
+
fi
|
|
4566
|
+
;;
|
|
4567
|
+
workbuddy)
|
|
4568
|
+
agent_detail "WorkBuddy authentication is managed by the desktop app"
|
|
4569
|
+
;;
|
|
4570
|
+
workbuddy_ai)
|
|
4571
|
+
agent_detail "WorkBuddy AI authentication is managed by the desktop app"
|
|
4572
|
+
;;
|
|
4573
|
+
aime)
|
|
4574
|
+
ensure_aime_ready
|
|
4575
|
+
;;
|
|
3389
4576
|
codem)
|
|
3390
4577
|
ensure_codem_local_bin_on_path
|
|
3391
4578
|
codem --version >/dev/null
|
|
@@ -3467,8 +4654,69 @@ resolve_codex_cli_for_acp() {
|
|
|
3467
4654
|
return 1
|
|
3468
4655
|
}
|
|
3469
4656
|
|
|
4657
|
+
acp_command_word() {
|
|
4658
|
+
local value="$1" single_quote_escape
|
|
4659
|
+
case "$value" in *$'\n'*|*$'\r'*) return 1 ;; esac
|
|
4660
|
+
single_quote_escape="'\"'\"'"
|
|
4661
|
+
value="${value//\'/$single_quote_escape}"
|
|
4662
|
+
printf "'%s'" "$value"
|
|
4663
|
+
}
|
|
4664
|
+
|
|
3470
4665
|
build_acp_agent_command() {
|
|
3471
4666
|
ACP_AGENT_COMMAND="$AGENT"
|
|
4667
|
+
if [ "$AGENT" = "workbuddy" ]; then
|
|
4668
|
+
local workbuddy_bin workbuddy_config_dir_word
|
|
4669
|
+
workbuddy_bin="$(find_workbuddy_cli)" \
|
|
4670
|
+
|| agent_fail "WorkBuddy 不可用。请确认已安装到 /Applications/WorkBuddy.app。"
|
|
4671
|
+
workbuddy_config_dir_word="$(acp_command_word "$HOME/.workbuddy")" \
|
|
4672
|
+
|| agent_fail "WorkBuddy 配置目录包含不受支持的换行符。"
|
|
4673
|
+
ACP_AGENT_COMMAND="env CODEBUDDY_CONFIG_DIR=$workbuddy_config_dir_word CODEBUDDY_SKIP_BUILTIN_MARKETPLACE=1 $workbuddy_bin --acp"
|
|
4674
|
+
agent_detail "using native WorkBuddy ACP command: $ACP_AGENT_COMMAND"
|
|
4675
|
+
return 0
|
|
4676
|
+
fi
|
|
4677
|
+
|
|
4678
|
+
if [ "$AGENT" = "workbuddy_ai" ]; then
|
|
4679
|
+
local workbuddy_ai_bin workbuddy_ai_word workbuddy_ai_config_dir_word
|
|
4680
|
+
workbuddy_ai_bin="$(find_workbuddy_ai_cli)" \
|
|
4681
|
+
|| agent_fail "WorkBuddy AI CLI 不可用:${WORKBUDDY_AI_APP_CLI}。请确认该文件存在且可执行。"
|
|
4682
|
+
workbuddy_ai_word="$(acp_command_word "$workbuddy_ai_bin")" \
|
|
4683
|
+
|| agent_fail "WorkBuddy AI 路径包含不受支持的换行符。"
|
|
4684
|
+
workbuddy_ai_config_dir_word="$(acp_command_word "$HOME/.workbuddy-ai")" \
|
|
4685
|
+
|| agent_fail "WorkBuddy AI 配置目录包含不受支持的换行符。"
|
|
4686
|
+
ACP_AGENT_COMMAND="env CODEBUDDY_CONFIG_DIR=$workbuddy_ai_config_dir_word CODEBUDDY_SKIP_BUILTIN_MARKETPLACE=1 $workbuddy_ai_word --acp"
|
|
4687
|
+
agent_detail "using native WorkBuddy AI ACP command: $ACP_AGENT_COMMAND"
|
|
4688
|
+
return 0
|
|
4689
|
+
fi
|
|
4690
|
+
|
|
4691
|
+
if [ "$AGENT" = "aime" ]; then
|
|
4692
|
+
local aime_bin aime_word
|
|
4693
|
+
aime_bin="$(aime_acp_cli_path)"
|
|
4694
|
+
[ -x "$aime_bin" ] || agent_fail "AIME_ACP_UNAVAILABLE: AIME ACP executable is unavailable after preparation."
|
|
4695
|
+
aime_word="$(acp_command_word "$aime_bin")" \
|
|
4696
|
+
|| agent_fail "AIME_ACP_PATH_INVALID: AIME ACP executable path is invalid."
|
|
4697
|
+
ACP_AGENT_COMMAND="$aime_word --site $(aime_acp_site)"
|
|
4698
|
+
agent_detail "AIME ACP configured for site $(aime_acp_site)"
|
|
4699
|
+
return 0
|
|
4700
|
+
fi
|
|
4701
|
+
|
|
4702
|
+
if [ "$AGENT" = "traecli" ]; then
|
|
4703
|
+
local traecode_bin traecode_word
|
|
4704
|
+
traecode_bin="$(find_traecode_cli)" || agent_fail "TraeCode CLI 不可用,无法启动 ACP 服务。"
|
|
4705
|
+
traecode_word="$(acp_command_word "$traecode_bin")" \
|
|
4706
|
+
|| agent_fail "TraeCode CLI 路径包含不受支持的换行符。"
|
|
4707
|
+
ACP_AGENT_COMMAND="$traecode_word acp serve"
|
|
4708
|
+
agent_detail "using native TraeCode ACP command: $ACP_AGENT_COMMAND"
|
|
4709
|
+
return 0
|
|
4710
|
+
fi
|
|
4711
|
+
|
|
4712
|
+
if [ "$AGENT" = "coco" ] || [ "$AGENT" = "traex" ]; then
|
|
4713
|
+
local trae_bin
|
|
4714
|
+
trae_bin="$(find_traex_cli)" || agent_fail "Trae CLI Next(内部版)(traex)不可用,无法启动飞书任务所需的 ACP 服务。"
|
|
4715
|
+
ACP_AGENT_COMMAND="$trae_bin acp serve"
|
|
4716
|
+
agent_detail "using native Trae ACP command: $ACP_AGENT_COMMAND"
|
|
4717
|
+
return 0
|
|
4718
|
+
fi
|
|
4719
|
+
|
|
3472
4720
|
if [ "$AGENT" != "codex" ]; then
|
|
3473
4721
|
return 0
|
|
3474
4722
|
fi
|
|
@@ -3689,6 +4937,22 @@ run_internal_discover_agents() {
|
|
|
3689
4937
|
if agent_cli_detected cursor; then
|
|
3690
4938
|
agents+=("cursor")
|
|
3691
4939
|
fi
|
|
4940
|
+
if agent_cli_detected traex; then
|
|
4941
|
+
agents+=("traex")
|
|
4942
|
+
elif agent_cli_detected coco; then
|
|
4943
|
+
agents+=("coco")
|
|
4944
|
+
elif agent_cli_detected traecli; then
|
|
4945
|
+
agents+=("traecli")
|
|
4946
|
+
fi
|
|
4947
|
+
if agent_cli_detected workbuddy; then
|
|
4948
|
+
agents+=("workbuddy")
|
|
4949
|
+
fi
|
|
4950
|
+
if agent_cli_detected workbuddy_ai; then
|
|
4951
|
+
agents+=("workbuddy_ai")
|
|
4952
|
+
fi
|
|
4953
|
+
if agent_cli_detected aime; then
|
|
4954
|
+
agents+=("aime")
|
|
4955
|
+
fi
|
|
3692
4956
|
local joined=""
|
|
3693
4957
|
if [ "${#agents[@]}" -gt 0 ]; then
|
|
3694
4958
|
joined="$(IFS=,; printf '%s' "${agents[*]}")"
|
|
@@ -3702,47 +4966,98 @@ process.stdout.write(JSON.stringify({ agents }));
|
|
|
3702
4966
|
prepare_internal_agent_environment() {
|
|
3703
4967
|
[ -n "$AGENT" ] || agent_fail "internal Agent preparation requires --agent"
|
|
3704
4968
|
validate_agent_name "$AGENT"
|
|
3705
|
-
|
|
4969
|
+
ensure_agent_selection_available "$AGENT"
|
|
4970
|
+
load_agent_metadata
|
|
4971
|
+
if [ "$AGENT_EXECUTION_LOCATION" = "local" ]; then
|
|
4972
|
+
source_lark_env
|
|
4973
|
+
fi
|
|
3706
4974
|
ensure_agent_cli
|
|
3707
4975
|
}
|
|
3708
4976
|
|
|
3709
4977
|
run_internal_register_binding() {
|
|
3710
4978
|
[ -n "$AGENT" ] || agent_fail "internal Bot registration requires --agent"
|
|
3711
4979
|
validate_agent_name "$AGENT"
|
|
3712
|
-
|
|
4980
|
+
ensure_agent_selection_available "$AGENT"
|
|
4981
|
+
load_agent_metadata
|
|
3713
4982
|
register_feishu_app
|
|
3714
|
-
|
|
4983
|
+
if [ "$AGENT_EXECUTION_LOCATION" = "remote" ]; then
|
|
4984
|
+
emit_internal_result "{\"app_id\":\"$(json_escape "$APP_ID")\",\"app_secret\":\"$(json_escape "$APP_SECRET")\",\"display_name\":\"$(json_escape "$BOT_NAME")\",\"tenant_brand\":\"$(json_escape "$APP_TENANT_BRAND")\",\"auth_mode\":\"app-secret\"}"
|
|
4985
|
+
else
|
|
4986
|
+
emit_internal_result "{\"app_id\":\"$(json_escape "$APP_ID")\",\"app_secret\":\"$(json_escape "$APP_SECRET")\",\"display_name\":\"$(json_escape "$BOT_NAME")\",\"tenant_brand\":\"$(json_escape "$APP_TENANT_BRAND")\",\"lark_cli_profile\":\"$(json_escape "$LARK_CLI_PROFILE")\",\"auth_mode\":\"lark-cli\"}"
|
|
4987
|
+
fi
|
|
3715
4988
|
}
|
|
3716
4989
|
|
|
3717
4990
|
run_internal_prepare_agent() {
|
|
3718
4991
|
prepare_internal_agent_environment
|
|
3719
4992
|
ensure_codex_cli_updated
|
|
3720
4993
|
ensure_agent_login
|
|
4994
|
+
if [ "$AGENT_PREPARE_CANCELLED" = "true" ]; then
|
|
4995
|
+
emit_internal_result "{\"cancelled\":true,\"agent_type\":\"$(json_escape "$AGENT")\",\"reason\":\"$(json_escape "$AGENT_PREPARE_CANCEL_REASON")\"}"
|
|
4996
|
+
return 0
|
|
4997
|
+
fi
|
|
3721
4998
|
maybe_mock_fail "agent-login"
|
|
3722
4999
|
ensure_acpx
|
|
3723
5000
|
build_acp_agent_command
|
|
3724
|
-
|
|
5001
|
+
if [ "$AGENT_EXECUTION_LOCATION" = "remote" ]; then
|
|
5002
|
+
emit_internal_result "{\"agent_type\":\"$(json_escape "$AGENT")\",\"acp_command\":\"$(json_escape "$ACP_AGENT_COMMAND")\"}"
|
|
5003
|
+
else
|
|
5004
|
+
emit_internal_result "{\"agent_type\":\"$(json_escape "$AGENT")\",\"acp_command\":\"$(json_escape "$ACP_AGENT_COMMAND")\",\"lark_cli_config_dir\":\"$(json_escape "${LARKSUITE_CLI_CONFIG_DIR:-}")\"}"
|
|
5005
|
+
fi
|
|
5006
|
+
}
|
|
5007
|
+
|
|
5008
|
+
run_internal_probe_profile() {
|
|
5009
|
+
AAMP_TASK_INTERNAL_BINDING_JSON=""
|
|
5010
|
+
IFS= read -r AAMP_TASK_INTERNAL_BINDING_JSON <&"$AAMP_TASK_INTERNAL_INPUT_FD" || true
|
|
5011
|
+
[ -n "$AAMP_TASK_INTERNAL_BINDING_JSON" ] || agent_fail "missing internal binding payload"
|
|
5012
|
+
AGENT="$(binding_json_field agent_type)"
|
|
5013
|
+
validate_agent_name "$AGENT"
|
|
5014
|
+
load_agent_metadata
|
|
5015
|
+
[ "$AGENT_EXECUTION_LOCATION" != "remote" ] || agent_fail "remote bindings do not use lark-cli profiles"
|
|
5016
|
+
APP_ID="$(binding_json_field bot.app_id)"
|
|
5017
|
+
LARK_CLI_PROFILE="$(binding_json_field bot.lark_cli_profile)"
|
|
5018
|
+
[ -n "$APP_ID" ] && [ -n "$LARK_CLI_PROFILE" ] || agent_fail "binding is missing Feishu app or profile"
|
|
5019
|
+
AAMP_TASK_INTERNAL_BINDING_JSON=""
|
|
5020
|
+
unset HTTPS_PROXY https_proxy HTTP_PROXY http_proxy ALL_PROXY all_proxy
|
|
5021
|
+
export LARKSUITE_CLI_CONFIG_DIR="$AAMP_LARK_CLI_CONFIG_DIR"
|
|
5022
|
+
unset LARK_CLI_NO_PROXY
|
|
5023
|
+
if ! select_lark_cli_bin_from_candidates; then
|
|
5024
|
+
emit_internal_result '{"ready":false}'
|
|
5025
|
+
return 0
|
|
5026
|
+
fi
|
|
5027
|
+
if with_lark_cli_config_lock probe_lark_cli_profile_locked "$LARK_CLI_PROFILE"; then
|
|
5028
|
+
emit_internal_result "{\"ready\":true,\"lark_cli_bin\":\"$(json_escape "$LARK_CLI_CMD")\",\"lark_cli_config_dir\":\"$(json_escape "${LARKSUITE_CLI_CONFIG_DIR:-}")\"}"
|
|
5029
|
+
else
|
|
5030
|
+
emit_internal_result '{"ready":false}'
|
|
5031
|
+
fi
|
|
3725
5032
|
}
|
|
3726
5033
|
|
|
3727
5034
|
run_internal_ensure_profile() {
|
|
3728
5035
|
AAMP_TASK_INTERNAL_BINDING_JSON=""
|
|
3729
5036
|
IFS= read -r AAMP_TASK_INTERNAL_BINDING_JSON <&"$AAMP_TASK_INTERNAL_INPUT_FD" || true
|
|
3730
5037
|
[ -n "$AAMP_TASK_INTERNAL_BINDING_JSON" ] || agent_fail "missing internal binding payload"
|
|
5038
|
+
AGENT="$(binding_json_field agent_type)"
|
|
5039
|
+
validate_agent_name "$AGENT"
|
|
5040
|
+
load_agent_metadata
|
|
5041
|
+
[ "$AGENT_EXECUTION_LOCATION" != "remote" ] || agent_fail "remote bindings do not use lark-cli profiles"
|
|
3731
5042
|
APP_ID="$(binding_json_field bot.app_id)"
|
|
3732
5043
|
APP_SECRET="$(binding_json_field bot.app_secret)"
|
|
3733
5044
|
BOT_NAME="$(binding_json_field bot.display_name)"
|
|
5045
|
+
APP_TENANT_BRAND="$(binding_json_field bot.tenant_brand)"
|
|
5046
|
+
APP_TENANT_BRAND="${APP_TENANT_BRAND:-feishu}"
|
|
3734
5047
|
LARK_CLI_PROFILE="$(binding_json_field bot.lark_cli_profile)"
|
|
3735
5048
|
[ -n "$APP_ID" ] && [ -n "$APP_SECRET" ] && [ -n "$LARK_CLI_PROFILE" ] || agent_fail "binding is missing Feishu credentials or profile"
|
|
3736
5049
|
AAMP_TASK_INTERNAL_BINDING_JSON=""
|
|
3737
5050
|
source_lark_env
|
|
3738
|
-
ensure_lark_cli_profile "$APP_ID" "$APP_SECRET" "$LARK_CLI_PROFILE"
|
|
5051
|
+
ensure_lark_cli_profile "$APP_ID" "$APP_SECRET" "$LARK_CLI_PROFILE" "$APP_TENANT_BRAND"
|
|
3739
5052
|
APP_SECRET=""
|
|
3740
5053
|
emit_internal_result "{\"lark_cli_bin\":\"$(json_escape "$LARK_CLI_CMD")\",\"lark_cli_config_dir\":\"$(json_escape "${LARKSUITE_CLI_CONFIG_DIR:-}")\"}"
|
|
3741
5054
|
}
|
|
3742
5055
|
|
|
3743
5056
|
run_internal_action() {
|
|
3744
5057
|
AAMP_TASK_INTERNAL="true"
|
|
3745
|
-
|
|
5058
|
+
if [ "$AAMP_TASK_ACTION" != "__probe-profile" ]; then
|
|
5059
|
+
ensure_node_toolchain
|
|
5060
|
+
fi
|
|
3746
5061
|
case "$AAMP_TASK_ACTION" in
|
|
3747
5062
|
__discover-agents)
|
|
3748
5063
|
run_internal_discover_agents
|
|
@@ -3753,6 +5068,9 @@ run_internal_action() {
|
|
|
3753
5068
|
__prepare-agent)
|
|
3754
5069
|
run_internal_prepare_agent
|
|
3755
5070
|
;;
|
|
5071
|
+
__probe-profile)
|
|
5072
|
+
run_internal_probe_profile
|
|
5073
|
+
;;
|
|
3756
5074
|
__ensure-profile)
|
|
3757
5075
|
run_internal_ensure_profile
|
|
3758
5076
|
;;
|
|
@@ -3766,6 +5084,92 @@ task_agent_controller_path() {
|
|
|
3766
5084
|
printf '%s/bin/feishu-task-agent-controller.mjs\n' "$(task_agent_global_package_dir)"
|
|
3767
5085
|
}
|
|
3768
5086
|
|
|
5087
|
+
task_agent_metadata_path() {
|
|
5088
|
+
printf '%s/bin/agent-metadata.mjs\n' "$(task_agent_global_package_dir)"
|
|
5089
|
+
}
|
|
5090
|
+
|
|
5091
|
+
local_package_override_is_supported() {
|
|
5092
|
+
local spec local_path
|
|
5093
|
+
spec="${1:-}"
|
|
5094
|
+
case "$spec" in
|
|
5095
|
+
file:*)
|
|
5096
|
+
local_path="${spec#file:}"
|
|
5097
|
+
[ -n "$local_path" ] && [ -d "$local_path" ]
|
|
5098
|
+
;;
|
|
5099
|
+
*.tgz) [ -f "$spec" ] ;;
|
|
5100
|
+
*) return 1 ;;
|
|
5101
|
+
esac
|
|
5102
|
+
}
|
|
5103
|
+
|
|
5104
|
+
aime_local_package_override_path() {
|
|
5105
|
+
local directory filename spec
|
|
5106
|
+
spec="${1:-}"
|
|
5107
|
+
case "$spec" in
|
|
5108
|
+
-*|file:*|*://*) return 1 ;;
|
|
5109
|
+
esac
|
|
5110
|
+
if [[ "$spec" =~ (^|@)[[:alpha:]][[:alnum:]+.-]*: ]]; then
|
|
5111
|
+
return 1
|
|
5112
|
+
fi
|
|
5113
|
+
case "$spec" in
|
|
5114
|
+
*.tgz) [ -f "$spec" ] || return 1 ;;
|
|
5115
|
+
*) return 1 ;;
|
|
5116
|
+
esac
|
|
5117
|
+
case "$spec" in
|
|
5118
|
+
*/*)
|
|
5119
|
+
directory="${spec%/*}"
|
|
5120
|
+
filename="${spec##*/}"
|
|
5121
|
+
[ -n "$directory" ] || directory="/"
|
|
5122
|
+
;;
|
|
5123
|
+
*)
|
|
5124
|
+
directory="."
|
|
5125
|
+
filename="$spec"
|
|
5126
|
+
;;
|
|
5127
|
+
esac
|
|
5128
|
+
directory="$(cd -P -- "$directory" 2>/dev/null && pwd -P)" || return 1
|
|
5129
|
+
printf '%s/%s\n' "$directory" "$filename"
|
|
5130
|
+
}
|
|
5131
|
+
|
|
5132
|
+
apply_task_agent_package_override_policy() {
|
|
5133
|
+
local aime_override_path
|
|
5134
|
+
ACP_BRIDGE_PKG="$AAMP_TASK_DEFAULT_ACP_BRIDGE_PKG"
|
|
5135
|
+
FEISHU_BRIDGE_PKG="$AAMP_TASK_DEFAULT_FEISHU_BRIDGE_PKG"
|
|
5136
|
+
AIME_ACP_PKG="$AAMP_TASK_DEFAULT_AIME_ACP_PKG"
|
|
5137
|
+
[ "$AAMP_TASK_ALLOW_PACKAGE_OVERRIDES" = "true" ] || return 0
|
|
5138
|
+
|
|
5139
|
+
if [ -n "$AAMP_TASK_REQUESTED_ACP_BRIDGE_PKG" ]; then
|
|
5140
|
+
local_package_override_is_supported "$AAMP_TASK_REQUESTED_ACP_BRIDGE_PKG" \
|
|
5141
|
+
|| agent_fail "Local ACP Bridge package override is invalid."
|
|
5142
|
+
ACP_BRIDGE_PKG="$AAMP_TASK_REQUESTED_ACP_BRIDGE_PKG"
|
|
5143
|
+
fi
|
|
5144
|
+
if [ -n "$AAMP_TASK_REQUESTED_FEISHU_BRIDGE_PKG" ]; then
|
|
5145
|
+
local_package_override_is_supported "$AAMP_TASK_REQUESTED_FEISHU_BRIDGE_PKG" \
|
|
5146
|
+
|| agent_fail "Local Feishu Bridge package override is invalid."
|
|
5147
|
+
FEISHU_BRIDGE_PKG="$AAMP_TASK_REQUESTED_FEISHU_BRIDGE_PKG"
|
|
5148
|
+
fi
|
|
5149
|
+
if [ -n "$AAMP_TASK_REQUESTED_AIME_ACP_PKG" ]; then
|
|
5150
|
+
aime_override_path="$(aime_local_package_override_path "$AAMP_TASK_REQUESTED_AIME_ACP_PKG")" \
|
|
5151
|
+
|| agent_fail "AIME_ACP_PACKAGE_OVERRIDE_INVALID: AIME ACP package override must be an existing local .tgz file."
|
|
5152
|
+
AAMP_TASK_REQUESTED_AIME_ACP_PKG="$aime_override_path"
|
|
5153
|
+
AIME_ACP_PKG="$aime_override_path"
|
|
5154
|
+
fi
|
|
5155
|
+
}
|
|
5156
|
+
|
|
5157
|
+
load_agent_metadata() {
|
|
5158
|
+
local metadata_path metadata_json
|
|
5159
|
+
metadata_path="$(task_agent_metadata_path)"
|
|
5160
|
+
[ -r "$metadata_path" ] || agent_fail "Task Agent metadata is missing: $metadata_path"
|
|
5161
|
+
metadata_json="$(node "$metadata_path" --json "$AGENT")" \
|
|
5162
|
+
|| agent_fail "failed to resolve Task Agent metadata for $AGENT"
|
|
5163
|
+
AGENT_EXECUTION_LOCATION="$(node -e 'const value=JSON.parse(process.argv[1]);process.stdout.write(value.executionLocation)' "$metadata_json")"
|
|
5164
|
+
AGENT_ATTACHMENT_POLICY="$(node -e 'const value=JSON.parse(process.argv[1]);process.stdout.write(value.attachmentPolicy || "")' "$metadata_json")"
|
|
5165
|
+
AGENT_TASK_DISPATCH_CONCURRENCY="$(node -e 'const value=JSON.parse(process.argv[1]);process.stdout.write(value.taskDispatchConcurrency ? String(value.taskDispatchConcurrency) : "")' "$metadata_json")"
|
|
5166
|
+
if [ -n "$AAMP_TASK_INTERNAL_EXECUTION_LOCATION" ] \
|
|
5167
|
+
&& [ "$AAMP_TASK_INTERNAL_EXECUTION_LOCATION" != "$AGENT_EXECUTION_LOCATION" ]; then
|
|
5168
|
+
agent_fail "Task Agent execution metadata mismatch"
|
|
5169
|
+
fi
|
|
5170
|
+
AAMP_TASK_INTERNAL_EXECUTION_LOCATION="$AGENT_EXECUTION_LOCATION"
|
|
5171
|
+
}
|
|
5172
|
+
|
|
3769
5173
|
run_task_agent_controller() {
|
|
3770
5174
|
local controller bootstrap_path install_command
|
|
3771
5175
|
controller="$(task_agent_controller_path)"
|
|
@@ -3778,6 +5182,17 @@ run_task_agent_controller() {
|
|
|
3778
5182
|
export AAMP_TASK_NPX_BIN="$NPX_BIN"
|
|
3779
5183
|
export AAMP_TASK_ACP_BRIDGE_PKG="$ACP_BRIDGE_PKG"
|
|
3780
5184
|
export AAMP_TASK_FEISHU_BRIDGE_PKG="$FEISHU_BRIDGE_PKG"
|
|
5185
|
+
export AAMP_TASK_AIME_ACP_PKG="$AIME_ACP_PKG"
|
|
5186
|
+
export AAMP_TASK_ALLOW_PACKAGE_OVERRIDES
|
|
5187
|
+
if [ "$AAMP_TASK_ALLOW_PACKAGE_OVERRIDES" != "true" ]; then
|
|
5188
|
+
AAMP_TASK_REQUESTED_ACP_BRIDGE_PKG=""
|
|
5189
|
+
AAMP_TASK_REQUESTED_FEISHU_BRIDGE_PKG=""
|
|
5190
|
+
AAMP_TASK_REQUESTED_AIME_ACP_PKG=""
|
|
5191
|
+
fi
|
|
5192
|
+
export AAMP_TASK_PACKAGE_OVERRIDES_RESOLVED=true
|
|
5193
|
+
export AAMP_TASK_REQUESTED_ACP_BRIDGE_PKG
|
|
5194
|
+
export AAMP_TASK_REQUESTED_FEISHU_BRIDGE_PKG
|
|
5195
|
+
export AAMP_TASK_REQUESTED_AIME_ACP_PKG
|
|
3781
5196
|
export AAMP_TASK_CODEX_ACP_PKG="$CODEX_ACP_PKG"
|
|
3782
5197
|
export AAMP_TASK_AGENT_VERSION
|
|
3783
5198
|
export AAMP_TASK_DEFAULT_AGENT="$AGENT"
|
|
@@ -3835,13 +5250,19 @@ main() {
|
|
|
3835
5250
|
return 0
|
|
3836
5251
|
fi
|
|
3837
5252
|
|
|
5253
|
+
apply_task_agent_package_override_policy
|
|
5254
|
+
|
|
3838
5255
|
case "$AAMP_TASK_ACTION" in
|
|
3839
|
-
__discover-agents|__register-binding|__prepare-agent|__ensure-profile)
|
|
5256
|
+
__discover-agents|__register-binding|__prepare-agent|__probe-profile|__ensure-profile)
|
|
3840
5257
|
run_internal_action
|
|
3841
5258
|
return 0
|
|
3842
5259
|
;;
|
|
3843
5260
|
esac
|
|
3844
5261
|
|
|
5262
|
+
if [ "$AGENT" = "aime" ]; then
|
|
5263
|
+
ensure_agent_selection_available "$AGENT"
|
|
5264
|
+
fi
|
|
5265
|
+
|
|
3845
5266
|
trap cleanup EXIT INT TERM HUP
|
|
3846
5267
|
init_log_run
|
|
3847
5268
|
validate_mock_fail_stage
|