Compare commits

..

10 Commits

Author SHA1 Message Date
copilot-swe-agent[bot] 929d2eb574 Revert sample file changes - fix belongs in preload
Reverted all changes to sample files as the correct fix is to export
NODE_OPTIONS/PYTHONPATH in the preload scripts (sitecustomize.js/py),
not to modify sample files. This was the maintainer's feedback.

Co-authored-by: whyour <22700758+whyour@users.noreply.github.com>
2025-11-22 14:50:55 +00:00
copilot-swe-agent[bot] ebedd994dd Improve string handling for NODE_OPTIONS and PYTHONPATH
Use filter(Boolean).join() to avoid extra spaces and properly handle
missing environment variables. This ensures clean paths even when
some variables are empty or undefined.

Co-authored-by: whyour <22700758+whyour@users.noreply.github.com>
2025-11-22 14:47:33 +00:00
copilot-swe-agent[bot] ee7d39f433 Fix NODE_OPTIONS not being available in task_before commands
Export NODE_OPTIONS and PYTHONPATH in bash subprocess so that any
node/python commands in task_before (pre-execution field) can access
the QLAPI preload. This fixes the issue where running
"node /ql/data/scripts/ql_sample.js" in pre-execution fails with
"ReferenceError: QLAPI is not defined".

