feat: 接入NapCat自动化MCP工具和CLI
This commit is contained in:
parent
c16a867c60
commit
b767732fd3
14
README.md
14
README.md
@ -16,6 +16,7 @@
|
||||
- 生成接口测试计划:接口改动后输出真实调用命令和统一返回结构断言。
|
||||
- 生成业务链路测试计划:固化 Admin 登录、博客 CRUD、QQBot 扫码/自动回复、更新登录 SSE、FFLogs 命令、系统日志可视化、Web/Playground 回跳。
|
||||
- 静态检查 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/只读命令骨架。
|
||||
- 生成卡点固化记录:把超时、卡进程、远程命令误写、重复失败整理成“问题点 / 稳定解法 / 后续入口 / 验证证据”,避免原样重试。
|
||||
- 生成改动文档同步计划:按变更文件自动提示需要同步的 README、API、AGENTS、docs、Obsidian、skill 和 ktWorkflow 入口。
|
||||
- 生成多仓库提交/推送计划:按仓库分组、建议提交信息、列出提交和推送前检查。
|
||||
@ -40,6 +41,10 @@ pnpm run obsidian-context -- --module ktWorkflow
|
||||
pnpm run obsidian-validate
|
||||
pnpm run obsidian-sync
|
||||
pnpm run workstream-closeout -- --title "发布闭环" --verification "Jenkins SUCCESS" --doc-sync "无需文档更新" --cleanup "cleanup-history dry-run deleted=0" --cleanup-final-deleted 0 --review "global-review findings=0" --superpowers-review "Superpowers reviewer completed; no Critical/Important findings" --problem "无新卡点" --solution "无新增稳定解法"
|
||||
pnpm run napcat-upstream-audit -- --artifact-root .kt-workspace/test-artifacts/napcat-upstream-sync
|
||||
pnpm run napcat-sync-candidate-review
|
||||
pnpm run napcat-runtime-release-readiness
|
||||
pnpm run nas-codex-bootstrap
|
||||
pnpm run napcat-device-profile-check
|
||||
pnpm run cleanup-history -- --dry-run
|
||||
pnpm run cleanup-history -- --execute
|
||||
@ -95,6 +100,11 @@ pnpm run admin-login -- --url http://127.0.0.1:5999/#/auth/login
|
||||
| `kt_commit_plan` | 生成多仓库提交计划、建议 commit message 和检查项 |
|
||||
| `kt_push_plan` | 生成多仓库推送计划和远程异常提醒 |
|
||||
| `kt_business_test_plan` | 生成固化业务链路测试计划,包含 QQBot SSE、FFLogs 和系统日志 |
|
||||
| `kt_napcat_upstream_audit` | 生成或执行 NapCatQQ upstream release 审计,默认 dry-run,显式 `execute/useCodex` 后才运行 Codex |
|
||||
| `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_remote_dev_handoff` | 生成 NapCat 自动化远程开发 handoff 的 prompt/context 骨架,不创建线程或同步仓库 |
|
||||
| `kt_nas_codex_bootstrap_plan` | 生成可信 NAS Codex bootstrap dry-run plan,Task 5 仅输出只读检查和占位计划 |
|
||||
| `kt_napcat_device_profile_check` | 静态检查 API NapCat 设备身份护栏,覆盖 hostname、MAC、`machine-info`、runtime dir 和 DB timezone |
|
||||
| `kt_blocker_resolution` | 生成或写入卡点固化记录,提醒停止原样重试 |
|
||||
| `kt_remote_health_check` | 生成或执行远程只读健康检查命令 |
|
||||
@ -113,6 +123,10 @@ pnpm run admin-login -- --url http://127.0.0.1:5999/#/auth/login
|
||||
| ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `pnpm run admin-login` | 使用可见 Edge 打开 Admin 登录页,填写账号密码,拖动滑块,保存登录态和截图。默认账号来自初始化数据 `admin/123456`,生产或个人账号用 `KT_ADMIN_USERNAME` / `KT_ADMIN_PASSWORD` 或 CLI 参数覆盖。 |
|
||||
| `pnpm run global-review` | 对 KT 全部子仓库做只读全局 CodeReview 扫描,默认仅对变更文件做内容深扫,输出 JSON 复审报告,并校验 `TASKS.md` 最近记录只保留范围、关键词、验证字段、NapCat `latest` 漂移、QQBot 重型服务单测导入风险、QQBot 插件 registry/controller smoke 未 mock 具体插件实现风险、OneBot/QQ 登录态边界、NapCat 密码登录验证码 wait 阶段、日志窗口锚点、验证码状态早于日志 URL 的短轮询、验证码 pending 被状态轮询误清理、API Pod SSH 日志读取超时及清理前 pending 回归,以及普通处理中状态误吃旧验证码日志回归;明显测试占位 token 不报凭据风险,确认误报时优先升级 `src/tools/review.ts`,不要把误报沉积到上下文。 |
|
||||
| `pnpm run napcat-upstream-audit` | 默认 dry-run 输出 NapCatQQ 上游 release 审计分类、只读 Git 命令和 artifact 路径;显式 `--execute --use-codex` 才运行 Codex。 |
|
||||
| `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 nas-codex-bootstrap` | 输出可信 NAS Codex bootstrap dry-run plan;真实安装、同步和 systemd 接入留给后续实现。 |
|
||||
| `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 obsidian-context` | 输出 Obsidian 索引上下文;可传 `--module Admin`、`--query QQBot`、`--max-documents 10`。 |
|
||||
|
||||
@ -10,6 +10,10 @@
|
||||
"deploy-observation": "node --import ./node_modules/tsx/dist/loader.mjs src/server.ts --deploy-observation",
|
||||
"global-review": "node --import ./node_modules/tsx/dist/loader.mjs src/server.ts --global-review",
|
||||
"napcat-device-profile-check": "node --import ./node_modules/tsx/dist/loader.mjs src/server.ts --napcat-device-profile-check",
|
||||
"napcat-runtime-release-readiness": "node --import ./node_modules/tsx/dist/loader.mjs src/server.ts --napcat-runtime-release-readiness",
|
||||
"napcat-sync-candidate-review": "node --import ./node_modules/tsx/dist/loader.mjs src/server.ts --napcat-sync-candidate-review",
|
||||
"napcat-upstream-audit": "node --import ./node_modules/tsx/dist/loader.mjs src/server.ts --napcat-upstream-audit",
|
||||
"nas-codex-bootstrap": "node --import ./node_modules/tsx/dist/loader.mjs src/server.ts --nas-codex-bootstrap",
|
||||
"obsidian-context": "node --import ./node_modules/tsx/dist/loader.mjs src/server.ts --obsidian-context",
|
||||
"obsidian-sync": "node --import ./node_modules/tsx/dist/loader.mjs src/server.ts --obsidian-sync",
|
||||
"obsidian-validate": "node --import ./node_modules/tsx/dist/loader.mjs src/server.ts --obsidian-validate",
|
||||
|
||||
144
src/core/cli.ts
144
src/core/cli.ts
@ -1,6 +1,10 @@
|
||||
import type {
|
||||
DeployObservationInput,
|
||||
GlobalCodeReviewInput,
|
||||
NapcatRemoteDevHandoffInput,
|
||||
NapcatRuntimeReleaseReadinessInput,
|
||||
NapcatSyncCandidateReviewInput,
|
||||
NasCodexBootstrapPlanInput,
|
||||
ObsidianContextInput,
|
||||
ObsidianSyncInput,
|
||||
ObsidianValidateInput,
|
||||
@ -8,6 +12,7 @@ import type {
|
||||
WorkstreamReusablePattern,
|
||||
} from '../types.js';
|
||||
import { workstreamReusablePatternValues } from './constants.js';
|
||||
import type { NapcatUpstreamAuditInput } from '../tools/napcatAutomation.types.js';
|
||||
|
||||
function parseContentScanMode(argv: string[]): 'all' | 'changed' {
|
||||
if (argv.includes('--content-scan-all') || argv.includes('--contentScanMode=all')) {
|
||||
@ -62,6 +67,16 @@ function readOptionList(argv: string[], names: string[]): string[] {
|
||||
.filter(Boolean);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether any supported boolean CLI flag is present in the raw argv list.
|
||||
* @param argv - Full process argv including node, script, mode flag, and user options.
|
||||
* @param names - Flag names to accept in dashed or camelCase form.
|
||||
* @returns True when the caller provided one of the named flags.
|
||||
*/
|
||||
function hasFlag(argv: string[], names: string[]): boolean {
|
||||
return names.some((name) => argv.includes(name));
|
||||
}
|
||||
|
||||
export function parseWorkstreamCloseoutCliArgs(argv: string[]): WorkstreamCloseoutInput {
|
||||
const patternSet = new Set<string>(workstreamReusablePatternValues);
|
||||
const patterns = readOptionList(argv, ['--pattern', '--reusable-pattern'])
|
||||
@ -123,6 +138,135 @@ export function parseDeployObservationCliArgs(argv: string[]): DeployObservation
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the NapCat upstream audit CLI mode into the deterministic audit builder input.
|
||||
* @param argv - Full process argv from `src/server.ts`; `--execute` and `--use-codex` must both be explicit before Codex can run.
|
||||
* @returns Upstream audit input with dry-run defaults for all optional metadata lists.
|
||||
*/
|
||||
export function parseNapcatUpstreamAuditCliArgs(
|
||||
argv: string[],
|
||||
): NapcatUpstreamAuditInput {
|
||||
return {
|
||||
artifactRoot: readOption(argv, ['--artifact-root', '--artifactRoot']),
|
||||
codexHome: readOption(argv, ['--codex-home', '--codexHome']),
|
||||
createCandidateBranch: hasFlag(argv, ['--create-candidate-branch', '--createCandidateBranch']),
|
||||
dryMergeConflict: hasFlag(argv, ['--dry-merge-conflict', '--dryMergeConflict']),
|
||||
execute: hasFlag(argv, ['--execute']),
|
||||
forkBranch: readOption(argv, ['--fork-branch', '--forkBranch']),
|
||||
forkPatchFiles: readOptionList(argv, [
|
||||
'--fork-patch-file',
|
||||
'--fork-patch-files',
|
||||
'--forkPatchFile',
|
||||
'--forkPatchFiles',
|
||||
]),
|
||||
forkRepo: readOption(argv, ['--fork-repo', '--forkRepo']),
|
||||
lastAcceptedUpstreamBase: readOption(argv, [
|
||||
'--last-accepted-upstream-base',
|
||||
'--lastAcceptedUpstreamBase',
|
||||
]),
|
||||
outputSchemaPath: readOption(argv, ['--output-schema', '--outputSchemaPath']),
|
||||
upstreamChangedFiles: readOptionList(argv, [
|
||||
'--upstream-changed-file',
|
||||
'--upstream-changed-files',
|
||||
'--upstreamChangedFile',
|
||||
'--upstreamChangedFiles',
|
||||
]),
|
||||
upstreamReleaseTag: readOption(argv, [
|
||||
'--upstream-release-tag',
|
||||
'--upstream-release-ref',
|
||||
'--upstreamReleaseTag',
|
||||
]),
|
||||
upstreamRepo: readOption(argv, ['--upstream-repo', '--upstreamRepo']),
|
||||
useCodex: hasFlag(argv, ['--use-codex', '--useCodex']),
|
||||
workspaceRoot: readOption(argv, ['--workspace-root', '--workspaceRoot']),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses common dry-run NapCat prompt tool options shared by candidate review, readiness, and handoff modes.
|
||||
* @param argv - Full process argv from a NapCat automation CLI script.
|
||||
* @returns Prompt skeleton input with `execute` false unless explicitly requested by the caller.
|
||||
*/
|
||||
function parseNapcatPromptToolCliArgs(argv: string[]): NapcatSyncCandidateReviewInput {
|
||||
return {
|
||||
artifactRoot: readOption(argv, ['--artifact-root', '--artifactRoot']),
|
||||
candidateBranch: readOption(argv, ['--candidate-branch', '--candidateBranch']),
|
||||
execute: hasFlag(argv, ['--execute']),
|
||||
forkBranch: readOption(argv, ['--fork-branch', '--forkBranch']),
|
||||
forkRepo: readOption(argv, ['--fork-repo', '--forkRepo']),
|
||||
lastAcceptedUpstreamBase: readOption(argv, [
|
||||
'--last-accepted-upstream-base',
|
||||
'--lastAcceptedUpstreamBase',
|
||||
]),
|
||||
upstreamReleaseTag: readOption(argv, [
|
||||
'--upstream-release-tag',
|
||||
'--upstream-release-ref',
|
||||
'--upstreamReleaseTag',
|
||||
]),
|
||||
upstreamRepo: readOption(argv, ['--upstream-repo', '--upstreamRepo']),
|
||||
useCodex: hasFlag(argv, ['--use-codex', '--useCodex']),
|
||||
workspaceRoot: readOption(argv, ['--workspace-root', '--workspaceRoot']),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the NapCat sync-candidate review CLI mode.
|
||||
* @param argv - Full process argv from `pnpm run napcat-sync-candidate-review`.
|
||||
* @returns Dry-run prompt skeleton input for human/Codex candidate review handoff.
|
||||
*/
|
||||
export function parseNapcatSyncCandidateReviewCliArgs(
|
||||
argv: string[],
|
||||
): NapcatSyncCandidateReviewInput {
|
||||
return parseNapcatPromptToolCliArgs(argv);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the NapCat runtime release readiness CLI mode.
|
||||
* @param argv - Full process argv from `pnpm run napcat-runtime-release-readiness`.
|
||||
* @returns Dry-run prompt skeleton input with image/profile hints and no default mutation.
|
||||
*/
|
||||
export function parseNapcatRuntimeReleaseReadinessCliArgs(
|
||||
argv: string[],
|
||||
): NapcatRuntimeReleaseReadinessInput {
|
||||
return {
|
||||
...parseNapcatPromptToolCliArgs(argv),
|
||||
apiImageTag: readOption(argv, ['--api-image-tag', '--apiImageTag']),
|
||||
napcatImageTag: readOption(argv, ['--napcat-image-tag', '--napcatImageTag']),
|
||||
profile: readOption(argv, ['--profile']),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the NapCat remote development handoff CLI mode.
|
||||
* @param argv - Full process argv from `src/server.ts --napcat-remote-dev-handoff`.
|
||||
* @returns Dry-run prompt skeleton input for a remote workspace handoff packet.
|
||||
*/
|
||||
export function parseNapcatRemoteDevHandoffCliArgs(
|
||||
argv: string[],
|
||||
): NapcatRemoteDevHandoffInput {
|
||||
return {
|
||||
...parseNapcatPromptToolCliArgs(argv),
|
||||
targetHost: readOption(argv, ['--target-host', '--targetHost']),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the NAS Codex bootstrap planning CLI mode.
|
||||
* @param argv - Full process argv from `pnpm run nas-codex-bootstrap`.
|
||||
* @returns Dry-run bootstrap plan input; `execute` is false unless the caller explicitly opts in.
|
||||
*/
|
||||
export function parseNasCodexBootstrapCliArgs(
|
||||
argv: string[],
|
||||
): NasCodexBootstrapPlanInput {
|
||||
return {
|
||||
artifactRoot: readOption(argv, ['--artifact-root', '--artifactRoot']),
|
||||
codexHome: readOption(argv, ['--codex-home', '--codexHome']),
|
||||
execute: hasFlag(argv, ['--execute']),
|
||||
serviceName: readOption(argv, ['--service-name', '--serviceName']),
|
||||
workspaceRoot: readOption(argv, ['--workspace-root', '--workspaceRoot']),
|
||||
};
|
||||
}
|
||||
|
||||
export function parseObsidianCliArgs(argv: string[]): ObsidianValidateInput {
|
||||
return {
|
||||
checkLayout: !argv.includes('--no-layout'),
|
||||
|
||||
@ -69,6 +69,11 @@ export const registeredToolNames = [
|
||||
'kt_commit_plan',
|
||||
'kt_push_plan',
|
||||
'kt_business_test_plan',
|
||||
'kt_napcat_upstream_audit',
|
||||
'kt_napcat_sync_candidate_review',
|
||||
'kt_napcat_runtime_release_readiness',
|
||||
'kt_napcat_remote_dev_handoff',
|
||||
'kt_nas_codex_bootstrap_plan',
|
||||
'kt_napcat_device_profile_check',
|
||||
'kt_blocker_resolution',
|
||||
'kt_remote_health_check',
|
||||
|
||||
@ -22,6 +22,13 @@ import { buildVerificationPlan } from './tools/verification.js';
|
||||
import { buildWorkstreamCloseout } from './tools/closeout.js';
|
||||
import { buildChangeDocSync } from './tools/docSync.js';
|
||||
import { buildDeployObservation } from './tools/deployObservation.js';
|
||||
import {
|
||||
buildNapcatRemoteDevHandoff,
|
||||
buildNapcatRuntimeReleaseReadiness,
|
||||
buildNapcatSyncCandidateReview,
|
||||
buildNapcatUpstreamAudit,
|
||||
buildNasCodexBootstrapPlan,
|
||||
} from './tools/napcatAutomation.js';
|
||||
import { buildCommitPlan, buildComponentWorkflow, buildDbSyncPlan, buildFinishTask, buildPushPlan, buildRemoteHealthCheck } from './tools/workflow.js';
|
||||
import { workstreamReusablePatternValues } from './core/constants.js';
|
||||
export function response(data: unknown): McpTextResponse {
|
||||
@ -35,6 +42,11 @@ export function response(data: unknown): McpTextResponse {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers every ktWorkflow MCP tool against the provided MCP server instance.
|
||||
* @param server - MCP SDK server that owns tool names, schemas, descriptions, and async handlers.
|
||||
* @returns Nothing; handlers are attached to `server` for later stdio transport use.
|
||||
*/
|
||||
export function registerTools(server: McpServer): void {
|
||||
server.registerTool(
|
||||
'kt_read_context',
|
||||
@ -370,6 +382,128 @@ export function registerTools(server: McpServer): void {
|
||||
async (input) => response(buildBusinessTestPlan(input)),
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
'kt_napcat_upstream_audit',
|
||||
{
|
||||
description:
|
||||
'生成或执行 NapCatQQ 上游 release 审计:默认 dry-run,只读输出 hot zone、fork patch overlap、dry merge 和 Codex 审计入口;execute/useCodex 均需显式开启才会运行 Codex。',
|
||||
inputSchema: {
|
||||
artifactRoot: z
|
||||
.string()
|
||||
.default('.kt-workspace/test-artifacts/napcat-upstream-audit'),
|
||||
codexHome: z.string().optional(),
|
||||
createCandidateBranch: z.boolean().default(false),
|
||||
dryMergeConflict: z.boolean().default(false),
|
||||
execute: z.boolean().default(false),
|
||||
forkBranch: z.string().default('HEAD'),
|
||||
forkPatchFiles: z.array(z.string()).default([]),
|
||||
forkRepo: z.string().default('KTeam/NapCatQQ'),
|
||||
lastAcceptedUpstreamBase: z.string().default('origin/main'),
|
||||
outputSchemaPath: z.string().optional(),
|
||||
upstreamChangedFiles: z.array(z.string()).default([]),
|
||||
upstreamReleaseTag: z.string().default('upstream/main'),
|
||||
upstreamRepo: z.string().default('NapNeko/NapCatQQ'),
|
||||
useCodex: z.boolean().default(false),
|
||||
workspaceRoot: z.string().default('/vol1/docker/kt-codex/workspace/KT'),
|
||||
},
|
||||
title: 'KT NapCat Upstream Audit',
|
||||
},
|
||||
async (input) => response(buildNapcatUpstreamAudit(input)),
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
'kt_napcat_sync_candidate_review',
|
||||
{
|
||||
description:
|
||||
'生成 NapCatQQ sync candidate 人工/Codex 复审的 dry-run prompt、上下文和只读命令骨架;Task 5 不执行 Codex 或 Git 写操作。',
|
||||
inputSchema: {
|
||||
artifactRoot: z
|
||||
.string()
|
||||
.default('.kt-workspace/test-artifacts/napcat-automation/sync-candidate-review'),
|
||||
candidateBranch: z.string().default('napcat-upstream-sync/candidate'),
|
||||
execute: z.boolean().default(false),
|
||||
forkBranch: z.string().default('dev'),
|
||||
forkRepo: z.string().default('KTeam/NapCatQQ'),
|
||||
lastAcceptedUpstreamBase: z.string().default('origin/main'),
|
||||
upstreamReleaseTag: z.string().default('upstream/main'),
|
||||
upstreamRepo: z.string().default('NapNeko/NapCatQQ'),
|
||||
useCodex: z.boolean().default(false),
|
||||
workspaceRoot: z.string().default('/vol1/docker/kt-codex/workspace/KT'),
|
||||
},
|
||||
title: 'KT NapCat Sync Candidate Review',
|
||||
},
|
||||
async (input) => response(buildNapcatSyncCandidateReview(input)),
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
'kt_napcat_runtime_release_readiness',
|
||||
{
|
||||
description:
|
||||
'生成 NapCat runtime release readiness dry-run prompt、上下文和只读检查骨架;不自动构建镜像、不调用 kubectl、不发布。',
|
||||
inputSchema: {
|
||||
apiImageTag: z.string().default('main-<jenkins-build>'),
|
||||
artifactRoot: z
|
||||
.string()
|
||||
.default('.kt-workspace/test-artifacts/napcat-automation/runtime-release-readiness'),
|
||||
candidateBranch: z.string().default('napcat-upstream-sync/candidate'),
|
||||
execute: z.boolean().default(false),
|
||||
forkBranch: z.string().default('dev'),
|
||||
forkRepo: z.string().default('KTeam/NapCatQQ'),
|
||||
napcatImageTag: z.string().default('kt-napcat-desktop-cn:desktop-cn'),
|
||||
profile: z.string().default('desktop-cn'),
|
||||
upstreamReleaseTag: z.string().default('upstream/main'),
|
||||
upstreamRepo: z.string().default('NapNeko/NapCatQQ'),
|
||||
useCodex: z.boolean().default(false),
|
||||
workspaceRoot: z.string().default('/vol1/docker/kt-codex/workspace/KT'),
|
||||
},
|
||||
title: 'KT NapCat Runtime Release Readiness',
|
||||
},
|
||||
async (input) => response(buildNapcatRuntimeReleaseReadiness(input)),
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
'kt_napcat_remote_dev_handoff',
|
||||
{
|
||||
description:
|
||||
'生成 NapCat 自动化远程开发 handoff 的 dry-run prompt 和上下文骨架;不创建线程、不执行 Codex、不同步仓库。',
|
||||
inputSchema: {
|
||||
artifactRoot: z
|
||||
.string()
|
||||
.default('.kt-workspace/test-artifacts/napcat-automation/remote-dev-handoff'),
|
||||
candidateBranch: z.string().default('napcat-upstream-sync/candidate'),
|
||||
execute: z.boolean().default(false),
|
||||
forkBranch: z.string().default('dev'),
|
||||
forkRepo: z.string().default('KTeam/NapCatQQ'),
|
||||
targetHost: z.string().default('nas'),
|
||||
upstreamReleaseTag: z.string().default('upstream/main'),
|
||||
upstreamRepo: z.string().default('NapNeko/NapCatQQ'),
|
||||
useCodex: z.boolean().default(false),
|
||||
workspaceRoot: z.string().default('/vol1/docker/kt-codex/workspace/KT'),
|
||||
},
|
||||
title: 'KT NapCat Remote Dev Handoff',
|
||||
},
|
||||
async (input) => response(buildNapcatRemoteDevHandoff(input)),
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
'kt_nas_codex_bootstrap_plan',
|
||||
{
|
||||
description:
|
||||
'生成可信 NAS Codex 自动化环境 bootstrap 的 dry-run plan;Task 5 仅输出只读检查和占位计划,不安装、不同步、不写 systemd。',
|
||||
inputSchema: {
|
||||
artifactRoot: z
|
||||
.string()
|
||||
.default('.kt-workspace/test-artifacts/napcat-automation/nas-codex-bootstrap'),
|
||||
codexHome: z.string().default('/vol1/docker/kt-codex/home/.codex'),
|
||||
execute: z.boolean().default(false),
|
||||
serviceName: z.string().default('kt-codex-automation'),
|
||||
workspaceRoot: z.string().default('/vol1/docker/kt-codex/workspace/KT'),
|
||||
},
|
||||
title: 'KT NAS Codex Bootstrap Plan',
|
||||
},
|
||||
async (input) => response(buildNasCodexBootstrapPlan(input)),
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
'kt_napcat_device_profile_check',
|
||||
{
|
||||
|
||||
@ -2,8 +2,12 @@ import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node
|
||||
import path from "node:path";
|
||||
|
||||
import {
|
||||
parseNasCodexBootstrapCliArgs,
|
||||
parseDeployObservationCliArgs,
|
||||
parseGlobalReviewCliArgs,
|
||||
parseNapcatRuntimeReleaseReadinessCliArgs,
|
||||
parseNapcatSyncCandidateReviewCliArgs,
|
||||
parseNapcatUpstreamAuditCliArgs,
|
||||
parseWorkstreamCloseoutCliArgs,
|
||||
} from "./core/cli.js";
|
||||
import { registeredToolNames } from "./core/constants.js";
|
||||
@ -96,6 +100,51 @@ export async function runSelfTest(): Promise<void> {
|
||||
if (!napcatAutomationReasonCodes.includes("HOT_ZONE_CHANGED")) {
|
||||
throw new Error("NapCat reason-code list self-check failed");
|
||||
}
|
||||
const napcatCli = parseNapcatUpstreamAuditCliArgs([
|
||||
"node",
|
||||
"server",
|
||||
"--napcat-upstream-audit",
|
||||
"--execute",
|
||||
"--use-codex",
|
||||
"--artifact-root",
|
||||
"/vol1/docker/kt-codex/artifacts/napcat-upstream-sync",
|
||||
]);
|
||||
if (!napcatCli.execute || !napcatCli.useCodex) {
|
||||
throw new Error("NapCat upstream audit CLI parser self-check failed");
|
||||
}
|
||||
const napcatCandidateCli = parseNapcatSyncCandidateReviewCliArgs([
|
||||
"node",
|
||||
"server",
|
||||
"--napcat-sync-candidate-review",
|
||||
]);
|
||||
const napcatRuntimeCli = parseNapcatRuntimeReleaseReadinessCliArgs([
|
||||
"node",
|
||||
"server",
|
||||
"--napcat-runtime-release-readiness",
|
||||
]);
|
||||
const nasBootstrapCli = parseNasCodexBootstrapCliArgs([
|
||||
"node",
|
||||
"server",
|
||||
"--nas-codex-bootstrap",
|
||||
]);
|
||||
if (
|
||||
napcatCandidateCli.execute ||
|
||||
napcatRuntimeCli.execute ||
|
||||
nasBootstrapCli.execute
|
||||
) {
|
||||
throw new Error("NapCat auxiliary CLI dry-run default self-check failed");
|
||||
}
|
||||
for (const toolName of [
|
||||
"kt_napcat_upstream_audit",
|
||||
"kt_napcat_sync_candidate_review",
|
||||
"kt_napcat_runtime_release_readiness",
|
||||
"kt_napcat_remote_dev_handoff",
|
||||
"kt_nas_codex_bootstrap_plan",
|
||||
] as const) {
|
||||
if (!registeredToolNames.includes(toolName)) {
|
||||
throw new Error(`NapCat MCP tool registry self-check failed: ${toolName}`);
|
||||
}
|
||||
}
|
||||
if (parseNapcatAutomationClassification("manual-review") !== "manual-review") {
|
||||
throw new Error("NapCat classification parser self-check failed");
|
||||
}
|
||||
|
||||
@ -3,8 +3,13 @@ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
||||
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
||||
|
||||
import {
|
||||
parseNasCodexBootstrapCliArgs,
|
||||
parseDeployObservationCliArgs,
|
||||
parseGlobalReviewCliArgs,
|
||||
parseNapcatRemoteDevHandoffCliArgs,
|
||||
parseNapcatRuntimeReleaseReadinessCliArgs,
|
||||
parseNapcatSyncCandidateReviewCliArgs,
|
||||
parseNapcatUpstreamAuditCliArgs,
|
||||
parseObsidianContextCliArgs,
|
||||
parseObsidianCliArgs,
|
||||
parseObsidianSyncCliArgs,
|
||||
@ -18,6 +23,13 @@ import { buildGlobalCodeReview } from './tools/review.js';
|
||||
import { registerTools } from './registerTools.js';
|
||||
import { runSelfTest } from './selfTest.js';
|
||||
import { buildNapcatDeviceProfileCheck } from './tools/testing.js';
|
||||
import {
|
||||
buildNapcatRemoteDevHandoff,
|
||||
buildNapcatRuntimeReleaseReadiness,
|
||||
buildNapcatSyncCandidateReview,
|
||||
buildNapcatUpstreamAudit,
|
||||
buildNasCodexBootstrapPlan,
|
||||
} from './tools/napcatAutomation.js';
|
||||
|
||||
if (process.argv.includes('--cleanup-history')) {
|
||||
console.log(JSON.stringify(cleanupHistoryArtifacts(parseCliCleanupArgs(process.argv)), null, 2));
|
||||
@ -43,6 +55,38 @@ if (process.argv.includes('--cleanup-history')) {
|
||||
2,
|
||||
),
|
||||
);
|
||||
} else if (process.argv.includes('--napcat-upstream-audit')) {
|
||||
console.log(
|
||||
JSON.stringify(buildNapcatUpstreamAudit(parseNapcatUpstreamAuditCliArgs(process.argv)), null, 2),
|
||||
);
|
||||
} else if (process.argv.includes('--napcat-sync-candidate-review')) {
|
||||
console.log(
|
||||
JSON.stringify(
|
||||
buildNapcatSyncCandidateReview(parseNapcatSyncCandidateReviewCliArgs(process.argv)),
|
||||
null,
|
||||
2,
|
||||
),
|
||||
);
|
||||
} else if (process.argv.includes('--napcat-runtime-release-readiness')) {
|
||||
console.log(
|
||||
JSON.stringify(
|
||||
buildNapcatRuntimeReleaseReadiness(parseNapcatRuntimeReleaseReadinessCliArgs(process.argv)),
|
||||
null,
|
||||
2,
|
||||
),
|
||||
);
|
||||
} else if (process.argv.includes('--napcat-remote-dev-handoff')) {
|
||||
console.log(
|
||||
JSON.stringify(
|
||||
buildNapcatRemoteDevHandoff(parseNapcatRemoteDevHandoffCliArgs(process.argv)),
|
||||
null,
|
||||
2,
|
||||
),
|
||||
);
|
||||
} else if (process.argv.includes('--nas-codex-bootstrap')) {
|
||||
console.log(
|
||||
JSON.stringify(buildNasCodexBootstrapPlan(parseNasCodexBootstrapCliArgs(process.argv)), null, 2),
|
||||
);
|
||||
} else if (process.argv.includes('--self-test')) {
|
||||
await runSelfTest();
|
||||
} else if (process.argv.includes('--workstream-closeout')) {
|
||||
|
||||
@ -3,8 +3,18 @@ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
||||
import path from 'node:path';
|
||||
|
||||
import { upstreamAuditOutputSchema } from './napcatAutomation.types.js';
|
||||
import { loadNapcatAutomationPrompt } from './napcatAutomation.prompts.js';
|
||||
import {
|
||||
loadNapcatAutomationPrompt,
|
||||
type NapcatAutomationPromptName,
|
||||
} from './napcatAutomation.prompts.js';
|
||||
import { workspaceRoot } from '../core/workspace.js';
|
||||
import type {
|
||||
NapcatPromptToolInput,
|
||||
NapcatRemoteDevHandoffInput,
|
||||
NapcatRuntimeReleaseReadinessInput,
|
||||
NapcatSyncCandidateReviewInput,
|
||||
NasCodexBootstrapPlanInput,
|
||||
} from '../types.js';
|
||||
import type {
|
||||
NapcatAuditClassificationInput,
|
||||
NapcatAuditClassificationResult,
|
||||
@ -88,6 +98,279 @@ const hotZoneMatchers: Array<{ pattern: string; regex: RegExp }> = [
|
||||
|
||||
const napcatNasCodexArtifactRoot = '/vol1/docker/kt-codex/artifacts';
|
||||
const napcatLocalArtifactRoot = '.kt-workspace/test-artifacts';
|
||||
const napcatAutomationSkeletonArtifactRoot =
|
||||
'.kt-workspace/test-artifacts/napcat-automation';
|
||||
const defaultNapcatForkRepo = 'KTeam/NapCatQQ';
|
||||
const defaultNapcatUpstreamRepo = 'NapNeko/NapCatQQ';
|
||||
const defaultNapcatCandidateBranch = 'napcat-upstream-sync/candidate';
|
||||
const defaultNapcatWorkspaceRoot = '/vol1/docker/kt-codex/workspace/KT';
|
||||
|
||||
interface NapcatPromptSkeletonConfig {
|
||||
artifactSlug: string;
|
||||
commands: NapcatAuditCommand[];
|
||||
context: Record<string, unknown>;
|
||||
input: NapcatPromptToolInput;
|
||||
notes: string[];
|
||||
promptName: NapcatAutomationPromptName;
|
||||
title: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the artifact root shown by dry-run NapCat prompt skeleton tools.
|
||||
* @param input - Prompt tool input carrying an optional artifactRoot override.
|
||||
* @param artifactSlug - Stable child directory name for the specific automation tool.
|
||||
* @returns The caller-provided artifact root, or the ktWorkflow test-artifact default for this tool.
|
||||
*/
|
||||
function resolveNapcatSkeletonArtifactRoot(
|
||||
input: NapcatPromptToolInput,
|
||||
artifactSlug: string,
|
||||
): string {
|
||||
return (
|
||||
input.artifactRoot?.trim() ||
|
||||
`${napcatAutomationSkeletonArtifactRoot}/${artifactSlug}`
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a deterministic dry-run prompt skeleton for Task 5 NapCat automation tools that are not allowed to mutate state yet.
|
||||
* @param config - Prompt name, context payload, read-only command hints, and caller execution intent.
|
||||
* @returns A structured prompt/context/command package that never runs Codex or mutating release commands.
|
||||
*/
|
||||
function buildNapcatPromptSkeleton(config: NapcatPromptSkeletonConfig) {
|
||||
const artifactRoot = resolveNapcatSkeletonArtifactRoot(
|
||||
config.input,
|
||||
config.artifactSlug,
|
||||
);
|
||||
const requestedExecute = config.input.execute === true;
|
||||
|
||||
return {
|
||||
artifacts: [
|
||||
{
|
||||
path: joinNapcatArtifactPath(
|
||||
artifactRoot,
|
||||
`${config.artifactSlug}-prompt.md`,
|
||||
),
|
||||
type: 'markdown',
|
||||
},
|
||||
{
|
||||
path: joinNapcatArtifactPath(
|
||||
artifactRoot,
|
||||
`${config.artifactSlug}-context.json`,
|
||||
),
|
||||
type: 'json',
|
||||
},
|
||||
],
|
||||
commands: config.commands,
|
||||
context: config.context,
|
||||
execute: false,
|
||||
notes: [
|
||||
'Task 5 dry-run skeleton only; no Codex, git merge, git push, docker build, kubectl, or deploy command is executed.',
|
||||
requestedExecute
|
||||
? 'execute=true was requested, but this Task 5 skeleton intentionally remains non-mutating until the later implementation task.'
|
||||
: 'execute defaults to false.',
|
||||
...config.notes,
|
||||
],
|
||||
prompt: {
|
||||
name: config.promptName,
|
||||
text: loadNapcatAutomationPrompt(config.promptName).trim(),
|
||||
},
|
||||
requestedExecute,
|
||||
summary: `${config.title} dry-run prompt skeleton generated.`,
|
||||
useCodex: config.input.useCodex === true,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a dry-run prompt skeleton for reviewing a NapCat upstream sync candidate branch.
|
||||
* @param input - Candidate branch, fork/upstream refs, artifact root, and execution intent; execution is never performed in Task 5.
|
||||
* @returns Prompt, context, artifacts, and read-only command hints for candidate review.
|
||||
*/
|
||||
export function buildNapcatSyncCandidateReview(
|
||||
input: NapcatSyncCandidateReviewInput,
|
||||
) {
|
||||
const context = {
|
||||
candidateBranch: input.candidateBranch ?? defaultNapcatCandidateBranch,
|
||||
forkBranch: input.forkBranch ?? 'dev',
|
||||
forkRepo: input.forkRepo ?? defaultNapcatForkRepo,
|
||||
lastAcceptedUpstreamBase:
|
||||
input.lastAcceptedUpstreamBase ?? 'LAST_ACCEPTED_UPSTREAM_BASE',
|
||||
upstreamReleaseTag: input.upstreamReleaseTag ?? 'UPSTREAM_RELEASE_REF',
|
||||
upstreamRepo: input.upstreamRepo ?? defaultNapcatUpstreamRepo,
|
||||
workspaceRoot: input.workspaceRoot ?? defaultNapcatWorkspaceRoot,
|
||||
};
|
||||
|
||||
return buildNapcatPromptSkeleton({
|
||||
artifactSlug: 'sync-candidate-review',
|
||||
commands: [
|
||||
{
|
||||
command: 'git status --short --branch',
|
||||
description: 'Confirm the candidate worktree state before review.',
|
||||
readOnly: true,
|
||||
},
|
||||
{
|
||||
command:
|
||||
'git log --oneline --decorate -n 20 "${CANDIDATE_BRANCH:-napcat-upstream-sync/candidate}"',
|
||||
description: 'Inspect recent candidate commits without changing refs.',
|
||||
readOnly: true,
|
||||
},
|
||||
{
|
||||
command:
|
||||
'git diff --stat "${LAST_ACCEPTED_UPSTREAM_BASE:-origin/main}..${CANDIDATE_BRANCH:-napcat-upstream-sync/candidate}"',
|
||||
description: 'Summarize candidate file churn for human review.',
|
||||
readOnly: true,
|
||||
},
|
||||
],
|
||||
context,
|
||||
input,
|
||||
notes: [
|
||||
'Use this skeleton after upstream audit classifies a candidate as safe enough for human review.',
|
||||
],
|
||||
promptName: 'sync-candidate-review',
|
||||
title: 'NapCat sync candidate review',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a dry-run prompt skeleton for checking NapCat runtime release readiness.
|
||||
* @param input - Image/profile hints and repo refs used to prepare readiness context; execution is never performed in Task 5.
|
||||
* @returns Prompt, context, artifacts, and bounded read-only command hints for readiness review.
|
||||
*/
|
||||
export function buildNapcatRuntimeReleaseReadiness(
|
||||
input: NapcatRuntimeReleaseReadinessInput,
|
||||
) {
|
||||
const context = {
|
||||
apiImageTag: input.apiImageTag ?? 'main-<jenkins-build>',
|
||||
candidateBranch: input.candidateBranch ?? defaultNapcatCandidateBranch,
|
||||
forkRepo: input.forkRepo ?? defaultNapcatForkRepo,
|
||||
napcatImageTag: input.napcatImageTag ?? 'kt-napcat-desktop-cn:<profile>',
|
||||
profile: input.profile ?? 'desktop-cn',
|
||||
upstreamReleaseTag: input.upstreamReleaseTag ?? 'UPSTREAM_RELEASE_REF',
|
||||
workspaceRoot: input.workspaceRoot ?? defaultNapcatWorkspaceRoot,
|
||||
};
|
||||
|
||||
return buildNapcatPromptSkeleton({
|
||||
artifactSlug: 'runtime-release-readiness',
|
||||
commands: [
|
||||
{
|
||||
command: 'git status --short --branch',
|
||||
description: 'Confirm local release metadata is not mixed with unrelated changes.',
|
||||
readOnly: true,
|
||||
},
|
||||
{
|
||||
command:
|
||||
'docker image inspect "${NAPCAT_IMAGE_TAG:-kt-napcat-desktop-cn:desktop-cn}"',
|
||||
description: 'Read the NAS-local NapCat image metadata without pulling or building.',
|
||||
readOnly: true,
|
||||
},
|
||||
{
|
||||
command:
|
||||
'curl -fsS --max-time 8 "${API_HEALTH_URL:-http://127.0.0.1:48085/health/runtime}"',
|
||||
description: 'Read the API runtime health endpoint before any release promotion.',
|
||||
readOnly: true,
|
||||
},
|
||||
],
|
||||
context,
|
||||
input,
|
||||
notes: [
|
||||
'Deployment and Kubernetes evidence must be collected by the existing deploy-observation workflow after explicit human approval.',
|
||||
],
|
||||
promptName: 'runtime-release-readiness',
|
||||
title: 'NapCat runtime release readiness',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a dry-run prompt skeleton for handing NapCat automation work to a trusted remote Codex workspace.
|
||||
* @param input - Fork/ref hints, remote target label, and artifact location for the handoff packet.
|
||||
* @returns Prompt, context, artifacts, and read-only local command hints for a remote handoff.
|
||||
*/
|
||||
export function buildNapcatRemoteDevHandoff(
|
||||
input: NapcatRemoteDevHandoffInput,
|
||||
) {
|
||||
const context = {
|
||||
candidateBranch: input.candidateBranch ?? defaultNapcatCandidateBranch,
|
||||
forkRepo: input.forkRepo ?? defaultNapcatForkRepo,
|
||||
targetHost: input.targetHost ?? 'nas',
|
||||
upstreamReleaseTag: input.upstreamReleaseTag ?? 'UPSTREAM_RELEASE_REF',
|
||||
workspaceRoot: input.workspaceRoot ?? defaultNapcatWorkspaceRoot,
|
||||
};
|
||||
|
||||
return buildNapcatPromptSkeleton({
|
||||
artifactSlug: 'remote-dev-handoff',
|
||||
commands: [
|
||||
{
|
||||
command: 'git rev-parse HEAD',
|
||||
description: 'Capture the local ktWorkflow commit used to prepare the handoff.',
|
||||
readOnly: true,
|
||||
},
|
||||
{
|
||||
command: 'git status --short --branch',
|
||||
description: 'Confirm no unrelated local state enters the handoff packet.',
|
||||
readOnly: true,
|
||||
},
|
||||
],
|
||||
context,
|
||||
input,
|
||||
notes: [
|
||||
'The returned context is for a future remote session only; this tool does not spawn a subagent or run Codex.',
|
||||
],
|
||||
promptName: 'remote-dev-handoff',
|
||||
title: 'NapCat remote dev handoff',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a non-mutating NAS Codex bootstrap plan placeholder for later automation tasks.
|
||||
* @param input - Trusted NAS workspace/Codex-home hints and optional service name; execution is intentionally not implemented in Task 5.
|
||||
* @returns A dry-run bootstrap checklist and read-only verification commands.
|
||||
*/
|
||||
export function buildNasCodexBootstrapPlan(input: NasCodexBootstrapPlanInput) {
|
||||
const artifactRoot =
|
||||
input.artifactRoot?.trim() ||
|
||||
`${napcatAutomationSkeletonArtifactRoot}/nas-codex-bootstrap`;
|
||||
const context = {
|
||||
codexHome: input.codexHome ?? '/vol1/docker/kt-codex/home/.codex',
|
||||
serviceName: input.serviceName ?? 'kt-codex-automation',
|
||||
workspaceRoot: input.workspaceRoot ?? defaultNapcatWorkspaceRoot,
|
||||
};
|
||||
const requestedExecute = input.execute === true;
|
||||
|
||||
return {
|
||||
artifacts: [
|
||||
{
|
||||
path: joinNapcatArtifactPath(artifactRoot, 'nas-codex-bootstrap-plan.md'),
|
||||
type: 'markdown',
|
||||
},
|
||||
{
|
||||
path: joinNapcatArtifactPath(artifactRoot, 'nas-codex-bootstrap-context.json'),
|
||||
type: 'json',
|
||||
},
|
||||
],
|
||||
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,
|
||||
execute: false,
|
||||
notes: [
|
||||
'Task 5 only exposes a dry-run bootstrap plan. Task 6 must implement real NAS bootstrap logic before any mutation is allowed.',
|
||||
requestedExecute
|
||||
? 'execute=true was requested, but no bootstrap mutation is performed by this placeholder.'
|
||||
: 'execute defaults to false.',
|
||||
],
|
||||
requestedExecute,
|
||||
summary: 'NAS Codex bootstrap dry-run plan generated.',
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Quotes a POSIX shell path argument for NAS-side Codex automation commands.
|
||||
|
||||
34
src/types.ts
34
src/types.ts
@ -189,6 +189,40 @@ export interface NapcatDeviceProfileCheckInput {
|
||||
project?: string;
|
||||
}
|
||||
|
||||
export interface NapcatPromptToolInput {
|
||||
artifactRoot?: string;
|
||||
candidateBranch?: string;
|
||||
execute?: boolean;
|
||||
forkBranch?: string;
|
||||
forkRepo?: string;
|
||||
upstreamReleaseTag?: string;
|
||||
upstreamRepo?: string;
|
||||
useCodex?: boolean;
|
||||
workspaceRoot?: string;
|
||||
}
|
||||
|
||||
export interface NapcatSyncCandidateReviewInput extends NapcatPromptToolInput {
|
||||
lastAcceptedUpstreamBase?: string;
|
||||
}
|
||||
|
||||
export interface NapcatRuntimeReleaseReadinessInput extends NapcatPromptToolInput {
|
||||
apiImageTag?: string;
|
||||
napcatImageTag?: string;
|
||||
profile?: string;
|
||||
}
|
||||
|
||||
export interface NapcatRemoteDevHandoffInput extends NapcatPromptToolInput {
|
||||
targetHost?: string;
|
||||
}
|
||||
|
||||
export interface NasCodexBootstrapPlanInput {
|
||||
artifactRoot?: string;
|
||||
codexHome?: string;
|
||||
execute?: boolean;
|
||||
serviceName?: string;
|
||||
workspaceRoot?: string;
|
||||
}
|
||||
|
||||
export interface BlockerResolutionInput {
|
||||
attempts?: number;
|
||||
command?: string;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user