mirror of
https://github.com/whyour/qinglong.git
synced 2026-11-05 20:19:11 +08:00
* feat(cli): add unified Commander CLI for QingLong 2.x * fix(cli): publish via npm and address security review feedback * ci(cli): package npm artifacts and remove evaluation collateral * test(cli): use a fixed shell fixture for log retention * refactor(cli): separate remote npm client from panel tools * feat(cli): cover active panel OpenAPI resources * docs(cli): unify authentication and skill guidance * refactor(cli): isolate internal commands and generate Commander help * refactor(cli): organize remote and internal modules by responsibility * ci(cli): publish verified npm archives from master * fix(cli): publish under the whyour npm scope * ci: use npm trusted publishing for both packages * docs: introduce the published CLI on the project homepage * fix(cli): preserve server log truncation and correct login hints * fix(cli): accept dashboard record request bodies * fix(cli): preserve stdin for local task execution * fix(cli): resolve task executables after changing directory * fix(cli): preserve shell function tasks and sanitize test failures * fix(cli): preserve shell hook state and resolve workdir after hooks * fix(cli): preserve cleanup across shared shell task timeouts * fix(cli): isolate shell control descriptors and reap timed-out descendants
99 lines
3.3 KiB
TypeScript
99 lines
3.3 KiB
TypeScript
import type { LocalContext } from '../runtime/context';
|
|
|
|
// Bash is the interpreter for user-owned files. The CLI supplies paths/argv as
|
|
// separate arguments; no user argument is interpolated into this fixed bridge.
|
|
export function shellSessionArguments(
|
|
context: LocalContext,
|
|
argv: string[],
|
|
scriptArgs: string[],
|
|
command = false,
|
|
timeoutMarker = '',
|
|
): string[] {
|
|
const scriptIndex = command
|
|
? argv.findIndex((arg) => /\.(?:js|mjs|py|pyc|sh|ts)$/.test(arg))
|
|
: 0;
|
|
const bridge = `
|
|
__ql_env=$1; __ql_before=$2; __ql_after=$3; __ql_command=$4; __ql_index=$5; __ql_count=$6; __ql_timeout=$7; shift 7
|
|
__ql_hook_args=( "\${@:1:__ql_count}" ); shift "$__ql_count"
|
|
__ql_script_args=( "$@" )
|
|
# Reserve an internal descriptor before sourcing user code. In particular, fd 3
|
|
# and fd 9 remain available for user redirections and locks. Bash 3 also supports
|
|
# this numeric descriptor, unlike Bash 4's dynamic descriptor syntax.
|
|
if [ -n "$__ql_timeout" ]; then exec 19>&3 3>&-; fi
|
|
__ql_after_started=false
|
|
__ql_run_after() {
|
|
__ql_after_started=true
|
|
if [ -n "$__ql_timeout" ]; then printf A >&19; fi
|
|
if [ "$__ql_nounset" = true ]; then set -u; fi
|
|
export NODE_PATH="\${PREV_NODE_PATH:-}"
|
|
unset QL_NODE_GLOBAL_PATH
|
|
if [ -f "$__ql_after" ]; then . "$__ql_after" "\${__ql_hook_args[@]}"; fi
|
|
if [ -n "\${task_after:-}" ]; then eval "\${task_after%;}"; fi
|
|
}
|
|
__ql_timeout_exit() {
|
|
if [ -f "$__ql_timeout" ] && [ "$__ql_after_started" = false ]; then
|
|
_task_exit_code=124
|
|
__ql_run_after
|
|
exit 124
|
|
fi
|
|
}
|
|
if [ -f "$__ql_env" ]; then . "$__ql_env"; fi
|
|
if [ -f "$__ql_before" ]; then . "$__ql_before" "\${__ql_hook_args[@]}"; fi
|
|
if [ -n "\${task_before:-}" ]; then eval "\${task_before%;}"; fi
|
|
__ql_nounset=false
|
|
case $- in *u*) __ql_nounset=true; set +u;; esac
|
|
if [ -n "\${__ql_selected_name:-}" ]; then
|
|
printf -v "$__ql_selected_name" '%s' "$__ql_selected_value"
|
|
export "$__ql_selected_name"
|
|
fi
|
|
unset __ql_selected_name __ql_selected_value
|
|
__ql_args=( "\${__ql_hook_args[@]}" )
|
|
if [ "$__ql_index" -lt 0 ]; then __ql_index=0; fi
|
|
__ql_file=\${__ql_args[__ql_index]}
|
|
__ql_resolve=false
|
|
cd "$dir_scripts" || exit 1
|
|
if [ -n "\${work_dir:-}" ] && [ -d "$work_dir" ]; then
|
|
cd "$work_dir" || exit 1
|
|
__ql_resolve=true
|
|
elif [[ "$__ql_file" == */* ]] && [ -d "\${__ql_file%/*}" ]; then
|
|
cd "\${__ql_file%/*}" || exit 1
|
|
__ql_resolve=true
|
|
fi
|
|
if [ "$__ql_resolve" = true ] && [[ "$__ql_file" == */* ]]; then
|
|
__ql_args[__ql_index]="./\${__ql_file##*/}"
|
|
fi
|
|
if [ -n "$__ql_timeout" ]; then
|
|
# Preserve a user-owned EXIT trap. If it prevents our cleanup, the parent
|
|
# performs the fallback after the process group has stopped.
|
|
if [ -z "$(trap -p EXIT)" ]; then trap '__ql_timeout_exit' EXIT; fi
|
|
printf T >&19
|
|
fi
|
|
if [ "$__ql_command" = true ]; then
|
|
"\${__ql_args[@]}" "\${__ql_script_args[@]}"
|
|
else
|
|
. "\${__ql_args[0]}" "\${__ql_script_args[@]}"
|
|
fi
|
|
_task_exit_code=$?
|
|
if [ -n "$__ql_timeout" ] && [ -f "$__ql_timeout" ]; then _task_exit_code=124; fi
|
|
__ql_run_after
|
|
exit "$_task_exit_code"
|
|
`;
|
|
return [
|
|
'--noprofile',
|
|
'--norc',
|
|
'-c',
|
|
bridge,
|
|
'ql-shell-session',
|
|
context.paths.file_env!,
|
|
context.paths.file_task_before!,
|
|
context.paths.file_task_after!,
|
|
String(command),
|
|
String(scriptIndex),
|
|
String(argv.length),
|
|
timeoutMarker,
|
|
...argv,
|
|
...(command ? [] : argv.slice(1)),
|
|
...scriptArgs,
|
|
];
|
|
}
|