Co-authored-by: whyour <22700758+whyour@users.noreply.github.com>
2025-11-22 14:45:56 +00:00
copilot-swe-agent[bot] eab8a93f28 Improve error messages for QLAPI initialization
Co-authored-by: whyour <22700758+whyour@users.noreply.github.com>
2025-11-22 14:34:17 +00:00
copilot-swe-agent[bot] 16b20e8b54 Add QLAPI auto-initialization for Python and format code
Co-authored-by: whyour <22700758+whyour@users.noreply.github.com>
2025-11-22 14:31:27 +00:00
copilot-swe-agent[bot] 6dbd980881 Add QLAPI auto-initialization for standalone node execution
Co-authored-by: whyour <22700758+whyour@users.noreply.github.com>
2025-11-22 14:30:25 +00:00
copilot-swe-agent[bot] 35a17fce95 Initial plan 2025-11-22 14:25:29 +00:00
Copilot 6a3dd4f83c Fix null log_name issue by omitting it from shell command when not set (#2849)
* Initial plan

* Fix null log_name handling in runSingle method

Co-authored-by: whyour <22700758+whyour@users.noreply.github.com>

* Update cron.log_name before makeCommand to avoid passing null to shell

Co-authored-by: whyour <22700758+whyour@users.noreply.github.com>

* Fix: Only pass log_name to shell when it has a value

Co-authored-by: whyour <22700758+whyour@users.noreply.github.com>

* Fix uniqPath calculation in runSingle for null log_name

Co-authored-by: whyour <22700758+whyour@users.noreply.github.com>

* Improve comment clarity in makeCommand

Co-authored-by: whyour <22700758+whyour@users.noreply.github.com>

* Refactor: Move no_tee and ID to initial commandVariable declaration

Co-authored-by: whyour <22700758+whyour@users.noreply.github.com>

* Refactor: Simplify uniqPath ternary expression

Co-authored-by: whyour <22700758+whyour@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: whyour <22700758+whyour@users.noreply.github.com>
2025-11-22 12:06:01 +08:00
whyour 177cd3de81 更新 docker 日志 2025-11-22 01:05:28 +08:00
Copilot d473c3ae88 Fix SSH global private key matching before subscription-specific keys (#2845)
* Initial plan

* Fix SSH global private key loading order by using zzz_ prefix

Co-authored-by: whyour <22700758+whyour@users.noreply.github.com>

* Use tilde (~) prefix for global SSH config to ensure it loads last

Co-authored-by: whyour <22700758+whyour@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: whyour <22700758+whyour@users.noreply.github.com>
2025-11-21 01:53:58 +08:00
6 changed files with 30 additions and 21 deletions
+6 -2
View File
@@ -507,7 +507,7 @@ export default class CronService {
let { id, command, log_name } = cron;
const uniqPath =
log_name === '/dev/null'
log_name === '/dev/null' || !log_name
? await getUniqPath(command, `${id}`)
: log_name;
const logTime = dayjs().format('YYYY-MM-DD-HH-mm-ss-SSS');
@@ -641,7 +641,11 @@ export default class CronService {
if (!command.startsWith(TASK_PREFIX) && !command.startsWith(QL_PREFIX)) {
command = `${TASK_PREFIX}${tab.command}`;
}
let commandVariable = `real_time=${Boolean(realTime)} log_name=${tab.log_name} no_tee=true ID=${tab.id} `;
let commandVariable = `real_time=${Boolean(realTime)} no_tee=true ID=${tab.id} `;
// Only include log_name if it has a truthy value to avoid passing null/undefined to shell
if (tab.log_name) {
commandVariable += `log_name=${tab.log_name} `;
}
if (tab.task_before) {
commandVariable += `task_before='${tab.task_before
.replace(/'/g, "'\\''")
+4 -4
View File
@@ -133,15 +133,15 @@ export default class SshKeyService {
}
public async addGlobalSSHKey(key: string, alias: string): Promise<void> {
await this.generatePrivateKeyFile(`global_${alias}`, key);
await this.generatePrivateKeyFile(`~global_${alias}`, key);
// Create a global SSH config entry that matches all hosts
// This allows the key to be used for any Git repository
await this.generateGlobalSshConfig(`global_${alias}`);
await this.generateGlobalSshConfig(`~global_${alias}`);
}
public async removeGlobalSSHKey(alias: string): Promise<void> {
await this.removePrivateKeyFile(`global_${alias}`);
await this.removeSshConfig(`global_${alias}`);
await this.removePrivateKeyFile(`~global_${alias}`);
await this.removeSshConfig(`~global_${alias}`);
}
private async generateGlobalSshConfig(alias: string) {
-10
View File
@@ -350,11 +350,6 @@ export default class SubscriptionService {
for (const doc of docs) {
await this.handleTask(doc.get({ plain: true }), false);
}
// Disable associated cron tasks
const crons = await CrontabModel.findAll({ where: { sub_id: ids } });
if (crons?.length) {
await this.crontabService.disabled(crons.map((x) => x.id!));
}
}
public async enabled(ids: number[]) {
@@ -364,11 +359,6 @@ export default class SubscriptionService {
for (const doc of docs) {
await this.handleTask(doc.get({ plain: true }));
}
// Enable associated cron tasks
const crons = await CrontabModel.findAll({ where: { sub_id: ids } });
if (crons?.length) {
await this.crontabService.enabled(crons.map((x) => x.id!));
}
}
public async log(id: number) {
+5 -5
View File
@@ -23,11 +23,11 @@ log_with_style() {
if [ -f /etc/alpine-release ]; then
if ! grep -q "^options ndots:0" /etc/resolv.conf 2>/dev/null; then
echo "options ndots:0" >> /etc/resolv.conf
log_with_style "INFO" "🔧 已配置 DNS 解析优化 (ndots:0)"
log_with_style "INFO" "🔧 0. 已配置 DNS 解析优化 (ndots:0)"
fi
fi
log_with_style "INFO" "🚀 1. 检测配置文件..."
log_with_style "INFO" "🚀 1. 检测配置文件..."
load_ql_envs
export_ql_envs
. $dir_shell/env.sh
@@ -41,16 +41,16 @@ log_with_style "INFO" "⚙️ 2. 启动 pm2 服务..."
reload_pm2
if [[ $AutoStartBot == true ]]; then
log_with_style "INFO" "🤖 3. 启动 bot..."
log_with_style "INFO" "🤖 3. 启动 bot..."
nohup ql bot >$dir_log/bot.log 2>&1 &
fi
if [[ $EnableExtraShell == true ]]; then
log_with_style "INFO" "🛠️ 4. 执行自定义脚本..."
log_with_style "INFO" "🛠️ 4. 执行自定义脚本..."
nohup ql extra >$dir_log/extra.log 2>&1 &
fi
log_with_style "SUCCESS" "🎉 容器启动成功!"
log_with_style "SUCCESS" "🎉 容器启动成功!"
crond -f >/dev/null
+7
View File
@@ -28,6 +28,7 @@ function run() {
numParam,
file_task_before,
file_task_before_js,
file_preload_js,
dir_scripts,
task_before,
PREV_NODE_OPTIONS,
@@ -40,7 +41,13 @@ function run() {
const fileName = process.argv[1].replace(`${dir_scripts}/`, '');
const tempFile = `/tmp/env_${process.pid}.json`;
// Export NODE_OPTIONS so task_before can use it for any node commands
const nodeOptionsForBash = file_preload_js
? ['-r', file_preload_js, PREV_NODE_OPTIONS].filter(Boolean).join(' ')
: PREV_NODE_OPTIONS || '';
const commands = [
`export NODE_OPTIONS="${nodeOptionsForBash}"`,
`source ${file_task_before} ${fileName}`,
task_before ? `eval '${task_before.replace(/'/g, "'\\''")}'` : null,
`echo -e '${splitStr}'`,
+8
View File
@@ -44,11 +44,19 @@ def run():
split_str = "__sitecustomize__"
file_name = sys.argv[0].replace(f"{os.getenv('dir_scripts')}/", "")
# Get environment variables needed for PYTHONPATH
dir_preload = os.getenv("dir_preload", "")
dir_config = os.getenv("dir_config", "")
# 创建临时文件路径
temp_file = f"/tmp/env_{os.getpid()}.json"
# Export PYTHONPATH so task_before can use it for any python commands
pythonpath_for_bash = ':'.join(filter(None, [dir_preload, dir_config, prev_pythonpath]))
# 构建命令数组
commands = [
f'export PYTHONPATH="{pythonpath_for_bash}"',
f'source {os.getenv("file_task_before")} {file_name}'
]