feat: 增加NAS Codex环境引导工具
This commit is contained in:
parent
30222fd85e
commit
d53b17f6f1
@ -16,7 +16,7 @@
|
|||||||
- 生成接口测试计划:接口改动后输出真实调用命令和统一返回结构断言。
|
- 生成接口测试计划:接口改动后输出真实调用命令和统一返回结构断言。
|
||||||
- 生成业务链路测试计划:固化 Admin 登录、博客 CRUD、QQBot 扫码/自动回复、更新登录 SSE、FFLogs 命令、系统日志可视化、Web/Playground 回跳。
|
- 生成业务链路测试计划:固化 Admin 登录、博客 CRUD、QQBot 扫码/自动回复、更新登录 SSE、FFLogs 命令、系统日志可视化、Web/Playground 回跳。
|
||||||
- 静态检查 NapCat 设备身份护栏:确认 API 仍保留 QQNT 可见 hostname、实体 OUI 风格 MAC、QQNT `machine-info` 写入、持久化 runtime dir 和 `DB_TIMEZONE` 默认值。
|
- 静态检查 NapCat 设备身份护栏:确认 API 仍保留 QQNT 可见 hostname、实体 OUI 风格 MAC、QQNT `machine-info` 写入、持久化 runtime dir 和 `DB_TIMEZONE` 默认值。
|
||||||
- 生成 NapCatQQ 上游同步与 runtime 发布自动化入口:MCP/CLI 默认 dry-run,覆盖 upstream audit、sync candidate review、runtime readiness、remote dev handoff 和 NAS Codex bootstrap plan;除 upstream audit 在显式 `execute=true` 且 `useCodex=true` 时可运行 Codex 外,其余 Task 5 入口只返回 prompt/context/只读命令骨架。
|
- 生成 NapCatQQ 上游同步与 runtime 发布自动化入口:MCP/CLI 默认 dry-run,覆盖 upstream audit、sync candidate review、runtime readiness、remote dev handoff 和 NAS Codex bootstrap plan;upstream audit 在显式 `execute=true` 且 `useCodex=true` 时可运行 Codex,NAS Codex bootstrap 在显式 `execute=true` 时只返回目录准备和 CLI 包检查/安装计划,不复制 secrets、不写 systemd、不触发发布。
|
||||||
- 生成卡点固化记录:把超时、卡进程、远程命令误写、重复失败整理成“问题点 / 稳定解法 / 后续入口 / 验证证据”,避免原样重试。
|
- 生成卡点固化记录:把超时、卡进程、远程命令误写、重复失败整理成“问题点 / 稳定解法 / 后续入口 / 验证证据”,避免原样重试。
|
||||||
- 生成改动文档同步计划:按变更文件自动提示需要同步的 README、API、AGENTS、docs、Obsidian、skill 和 ktWorkflow 入口。
|
- 生成改动文档同步计划:按变更文件自动提示需要同步的 README、API、AGENTS、docs、Obsidian、skill 和 ktWorkflow 入口。
|
||||||
- 生成多仓库提交/推送计划:按仓库分组、建议提交信息、列出提交和推送前检查。
|
- 生成多仓库提交/推送计划:按仓库分组、建议提交信息、列出提交和推送前检查。
|
||||||
@ -105,7 +105,7 @@ pnpm run admin-login -- --url http://127.0.0.1:5999/#/auth/login
|
|||||||
| `kt_napcat_sync_candidate_review` | 生成 NapCat sync candidate review 的 prompt/context/只读命令骨架,Task 5 不执行 Codex 或 Git 写操作 |
|
| `kt_napcat_sync_candidate_review` | 生成 NapCat sync candidate review 的 prompt/context/只读命令骨架,Task 5 不执行 Codex 或 Git 写操作 |
|
||||||
| `kt_napcat_runtime_release_readiness` | 生成 NapCat runtime release readiness 的 prompt/context/只读检查骨架,不自动构建或发布 |
|
| `kt_napcat_runtime_release_readiness` | 生成 NapCat runtime release readiness 的 prompt/context/只读检查骨架,不自动构建或发布 |
|
||||||
| `kt_napcat_remote_dev_handoff` | 生成 NapCat 自动化远程开发 handoff 的 prompt/context 骨架,不创建线程或同步仓库 |
|
| `kt_napcat_remote_dev_handoff` | 生成 NapCat 自动化远程开发 handoff 的 prompt/context 骨架,不创建线程或同步仓库 |
|
||||||
| `kt_nas_codex_bootstrap_plan` | 生成可信 NAS Codex bootstrap dry-run plan,Task 5 仅输出只读检查和占位计划 |
|
| `kt_nas_codex_bootstrap_plan` | 生成可信 NAS Codex bootstrap dry-run/execute command plan;execute 只规划目录准备和 CLI 包检查/安装,不复制 secrets、不写 systemd |
|
||||||
| `kt_napcat_device_profile_check` | 静态检查 API NapCat 设备身份护栏,覆盖 hostname、MAC、`machine-info`、runtime dir 和 DB timezone |
|
| `kt_napcat_device_profile_check` | 静态检查 API NapCat 设备身份护栏,覆盖 hostname、MAC、`machine-info`、runtime dir 和 DB timezone |
|
||||||
| `kt_blocker_resolution` | 生成或写入卡点固化记录,提醒停止原样重试 |
|
| `kt_blocker_resolution` | 生成或写入卡点固化记录,提醒停止原样重试 |
|
||||||
| `kt_remote_health_check` | 生成或执行远程只读健康检查命令 |
|
| `kt_remote_health_check` | 生成或执行远程只读健康检查命令 |
|
||||||
@ -128,7 +128,7 @@ pnpm run admin-login -- --url http://127.0.0.1:5999/#/auth/login
|
|||||||
| `pnpm run napcat-sync-candidate-review` | 输出 sync candidate review 的 prompt/context/只读命令骨架,不执行 Codex 或 Git 写操作。 |
|
| `pnpm run napcat-sync-candidate-review` | 输出 sync candidate review 的 prompt/context/只读命令骨架,不执行 Codex 或 Git 写操作。 |
|
||||||
| `pnpm run napcat-runtime-release-readiness` | 输出 runtime release readiness 的 prompt/context/只读检查骨架,不构建镜像、不调用 kubectl、不发布。 |
|
| `pnpm run napcat-runtime-release-readiness` | 输出 runtime release readiness 的 prompt/context/只读检查骨架,不构建镜像、不调用 kubectl、不发布。 |
|
||||||
| `pnpm run napcat-remote-dev-handoff` | 输出远程开发 handoff 的 prompt/context 骨架,不创建线程、不同步仓库、不执行 Codex。 |
|
| `pnpm run napcat-remote-dev-handoff` | 输出远程开发 handoff 的 prompt/context 骨架,不创建线程、不同步仓库、不执行 Codex。 |
|
||||||
| `pnpm run nas-codex-bootstrap` | 输出可信 NAS Codex bootstrap dry-run plan;真实安装、同步和 systemd 接入留给后续实现。 |
|
| `pnpm run nas-codex-bootstrap` | 输出可信 NAS Codex bootstrap dry-run plan;传 `--execute` 只生成目录准备和 CLI 包检查/安装命令计划,不真实执行 SSH、不复制 secrets、不写 systemd。 |
|
||||||
| `pnpm run napcat-device-profile-check` | 静态检查 API NapCat 设备身份护栏,防止回退到未知设备风险配置。 |
|
| `pnpm run napcat-device-profile-check` | 静态检查 API NapCat 设备身份护栏,防止回退到未知设备风险配置。 |
|
||||||
| `pnpm run deploy-observation` | 默认 dry-run 输出只读 NAS 观测命令;传 `--execute` 时执行 Jenkins/K8s/health/smoke 观测并写入 `.kt-workspace/test-artifacts/deploy-observation`。 |
|
| `pnpm run deploy-observation` | 默认 dry-run 输出只读 NAS 观测命令;传 `--execute` 时执行 Jenkins/K8s/health/smoke 观测并写入 `.kt-workspace/test-artifacts/deploy-observation`。 |
|
||||||
| `pnpm run obsidian-context` | 输出 Obsidian 索引上下文;可传 `--module Admin`、`--query QQBot`、`--max-documents 10`。 |
|
| `pnpm run obsidian-context` | 输出 Obsidian 索引上下文;可传 `--module Admin`、`--query QQBot`、`--max-documents 10`。 |
|
||||||
|
|||||||
@ -209,6 +209,81 @@ export async function runSelfTest(): Promise<void> {
|
|||||||
) {
|
) {
|
||||||
throw new Error("NAS Codex bootstrap default alignment self-check failed");
|
throw new Error("NAS Codex bootstrap default alignment self-check failed");
|
||||||
}
|
}
|
||||||
|
const bootstrap = buildNasCodexBootstrapPlan({ execute: false });
|
||||||
|
const bootstrapCommandText = bootstrap.commands
|
||||||
|
.map((item) => item.command)
|
||||||
|
.join("\n");
|
||||||
|
if (!bootstrapCommandText.includes("/vol1/docker/kt-codex/home/.codex")) {
|
||||||
|
throw new Error("NAS Codex bootstrap CODEX_HOME self-check failed");
|
||||||
|
}
|
||||||
|
if (bootstrapCommandText.includes("C:\\Users")) {
|
||||||
|
throw new Error("NAS Codex bootstrap Windows path guard self-check failed");
|
||||||
|
}
|
||||||
|
for (const expected of [
|
||||||
|
"node --version",
|
||||||
|
"corepack --version",
|
||||||
|
"pnpm --version",
|
||||||
|
"git --version",
|
||||||
|
"docker --version",
|
||||||
|
"codex --version",
|
||||||
|
"test -d /vol1/docker/kt-codex/workspace/KT",
|
||||||
|
"test -d /vol1/docker/kt-codex/home/.codex",
|
||||||
|
]) {
|
||||||
|
if (!bootstrapCommandText.includes(expected)) {
|
||||||
|
throw new Error(`NAS Codex bootstrap dry-run command missing: ${expected}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const command of bootstrap.commands) {
|
||||||
|
if (!command.readOnly) {
|
||||||
|
throw new Error("NAS Codex bootstrap dry-run command must be read-only");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const executeBootstrap = buildNasCodexBootstrapPlan({ execute: true });
|
||||||
|
const executeBootstrapCommandText = executeBootstrap.commands
|
||||||
|
.map((item) => item.command)
|
||||||
|
.join("\n");
|
||||||
|
if (
|
||||||
|
executeBootstrap.execute !== true ||
|
||||||
|
executeBootstrap.commands.every((command) => command.readOnly)
|
||||||
|
) {
|
||||||
|
throw new Error("NAS Codex bootstrap execute plan self-check failed");
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
!executeBootstrapCommandText.includes("install -d -m 700 /vol1/docker/kt-codex/home/.codex") ||
|
||||||
|
!executeBootstrapCommandText.includes("npm install -g @openai/codex")
|
||||||
|
) {
|
||||||
|
throw new Error("NAS Codex bootstrap execute package plan self-check failed");
|
||||||
|
}
|
||||||
|
for (const forbidden of [
|
||||||
|
"git push",
|
||||||
|
"git merge",
|
||||||
|
"docker build",
|
||||||
|
"docker pull",
|
||||||
|
"kubectl",
|
||||||
|
"systemctl enable",
|
||||||
|
"systemctl start",
|
||||||
|
"cp ~/.codex",
|
||||||
|
"scp ~/.codex",
|
||||||
|
"C:\\Users",
|
||||||
|
]) {
|
||||||
|
if (executeBootstrapCommandText.includes(forbidden)) {
|
||||||
|
throw new Error(`NAS Codex bootstrap forbidden command leaked: ${forbidden}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let windowsBootstrapPathRejected = false;
|
||||||
|
try {
|
||||||
|
buildNasCodexBootstrapPlan({
|
||||||
|
codexHome: "C:\\Users\\example\\.codex",
|
||||||
|
execute: false,
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
windowsBootstrapPathRejected = String(error).includes(
|
||||||
|
"Unsafe NAS Codex bootstrap path",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (!windowsBootstrapPathRejected) {
|
||||||
|
throw new Error("NAS Codex bootstrap unsafe Windows path self-check failed");
|
||||||
|
}
|
||||||
const napcatCandidateOverride = buildNapcatSyncCandidateReview({
|
const napcatCandidateOverride = buildNapcatSyncCandidateReview({
|
||||||
candidateBranch: "custom-candidate",
|
candidateBranch: "custom-candidate",
|
||||||
lastAcceptedUpstreamBase: "custom-base",
|
lastAcceptedUpstreamBase: "custom-base",
|
||||||
|
|||||||
@ -333,21 +333,54 @@ export function buildNapcatRemoteDevHandoff(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface NasCodexBootstrapContext {
|
||||||
|
codexHome: string;
|
||||||
|
serviceName: string;
|
||||||
|
workspaceRoot: string;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builds a non-mutating NAS Codex bootstrap plan placeholder for later automation tasks.
|
* Builds a safe NAS Codex bootstrap command plan without running SSH locally.
|
||||||
* @param input - Trusted NAS workspace/Codex-home hints and optional service name; execution is intentionally not implemented in Task 5.
|
* @param input - Trusted NAS workspace/Codex-home hints, optional service name, and explicit execution intent.
|
||||||
* @returns A dry-run bootstrap checklist and read-only verification commands.
|
* @returns A dry-run or execute-mode command plan; execute mode only emits bounded NAS preparation commands for a trusted operator to run.
|
||||||
*/
|
*/
|
||||||
export function buildNasCodexBootstrapPlan(input: NasCodexBootstrapPlanInput) {
|
export function buildNasCodexBootstrapPlan(input: NasCodexBootstrapPlanInput) {
|
||||||
const artifactRoot =
|
const artifactRoot =
|
||||||
input.artifactRoot?.trim() ||
|
input.artifactRoot?.trim() ||
|
||||||
`${napcatAutomationSkeletonArtifactRoot}/nas-codex-bootstrap`;
|
`${napcatAutomationSkeletonArtifactRoot}/nas-codex-bootstrap`;
|
||||||
const context = {
|
const context: NasCodexBootstrapContext = {
|
||||||
codexHome: input.codexHome ?? napcatAutomationDefaults.codexHome,
|
codexHome: resolveNasBootstrapPath(
|
||||||
serviceName: input.serviceName ?? napcatAutomationDefaults.bootstrapServiceName,
|
'codexHome',
|
||||||
workspaceRoot: input.workspaceRoot ?? napcatAutomationDefaults.workspaceRoot,
|
input.codexHome,
|
||||||
|
napcatAutomationDefaults.codexHome,
|
||||||
|
),
|
||||||
|
serviceName: resolveNasBootstrapServiceName(
|
||||||
|
input.serviceName ?? napcatAutomationDefaults.bootstrapServiceName,
|
||||||
|
),
|
||||||
|
workspaceRoot: resolveNasBootstrapPath(
|
||||||
|
'workspaceRoot',
|
||||||
|
input.workspaceRoot,
|
||||||
|
napcatAutomationDefaults.workspaceRoot,
|
||||||
|
),
|
||||||
};
|
};
|
||||||
const requestedExecute = input.execute === true;
|
const requestedExecute = input.execute === true;
|
||||||
|
const commands = [
|
||||||
|
{
|
||||||
|
command: buildNasBootstrapDryRunCommand(context),
|
||||||
|
description:
|
||||||
|
'Run bounded read-only NAS checks for Linux tools, KT workspace, and trusted CODEX_HOME.',
|
||||||
|
readOnly: true,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
if (requestedExecute) {
|
||||||
|
commands.push({
|
||||||
|
command: buildNasBootstrapExecuteCommand(context),
|
||||||
|
description:
|
||||||
|
'Create trusted NAS Codex directories and install/check CLI packages without touching business repos, secrets, deploys, or systemd.',
|
||||||
|
readOnly: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
artifacts: [
|
artifacts: [
|
||||||
@ -360,32 +393,143 @@ export function buildNasCodexBootstrapPlan(input: NasCodexBootstrapPlanInput) {
|
|||||||
type: 'json',
|
type: 'json',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
commands: [
|
commands,
|
||||||
{
|
|
||||||
command: 'ssh nas "command -v codex && codex --version"',
|
|
||||||
description: 'Read the trusted NAS Codex CLI version without installing or changing files.',
|
|
||||||
readOnly: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
command:
|
|
||||||
'ssh nas "test -d /vol1/docker/kt-codex/workspace/KT && git -C /vol1/docker/kt-codex/workspace/KT status --short --branch"',
|
|
||||||
description: 'Read the trusted NAS KT workspace state without syncing or committing.',
|
|
||||||
readOnly: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
context,
|
context,
|
||||||
execute: false,
|
execute: requestedExecute,
|
||||||
notes: [
|
notes: [
|
||||||
'Task 5 only exposes a dry-run bootstrap plan. Task 6 must implement real NAS bootstrap logic before any mutation is allowed.',
|
'The builder only returns command plans; it does not open SSH sessions or mutate NAS state by itself.',
|
||||||
|
'Dry-run mode emits Linux-only version and directory checks and never copies Codex secrets.',
|
||||||
requestedExecute
|
requestedExecute
|
||||||
? 'execute=true was requested, but no bootstrap mutation is performed by this placeholder.'
|
? 'execute=true adds a bounded preparation plan that may create trusted directories and install/check Node/Corepack/pnpm/Codex packages, but still does not push, merge, deploy, edit business repos, copy secrets, or write systemd.'
|
||||||
: 'execute defaults to false.',
|
: 'execute defaults to false.',
|
||||||
],
|
],
|
||||||
requestedExecute,
|
requestedExecute,
|
||||||
summary: 'NAS Codex bootstrap dry-run plan generated.',
|
summary: requestedExecute
|
||||||
|
? 'NAS Codex bootstrap execute-mode command plan generated.'
|
||||||
|
: 'NAS Codex bootstrap dry-run plan generated.',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolves and validates a NAS bootstrap Linux path before embedding it in remote shell text.
|
||||||
|
* @param label - Human-readable input name used in validation errors.
|
||||||
|
* @param value - Optional caller override for a trusted NAS filesystem path.
|
||||||
|
* @param fallback - Stabilized default path used when no override is provided.
|
||||||
|
* @returns A normalized absolute Linux path under `/vol1/docker/kt-codex`.
|
||||||
|
*/
|
||||||
|
function resolveNasBootstrapPath(
|
||||||
|
label: string,
|
||||||
|
value: string | undefined,
|
||||||
|
fallback: string,
|
||||||
|
): string {
|
||||||
|
const resolved = (value?.trim() || fallback).replace(/\/+$/, '');
|
||||||
|
if (
|
||||||
|
/^[a-zA-Z]:[\\/]/.test(resolved) ||
|
||||||
|
resolved.includes('\\') ||
|
||||||
|
resolved.includes('~') ||
|
||||||
|
resolved.includes('$') ||
|
||||||
|
/[\r\n]/.test(resolved) ||
|
||||||
|
!/^\/[A-Za-z0-9._/-]+$/.test(resolved) ||
|
||||||
|
!resolved.startsWith('/vol1/docker/kt-codex/') ||
|
||||||
|
hasParentPathSegment(resolved)
|
||||||
|
) {
|
||||||
|
throw new Error(`Unsafe NAS Codex bootstrap path "${label}"`);
|
||||||
|
}
|
||||||
|
return resolved;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates the future service label while Task 6 deliberately avoids writing systemd units.
|
||||||
|
* @param value - Service name from CLI/MCP input or the stabilized default.
|
||||||
|
* @returns A compact service label safe to carry in JSON context.
|
||||||
|
*/
|
||||||
|
function resolveNasBootstrapServiceName(value: string): string {
|
||||||
|
const resolved = value.trim();
|
||||||
|
if (!/^[A-Za-z0-9._-]+$/.test(resolved)) {
|
||||||
|
throw new Error('Unsafe NAS Codex bootstrap serviceName');
|
||||||
|
}
|
||||||
|
return resolved;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds the bounded PowerShell-to-NAS here-string wrapper used by bootstrap plans.
|
||||||
|
* @param bodyLines - Linux shell commands that will run on NAS only when a human executes the returned plan.
|
||||||
|
* @param timeoutSeconds - Remote `timeout` budget that prevents hanging checks or installs.
|
||||||
|
* @returns A copy-pastable PowerShell command using the KT NAS CRLF-safe SSH pattern.
|
||||||
|
*/
|
||||||
|
function buildNasBootstrapSshPlanCommand(
|
||||||
|
bodyLines: string[],
|
||||||
|
timeoutSeconds: number,
|
||||||
|
): string {
|
||||||
|
return [
|
||||||
|
"$remoteScript = @'",
|
||||||
|
'set -euo pipefail',
|
||||||
|
...bodyLines,
|
||||||
|
"'@",
|
||||||
|
`$remoteScript | ssh nas "tr -d '\\015' | timeout ${timeoutSeconds}s bash -s"`,
|
||||||
|
].join('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds the read-only NAS Codex bootstrap dry-run command required by Task 6.
|
||||||
|
* @param context - Trusted NAS workspace and CODEX_HOME paths.
|
||||||
|
* @returns A bounded SSH here-string containing Linux-only version and directory checks.
|
||||||
|
*/
|
||||||
|
function buildNasBootstrapDryRunCommand(
|
||||||
|
context: NasCodexBootstrapContext,
|
||||||
|
): string {
|
||||||
|
return buildNasBootstrapSshPlanCommand(
|
||||||
|
[
|
||||||
|
"printf '%s\\n' '[ktWorkflow] NAS Codex bootstrap dry-run checks'",
|
||||||
|
'node --version',
|
||||||
|
'corepack --version',
|
||||||
|
'pnpm --version',
|
||||||
|
'git --version',
|
||||||
|
'docker --version',
|
||||||
|
'codex --version',
|
||||||
|
`test -d ${context.workspaceRoot}`,
|
||||||
|
`test -d ${context.codexHome}`,
|
||||||
|
`git -C ${context.workspaceRoot} status --short --branch`,
|
||||||
|
],
|
||||||
|
120,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds the explicit execute-mode NAS preparation plan without running it locally.
|
||||||
|
* @param context - Trusted NAS workspace, Codex home, and service label context.
|
||||||
|
* @returns A bounded SSH here-string that creates only kt-codex directories and checks/installs CLI packages.
|
||||||
|
*/
|
||||||
|
function buildNasBootstrapExecuteCommand(
|
||||||
|
context: NasCodexBootstrapContext,
|
||||||
|
): string {
|
||||||
|
const workspaceParent = path.posix.dirname(context.workspaceRoot);
|
||||||
|
|
||||||
|
return buildNasBootstrapSshPlanCommand(
|
||||||
|
[
|
||||||
|
"printf '%s\\n' '[ktWorkflow] NAS Codex bootstrap execute plan'",
|
||||||
|
`install -d -m 755 ${workspaceParent}`,
|
||||||
|
`install -d -m 700 ${context.codexHome}`,
|
||||||
|
`install -d -m 755 ${napcatNasCodexArtifactRoot}`,
|
||||||
|
'node --version',
|
||||||
|
'corepack --version',
|
||||||
|
'corepack enable',
|
||||||
|
'corepack prepare pnpm@10.28.2 --activate',
|
||||||
|
'pnpm --version',
|
||||||
|
'git --version',
|
||||||
|
'docker --version',
|
||||||
|
'if ! command -v codex >/dev/null 2>&1; then',
|
||||||
|
' npm install -g @openai/codex',
|
||||||
|
'fi',
|
||||||
|
'codex --version',
|
||||||
|
`test -d ${context.workspaceRoot}`,
|
||||||
|
`test -d ${context.codexHome}`,
|
||||||
|
`git -C ${context.workspaceRoot} status --short --branch`,
|
||||||
|
],
|
||||||
|
300,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Quotes a POSIX shell path argument for NAS-side Codex automation commands.
|
* Quotes a POSIX shell path argument for NAS-side Codex automation commands.
|
||||||
* @param value - Absolute or repo-relative filesystem path that will be interpreted by a Linux shell.
|
* @param value - Absolute or repo-relative filesystem path that will be interpreted by a Linux shell.
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user