@larktask/aamp-feishu-task-agent 0.1.0-dev.171 → 0.1.0-dev.173

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.
@@ -10,6 +10,7 @@ import { spawn } from 'node:child_process';
10
10
  import { EventEmitter } from 'node:events';
11
11
  import {
12
12
  agentStartRetryError,
13
+ bridgeAuthenticationRetryError,
13
14
  classifyNetworkError,
14
15
  createSerializedLineWriter,
15
16
  describeNetworkError,
@@ -236,7 +237,11 @@ async function runNetworkStage(operation, {
236
237
  shouldRetry,
237
238
  onRetry: async (event) => {
238
239
  await appendDiagnostic(logFile, { type: 'network.retry', stage, label, host: safeDiagnosticUrl(host), ...event });
239
- console.log(`[aamp-one-click] ${label}遇到网络波动,正在重试(${event.attempt + 1}/${event.maxAttempts})...`);
240
+ if (event.category === 'mail_auth') {
241
+ console.log(`[aamp-one-click] ${label}检测到 AAMP 邮箱凭据失效,正在重新注册并重试(${event.attempt + 1}/${event.maxAttempts})...`);
242
+ } else {
243
+ console.log(`[aamp-one-click] ${label}遇到网络波动,正在重试(${event.attempt + 1}/${event.maxAttempts})...`);
244
+ }
240
245
  launchDetachedDiagnostic(() => probeFailureEndpoints(host, logFile, environment, `${stage}-retry-probe`));
241
246
  },
242
247
  });
@@ -867,6 +872,7 @@ async function startManagedProcess({ label, packageSpec, executable, args, env,
867
872
  const safeLine = redact(line);
868
873
  record.outputTail.push(`[${streamName}] ${safeLine}`);
869
874
  if (record.outputTail.length > 30) record.outputTail.shift();
875
+ record.emitter.emit('output', safeLine);
870
876
  if (streamName === 'stdout' && line.trim()) {
871
877
  try {
872
878
  const event = JSON.parse(line.trim());
@@ -948,6 +954,8 @@ async function stopManagedProcess(record) {
948
954
  }
949
955
 
950
956
  async function waitForEvent(record, predicate, timeoutMs = READY_TIMEOUT_MS) {
957
+ const authenticationError = bridgeAuthenticationRetryError(record.outputTail);
958
+ if (authenticationError) throw authenticationError;
951
959
  const existing = record.events.find(predicate);
952
960
  if (existing) return existing;
953
961
  if (record.exited) {
@@ -970,13 +978,21 @@ async function waitForEvent(record, predicate, timeoutMs = READY_TIMEOUT_MS) {
970
978
  const tail = record.outputTail.slice(-10).join('\n');
971
979
  reject(new Error(`${record.label} exited before ready (${exit.signal || exit.code})${tail ? `:\n${tail}` : ''}\n日志:${record.logFile}`));
972
980
  };
981
+ const onOutput = () => {
982
+ const error = bridgeAuthenticationRetryError(record.outputTail);
983
+ if (!error) return;
984
+ cleanup();
985
+ reject(error);
986
+ };
973
987
  const cleanup = () => {
974
988
  clearTimeout(timeout);
975
989
  record.emitter.off('event', onEvent);
976
990
  record.emitter.off('exit', onExit);
991
+ record.emitter.off('output', onOutput);
977
992
  };
978
993
  record.emitter.on('event', onEvent);
979
994
  record.emitter.on('exit', onExit);
995
+ record.emitter.on('output', onOutput);
980
996
  });
981
997
  }
982
998
 
@@ -1333,6 +1349,8 @@ async function pairingConsumed(pairingFile) {
1333
1349
  async function waitForInitialBinding(record, pairingFile) {
1334
1350
  const deadline = Date.now() + READY_TIMEOUT_MS;
1335
1351
  while (Date.now() < deadline) {
1352
+ const authenticationError = bridgeAuthenticationRetryError(record.outputTail);
1353
+ if (authenticationError) throw authenticationError;
1336
1354
  if (record.exited) {
1337
1355
  const tail = record.outputTail.slice(-10).join('\n');
1338
1356
  throw new Error(`${record.label} exited before binding completed${tail ? `:\n${tail}` : ''}\n日志:${record.logFile}`);
@@ -24,6 +24,7 @@ const TLS_CODES = new Set([
24
24
  'UNABLE_TO_GET_ISSUER_CERT_LOCALLY',
25
25
  'UNABLE_TO_VERIFY_LEAF_SIGNATURE',
26
26
  ]);
27
+ const MAIL_AUTH_CODES = new Set(['EAAMPMAILAUTH']);
27
28
 
28
29
  function asErrorDetails(error) {
29
30
  return error && typeof error === 'object' ? error : {};
@@ -95,6 +96,7 @@ export function classifyNetworkError(error) {
95
96
  if (status !== undefined) return status >= 500 ? 'http_5xx' : 'http_4xx';
96
97
 
97
98
  const codes = errorCodes(error);
99
+ if (codes.some((code) => MAIL_AUTH_CODES.has(code))) return 'mail_auth';
98
100
  if (codes.some((code) => DNS_CODES.has(code))) return 'dns';
99
101
  if (codes.some((code) => CONNECT_TIMEOUT_CODES.has(code))) return 'connect_timeout';
100
102
  if (codes.some((code) => TIMEOUT_CODES.has(code))) return 'timeout';
@@ -121,10 +123,18 @@ export function isRetryableHttpStatus(status) {
121
123
  export function isRetryableNetworkError(error) {
122
124
  const status = errorStatus(error);
123
125
  if (status !== undefined) return isRetryableHttpStatus(status);
124
- return ['dns', 'connect_timeout', 'timeout', 'connection_reset', 'unreachable', 'network']
126
+ return ['mail_auth', 'dns', 'connect_timeout', 'timeout', 'connection_reset', 'unreachable', 'network']
125
127
  .includes(classifyNetworkError(error));
126
128
  }
127
129
 
130
+ export function bridgeAuthenticationRetryError(outputLines) {
131
+ const output = (outputLines || []).slice(-30).join('\n');
132
+ if (!/\b535(?:\s+5\.7\.8)?\b[^\n]*authentication credentials invalid/i.test(output)) return undefined;
133
+ const error = new Error('AAMP 邮箱认证凭据已失效');
134
+ error.code = 'EAAMPMAILAUTH';
135
+ return error;
136
+ }
137
+
128
138
  function defaultSleep(ms) {
129
139
  if (ms <= 0) return Promise.resolve();
130
140
  return new Promise((resolve) => setTimeout(resolve, ms));
@@ -64,7 +64,8 @@ ACP_BRIDGE_PKG="${ACP_BRIDGE_PKG:-@zengxingyuan/aamp-acp-bridge@0.1.28-dev.20}"
64
64
  CLI_BRIDGE_PKG="${CLI_BRIDGE_PKG:-@zengxingyuan/aamp-cli-bridge@0.1.7-dev.14}"
65
65
  FEISHU_BRIDGE_PKG="${FEISHU_BRIDGE_PKG:-@zengxingyuan/aamp-feishu-bridge@0.1.51}"
66
66
  AAMP_TASK_AGENT_NAME="${AAMP_TASK_AGENT_NAME:-@larktask/aamp-feishu-task-agent}"
67
- AAMP_TASK_AGENT_VERSION="0.1.0-dev.171"
67
+ AAMP_TASK_AGENT_LEGACY_NAME="${AAMP_TASK_AGENT_LEGACY_NAME:-@zengxingyuan/aamp-feishu-task-agent}"
68
+ AAMP_TASK_AGENT_VERSION="0.1.0-dev.173"
68
69
  AAMP_TASK_AGENT_CHANNEL="${AAMP_TASK_AGENT_CHANNEL:-dev}"
69
70
  AAMP_STALE_PROCESS_CLEANUP="${AAMP_STALE_PROCESS_CLEANUP:-false}"
70
71
  AAMP_STALE_PROCESS_SECONDS="${AAMP_STALE_PROCESS_SECONDS:-86400}"
@@ -740,10 +741,34 @@ script_file_task_agent_version() {
740
741
  sed -n 's/^AAMP_TASK_AGENT_VERSION="\([^"]*\)".*/\1/p' "$file" | head -n 1
741
742
  }
742
743
 
744
+ script_file_task_agent_name() {
745
+ local file="$1"
746
+ [ -f "$file" ] || return 1
747
+ sed -n 's/^AAMP_TASK_AGENT_NAME="${AAMP_TASK_AGENT_NAME:-\([^}]*\)}"$/\1/p' "$file" | head -n 1
748
+ }
749
+
743
750
  task_agent_global_package_dir() {
744
751
  printf '%s/lib/node_modules/%s' "$NPM_GLOBAL_PREFIX" "$AAMP_TASK_AGENT_NAME"
745
752
  }
746
753
 
754
+ legacy_task_agent_global_package_dir() {
755
+ printf '%s/lib/node_modules/%s' "$NPM_GLOBAL_PREFIX" "$AAMP_TASK_AGENT_LEGACY_NAME"
756
+ }
757
+
758
+ remove_legacy_task_agent_global_install() {
759
+ [ "$AAMP_TASK_AGENT_NAME" != "$AAMP_TASK_AGENT_LEGACY_NAME" ] || return 0
760
+ [ -d "$(legacy_task_agent_global_package_dir)" ] || return 0
761
+
762
+ agent_detail "removing legacy task-agent npm package: $AAMP_TASK_AGENT_LEGACY_NAME"
763
+ sanitize_inherited_npm_exec_env
764
+ "$NPM_BIN" uninstall -g \
765
+ --registry "$NPM_REGISTRY" \
766
+ --cache "$NPM_CACHE_DIR" \
767
+ --prefix "$NPM_GLOBAL_PREFIX" \
768
+ "$AAMP_TASK_AGENT_LEGACY_NAME" >>"$ONE_CLICK_LOG" 2>&1
769
+ hash -r 2>/dev/null || true
770
+ }
771
+
747
772
  task_agent_global_package_version() {
748
773
  local package_json
749
774
  package_json="$(task_agent_global_package_dir)/package.json"
@@ -788,6 +813,7 @@ ensure_task_agent_global_install_locked() {
788
813
  agent_detail "keeping newer task-agent npm package: installed=$installed_version requested=$expected_version"
789
814
  return 0
790
815
  fi
816
+ remove_legacy_task_agent_global_install || return 1
791
817
  agent_detail "synchronizing task-agent npm package: current=${installed_version:-missing} expected=$expected_version"
792
818
  npm_install_global "$AAMP_TASK_AGENT_NAME@$expected_version" >>"$ONE_CLICK_LOG" 2>&1 || return 1
793
819
  task_agent_global_install_is_current "$expected_version"
@@ -803,9 +829,11 @@ ensure_task_agent_global_install() {
803
829
 
804
830
  short_command_is_current() {
805
831
  local target="$1"
806
- local installed_version
832
+ local installed_name installed_version
807
833
  [ -x "$target" ] || return 1
834
+ installed_name="$(script_file_task_agent_name "$target" || true)"
808
835
  installed_version="$(script_file_task_agent_version "$target" || true)"
836
+ [ "$installed_name" = "$AAMP_TASK_AGENT_NAME" ] || return 1
809
837
  [ "$installed_version" = "$AAMP_TASK_AGENT_VERSION" ]
810
838
  }
811
839
 
package/package.json CHANGED
@@ -6,7 +6,7 @@
6
6
  "README.md"
7
7
  ],
8
8
  "license": "MIT",
9
- "version": "0.1.0-dev.171",
9
+ "version": "0.1.0-dev.173",
10
10
  "description": "One-click manager for local Agent and Feishu Bot bindings.",
11
11
  "type": "module",
12
12
  "bin": {