@nggaigc/cli 0.1.45 → 0.1.48
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.
- package/README.md +11 -3
- package/dist/agent-selection.js +91 -0
- package/dist/bundle.js +1 -1
- package/dist/errors.js +49 -1
- package/dist/install.js +47 -10
- package/dist/main.js +40 -11
- package/dist/skill-command.js +1 -1
- package/dist/skill-location.js +28 -1
- package/package.json +1 -1
- package/vendor/manifest.json +14 -14
- package/vendor/{nggaigc-plugin-1.1.44.zip → nggaigc-plugin-1.1.46.zip} +0 -0
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @nggaigc/cli
|
|
2
2
|
|
|
3
|
-
NGGAIGC Skill
|
|
3
|
+
NGGAIGC Skill 的受信安装器。Codex 与 WorkBuddy 使用同一条安装命令,自动识别当前宿主。
|
|
4
4
|
|
|
5
5
|
```powershell
|
|
6
6
|
npx --yes @nggaigc/cli@latest install
|
|
@@ -12,7 +12,15 @@ CLI 保留 macOS npm symlink 入口与 packed-TGZ launcher 检查,并验证随
|
|
|
12
12
|
|
|
13
13
|
macOS arm64 辅助程序沿用已签名 Plugin 中通过完整性校验的字节;Intel Mac 不在支持范围内。实际公开版本和 `@latest` 状态以 npm registry 为准,Apple Silicon 真机验收需单独进行。
|
|
14
14
|
|
|
15
|
-
##
|
|
15
|
+
## 统一安装入口(0.1.46 起)
|
|
16
|
+
|
|
17
|
+
不带目录参数时,`install`、`start-skill`、`client` 使用同一套宿主识别:Codex 的当前会话标记,或 WorkBuddy 的会话标记/实际工作会话与专属应用标记组合。配置目录、已安装应用和通用终端变量本身不代表当前宿主;环境标记只是便利提示,不用于认证或授权。
|
|
18
|
+
|
|
19
|
+
无法识别或同时命中两个宿主时,有交互终端可选择 Codex 或 WorkBuddy;非交互调用立即返回 `status: selection-required`、两项 `choices` 和退出码 3,不安装、不打开授权网页。当前 Agent 应让用户选择一次,再把 `--agent codex` 或 `--agent workbuddy` 加到原命令继续;`client` 的目标选项放在 `--` 分隔符之前,业务参数保持原样。安装结果始终返回真实 `skillsDirectory` 和 `skillPath`,连接失败也保留该位置,后续继续使用同一位置。
|
|
20
|
+
|
|
21
|
+
本次仅 Codex 与 WorkBuddy 为自动识别支持范围;旧 `universal` 与自定义目录参数仍兼容,但不代表其他 Agent 已获验收。
|
|
22
|
+
|
|
23
|
+
## 显式目标(0.1.45 起)
|
|
16
24
|
|
|
17
25
|
下列目标参数与 `client` 桥要求 CLI 0.1.45 或更高版本。旧版本不支持新参数;`@latest` 的实际可用版本以 npm registry 与对应签名制品为准。
|
|
18
26
|
|
|
@@ -24,7 +32,7 @@ npx --yes @nggaigc/cli@latest start-skill skill.<id> [version] --skills-dir "/ab
|
|
|
24
32
|
npx --yes @nggaigc/cli@latest client --skills-dir "/absolute/project/.codebuddy/skills" -- <原command> <原args>
|
|
25
33
|
```
|
|
26
34
|
|
|
27
|
-
`install`、`start-skill` 和 `client` 支持互斥的 `--agent codex|workbuddy|universal` 或 `--skills-dir
|
|
35
|
+
`install`、`start-skill` 和 `client` 支持互斥的 `--agent codex|workbuddy|universal` 或 `--skills-dir <绝对目录>`。识别或选择 Codex 后使用 `CODEX_HOME/skills`,未设置时为 `~/.codex/skills`。WorkBuddy 优先使用实际进程提供的 `WORKBUDDY_CONFIG_DIR/skills`(其次 `CODEBUDDY_CONFIG_DIR/skills`),否则使用 `~/.workbuddy/skills`;在宿主外升级时,若现代目录没有根 Skill 而旧 `~/.codebuddy/skills` 已安装,则继续使用旧位置。不会删除或迁移旧安装。`--skills-dir` 始终精确指定项目级或其他现有安装。universal 使用 `~/.agents/skills`,不保证所有 Agent 自动识别。`--no-login` 仅跳过安装后的登录,不绕过签名、哈希、路径检查或后续鉴权。
|
|
28
36
|
|
|
29
37
|
根 Skill 按实际读取的 `SKILL.md` 定位父目录及其上一级 `skillsDirectory`;后续升级与 `start-skill` 显式使用同一目录。准备回执增加 `skillsDirectory`、`rootLauncherPath`,保留 `preparedSkills`;宿主应显式读取返回的真实路径。独立包的原客户端调用使用回执的受信根启动器;`client` 是同目录根包验签桥,保留原命令/参数,不增加 API 专用业务分支。安装新包不证明当前宿主热加载,必要时开启新会话。
|
|
30
38
|
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { createInterface } from "node:readline/promises";
|
|
2
|
+
import { resolveSkillLocation, } from "./skill-location.js";
|
|
3
|
+
export const agentChoices = [
|
|
4
|
+
{ agent: "codex", label: "Codex" },
|
|
5
|
+
{ agent: "workbuddy", label: "WorkBuddy" },
|
|
6
|
+
];
|
|
7
|
+
export class AgentSelectionRequired extends Error {
|
|
8
|
+
reason;
|
|
9
|
+
code = "AGENT_SELECTION_REQUIRED";
|
|
10
|
+
constructor(reason) {
|
|
11
|
+
super("AGENT_SELECTION_REQUIRED");
|
|
12
|
+
this.reason = reason;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
/** Configuration paths and installed applications are not caller identity. */
|
|
16
|
+
export function detectCallingAgent(environment) {
|
|
17
|
+
const present = (value) => typeof value === "string" && value.trim().length > 0;
|
|
18
|
+
const codex = present(environment.CODEX_THREAD_ID);
|
|
19
|
+
// WorkBuddy's prewarmed runtime omits WORKBUDDY_CONVERSATION_ID. Its shell
|
|
20
|
+
// still has a CodeBuddy session AND WorkBuddy-specific application markers.
|
|
21
|
+
// A standalone CodeBuddy session is deliberately not treated as WorkBuddy.
|
|
22
|
+
const workbuddy = present(environment.WORKBUDDY_CONVERSATION_ID) ||
|
|
23
|
+
(present(environment.CODEBUDDY_SESSION_ID) &&
|
|
24
|
+
present(environment.WORKBUDDY_APP_VERSION) &&
|
|
25
|
+
present(environment.WORKBUDDY_APP_PATH));
|
|
26
|
+
if (codex && workbuddy)
|
|
27
|
+
return { reason: "conflicting" };
|
|
28
|
+
if (codex)
|
|
29
|
+
return { agent: "codex" };
|
|
30
|
+
if (workbuddy)
|
|
31
|
+
return { agent: "workbuddy" };
|
|
32
|
+
return { reason: "unknown" };
|
|
33
|
+
}
|
|
34
|
+
async function chooseInTerminal() {
|
|
35
|
+
const terminal = createInterface({
|
|
36
|
+
input: process.stdin,
|
|
37
|
+
output: process.stderr,
|
|
38
|
+
});
|
|
39
|
+
const controller = new AbortController();
|
|
40
|
+
const cancel = () => controller.abort();
|
|
41
|
+
terminal.once("SIGINT", cancel);
|
|
42
|
+
terminal.once("close", cancel);
|
|
43
|
+
try {
|
|
44
|
+
const answer = (await terminal.question("请选择使用 NGGAIGC 的 AI 助手:1. Codex 2. WorkBuddy\n输入 1 或 2:", { signal: controller.signal }))
|
|
45
|
+
.trim()
|
|
46
|
+
.toLowerCase();
|
|
47
|
+
if (answer === "1" || answer === "codex")
|
|
48
|
+
return "codex";
|
|
49
|
+
if (answer === "2" || answer === "workbuddy")
|
|
50
|
+
return "workbuddy";
|
|
51
|
+
return undefined;
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
56
|
+
finally {
|
|
57
|
+
terminal.off("SIGINT", cancel);
|
|
58
|
+
terminal.off("close", cancel);
|
|
59
|
+
terminal.close();
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
/** Resolve before any installation, browser authorization or client request. */
|
|
63
|
+
export async function selectCommandLocation(options, runtime = {}) {
|
|
64
|
+
const environment = runtime.environment ?? process.env;
|
|
65
|
+
if (options.agent !== undefined ||
|
|
66
|
+
options.skillsDirectory !== undefined ||
|
|
67
|
+
options.codexHome !== undefined) {
|
|
68
|
+
resolveSkillLocation(options, environment);
|
|
69
|
+
return options;
|
|
70
|
+
}
|
|
71
|
+
const detected = detectCallingAgent(environment);
|
|
72
|
+
if ("agent" in detected)
|
|
73
|
+
return { ...options, agent: detected.agent };
|
|
74
|
+
const choose = runtime.choose ??
|
|
75
|
+
(process.stdin.isTTY && process.stderr.isTTY
|
|
76
|
+
? chooseInTerminal
|
|
77
|
+
: undefined);
|
|
78
|
+
const agent = await choose?.();
|
|
79
|
+
if (agent === "codex" || agent === "workbuddy")
|
|
80
|
+
return { ...options, agent };
|
|
81
|
+
throw new AgentSelectionRequired(detected.reason);
|
|
82
|
+
}
|
|
83
|
+
export function selectionRequiredResult(error) {
|
|
84
|
+
return {
|
|
85
|
+
status: "selection-required",
|
|
86
|
+
error: { code: error.code, reason: error.reason },
|
|
87
|
+
message: "请选择当前使用的 AI 助手,然后在原命令中添加 --agent codex 或 --agent workbuddy 继续;client 命令的选项须放在 -- 分隔符之前。",
|
|
88
|
+
choices: agentChoices,
|
|
89
|
+
nextAction: "select-agent-and-retry",
|
|
90
|
+
};
|
|
91
|
+
}
|
package/dist/bundle.js
CHANGED
|
@@ -47,7 +47,7 @@ export async function verifyBundle(input) {
|
|
|
47
47
|
!exactKeys(manifestValue, manifestKeys) ||
|
|
48
48
|
manifestValue.schemaVersion !== "nggaigc-plugin-package/v1" ||
|
|
49
49
|
manifestValue.artifactId !== "plugin.nggaigc" ||
|
|
50
|
-
manifestValue.version !== "1.1.
|
|
50
|
+
manifestValue.version !== "1.1.46" ||
|
|
51
51
|
manifestValue.artifactPath !==
|
|
52
52
|
`packages/plugins/nggaigc-plugin-${manifestValue.version}.zip` ||
|
|
53
53
|
typeof manifestValue.sourceCommit !== "string" ||
|
package/dist/errors.js
CHANGED
|
@@ -1,9 +1,57 @@
|
|
|
1
|
+
const localCauseCodes = new Set([
|
|
2
|
+
"EPERM",
|
|
3
|
+
"EACCES",
|
|
4
|
+
"ENOENT",
|
|
5
|
+
"EAGAIN",
|
|
6
|
+
"EMFILE",
|
|
7
|
+
"ENFILE",
|
|
8
|
+
"ENOMEM",
|
|
9
|
+
"EINVAL",
|
|
10
|
+
"ERR_ACCESS_DENIED",
|
|
11
|
+
"ERR_MODULE_NOT_FOUND",
|
|
12
|
+
"SETUP_REQUIRED",
|
|
13
|
+
"CREDENTIAL_FRAME_INVALID",
|
|
14
|
+
"CREDENTIAL_STORE_FAILED",
|
|
15
|
+
"INVALID_INPUT",
|
|
16
|
+
"CREDENTIAL_CHANGED",
|
|
17
|
+
"ALREADY_CONFIGURED",
|
|
18
|
+
"CREDENTIAL_STORE_UNAVAILABLE",
|
|
19
|
+
"CREDENTIAL_HELPER_START_FAILED",
|
|
20
|
+
"CREDENTIAL_HELPER_FAILED",
|
|
21
|
+
"DISTRIBUTION_INVALID",
|
|
22
|
+
"LOCAL_SESSION_FAILED",
|
|
23
|
+
"LOCAL_SESSION_TIMEOUT",
|
|
24
|
+
"POWERSHELL_EXECUTION_POLICY_BLOCKED",
|
|
25
|
+
"RUNTIME_UNSUPPORTED",
|
|
26
|
+
"UNKNOWN",
|
|
27
|
+
]);
|
|
28
|
+
export function safeConnectionDiagnostics(value) {
|
|
29
|
+
if (value === null || typeof value !== "object" || !("stage" in value))
|
|
30
|
+
return undefined;
|
|
31
|
+
const stage = value.stage;
|
|
32
|
+
if (stage !== "helper_start" && stage !== "credential_verification")
|
|
33
|
+
return undefined;
|
|
34
|
+
const cause = "causeCode" in value ? value.causeCode : undefined;
|
|
35
|
+
return {
|
|
36
|
+
stage,
|
|
37
|
+
causeCode: typeof cause === "string" && localCauseCodes.has(cause)
|
|
38
|
+
? cause
|
|
39
|
+
: "UNKNOWN",
|
|
40
|
+
};
|
|
41
|
+
}
|
|
1
42
|
export class CliError extends Error {
|
|
2
43
|
code;
|
|
3
|
-
|
|
44
|
+
stage;
|
|
45
|
+
causeCode;
|
|
46
|
+
constructor(code, diagnostics) {
|
|
4
47
|
super(code);
|
|
5
48
|
this.code = code;
|
|
6
49
|
this.name = "CliError";
|
|
50
|
+
const safe = safeConnectionDiagnostics(diagnostics);
|
|
51
|
+
if (safe) {
|
|
52
|
+
this.stage = safe.stage;
|
|
53
|
+
this.causeCode = safe.causeCode;
|
|
54
|
+
}
|
|
7
55
|
}
|
|
8
56
|
}
|
|
9
57
|
export function fixedErrorCode(error) {
|
package/dist/install.js
CHANGED
|
@@ -4,12 +4,12 @@ import os from "node:os";
|
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
6
6
|
import { extractBundle, verifyBundle, verifyExtractedBundle, verifyInstalledSkill, } from "./bundle.js";
|
|
7
|
-
import { CliError, fixedErrorCode } from "./errors.js";
|
|
7
|
+
import { CliError, fixedErrorCode, safeConnectionDiagnostics, } from "./errors.js";
|
|
8
8
|
import { resolveSkillLocation, } from "./skill-location.js";
|
|
9
9
|
function defaultBundle() {
|
|
10
10
|
const vendor = fileURLToPath(new URL("../vendor/", import.meta.url));
|
|
11
11
|
return {
|
|
12
|
-
archive: path.join(vendor, "nggaigc-plugin-1.1.
|
|
12
|
+
archive: path.join(vendor, "nggaigc-plugin-1.1.46.zip"),
|
|
13
13
|
manifest: path.join(vendor, "manifest.json"),
|
|
14
14
|
trust: path.join(vendor, "trusted-keys.json"),
|
|
15
15
|
};
|
|
@@ -37,6 +37,47 @@ function installationError(error) {
|
|
|
37
37
|
return new CliError("SKILL_PAIR_RECOVERY_REQUIRED");
|
|
38
38
|
return new CliError("INSTALLATION_FAILED");
|
|
39
39
|
}
|
|
40
|
+
function connectionError(error, fallback) {
|
|
41
|
+
const code = fixedErrorCode(error);
|
|
42
|
+
const localCodes = [
|
|
43
|
+
"CREDENTIAL_HELPER_START_FAILED",
|
|
44
|
+
"CREDENTIAL_VERIFICATION_FAILED",
|
|
45
|
+
"CREDENTIAL_STORE_FAILED",
|
|
46
|
+
"CREDENTIAL_STORE_UNAVAILABLE",
|
|
47
|
+
"CREDENTIAL_FRAME_INVALID",
|
|
48
|
+
"CREDENTIAL_HELPER_FAILED",
|
|
49
|
+
"DISTRIBUTION_INVALID",
|
|
50
|
+
"LOCAL_SESSION_FAILED",
|
|
51
|
+
"LOCAL_SESSION_TIMEOUT",
|
|
52
|
+
"POWERSHELL_EXECUTION_POLICY_BLOCKED",
|
|
53
|
+
"RUNTIME_UNSUPPORTED",
|
|
54
|
+
"UNSUPPORTED_PLATFORM",
|
|
55
|
+
"BROWSER_OPEN_FAILED",
|
|
56
|
+
];
|
|
57
|
+
if (localCodes.includes(code))
|
|
58
|
+
return new CliError(code, error);
|
|
59
|
+
// Older signed launchers can throw a synchronous OS spawn error before
|
|
60
|
+
// they can return a protected error envelope. Keep only this closed cause.
|
|
61
|
+
if (error !== null &&
|
|
62
|
+
typeof error === "object" &&
|
|
63
|
+
"syscall" in error &&
|
|
64
|
+
typeof error.syscall === "string" &&
|
|
65
|
+
/^spawn(?: |$)/.test(error.syscall)) {
|
|
66
|
+
return new CliError("CREDENTIAL_HELPER_START_FAILED", {
|
|
67
|
+
stage: "helper_start",
|
|
68
|
+
causeCode: code,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
if (fallback === "BROWSER_AUTHORIZATION_FAILED" &&
|
|
72
|
+
[
|
|
73
|
+
"AUTHORIZATION_REJECTED",
|
|
74
|
+
"AUTHORIZATION_CANCELLED",
|
|
75
|
+
"ACTIVATION_REJECTED",
|
|
76
|
+
"ACTIVATION_INPUT_INVALID",
|
|
77
|
+
].includes(code ?? ""))
|
|
78
|
+
return new CliError(fallback);
|
|
79
|
+
return new CliError("CONNECTION_VERIFICATION_FAILED");
|
|
80
|
+
}
|
|
40
81
|
async function installedVersion(target) {
|
|
41
82
|
try {
|
|
42
83
|
const marker = JSON.parse(await readFile(path.join(target, ".nggaigc-install.json"), "utf8"));
|
|
@@ -116,10 +157,8 @@ async function connect(launcher, options, report, probe) {
|
|
|
116
157
|
catch (error) {
|
|
117
158
|
if (!probe && fixedErrorCode(error) === "SETUP_REQUIRED")
|
|
118
159
|
configured = false;
|
|
119
|
-
else if (fixedErrorCode(error) === "POWERSHELL_EXECUTION_POLICY_BLOCKED")
|
|
120
|
-
throw new CliError("POWERSHELL_EXECUTION_POLICY_BLOCKED");
|
|
121
160
|
else
|
|
122
|
-
throw
|
|
161
|
+
throw connectionError(error, "CONNECTION_VERIFICATION_FAILED");
|
|
123
162
|
}
|
|
124
163
|
if (!configured) {
|
|
125
164
|
report("launching");
|
|
@@ -157,11 +196,7 @@ async function connect(launcher, options, report, probe) {
|
|
|
157
196
|
throw new Error();
|
|
158
197
|
}
|
|
159
198
|
catch (error) {
|
|
160
|
-
|
|
161
|
-
throw new CliError("BROWSER_OPEN_FAILED");
|
|
162
|
-
if (fixedErrorCode(error) === "POWERSHELL_EXECUTION_POLICY_BLOCKED")
|
|
163
|
-
throw new CliError("POWERSHELL_EXECUTION_POLICY_BLOCKED");
|
|
164
|
-
throw new CliError("BROWSER_AUTHORIZATION_FAILED");
|
|
199
|
+
throw connectionError(error, "BROWSER_AUTHORIZATION_FAILED");
|
|
165
200
|
}
|
|
166
201
|
finally {
|
|
167
202
|
process.off("SIGINT", interrupt);
|
|
@@ -215,11 +250,13 @@ export async function runInstall(options = {}) {
|
|
|
215
250
|
catch (error) {
|
|
216
251
|
if (!(error instanceof CliError))
|
|
217
252
|
throw error;
|
|
253
|
+
const diagnostics = safeConnectionDiagnostics(error);
|
|
218
254
|
return {
|
|
219
255
|
status: "installed-unconnected",
|
|
220
256
|
installation,
|
|
221
257
|
version: bundle.version,
|
|
222
258
|
connectionError: error.code,
|
|
259
|
+
...(diagnostics ? { connectionDiagnostics: diagnostics } : {}),
|
|
223
260
|
};
|
|
224
261
|
}
|
|
225
262
|
}
|
package/dist/main.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
-
import { CliError, fixedErrorCode } from "./errors.js";
|
|
2
|
+
import { CliError, fixedErrorCode, safeConnectionDiagnostics, } from "./errors.js";
|
|
3
3
|
import { runInstall } from "./install.js";
|
|
4
4
|
import { runSkillStartCommand, runClientCommand, } from "./skill-command.js";
|
|
5
5
|
import { parseSkillLocation, resolveSkillLocation } from "./skill-location.js";
|
|
6
|
+
import { AgentSelectionRequired, selectCommandLocation, selectionRequiredResult, } from "./agent-selection.js";
|
|
6
7
|
const messages = {
|
|
7
8
|
authorizing: "浏览器已成功启动,请在 NGGAIGC 页面确认连接…",
|
|
8
9
|
connected: "NGGAIGC Skill 已安装,设备连接验证成功。",
|
|
@@ -16,6 +17,15 @@ const errorMessages = {
|
|
|
16
17
|
BROWSER_AUTHORIZATION_FAILED: "网页授权未完成;请在当前 Agent 中调用 NGGAIGC 继续连接,无需重装。",
|
|
17
18
|
BROWSER_OPEN_FAILED: "系统未能打开默认浏览器,也无法提供手动授权入口;请在当前 Agent 中调用 NGGAIGC 重试连接,无需重装。",
|
|
18
19
|
CONNECTION_VERIFICATION_FAILED: "设备连接验证未完成;请在当前 Agent 中检查连接状态,无需重装。",
|
|
20
|
+
CREDENTIAL_HELPER_START_FAILED: "本地凭据助手未能启动;请先处理当前运行错误,不要重复网页授权或重装。安装器没有更改系统保护。",
|
|
21
|
+
CREDENTIAL_VERIFICATION_FAILED: "凭据写入后的本地验证未完成,已尝试安全清理本次凭据;请先处理原本地错误,不要重复网页授权或重装。",
|
|
22
|
+
CREDENTIAL_STORE_FAILED: "本地凭据保存未完成;请先检查本地存储错误,不要重复网页授权。",
|
|
23
|
+
CREDENTIAL_STORE_UNAVAILABLE: "本地凭据存储暂不可用;请先检查本地运行条件,不要重复网页授权。",
|
|
24
|
+
CREDENTIAL_FRAME_INVALID: "本地凭据数据未能通过校验;请先处理当前本地错误,不要重复网页授权。",
|
|
25
|
+
CREDENTIAL_HELPER_FAILED: "本地凭据助手未能完成操作;请先处理当前本地错误,不要重复网页授权。",
|
|
26
|
+
DISTRIBUTION_INVALID: "本地受信客户端文件无法通过校验;请先检查当前安装,不要重复网页授权或手工修改签名文件。",
|
|
27
|
+
LOCAL_SESSION_FAILED: "本地凭据会话未能完成;请先处理本地错误,不要重复网页授权。",
|
|
28
|
+
LOCAL_SESSION_TIMEOUT: "本地凭据会话超时;请先检查当前本地进程,不要重复网页授权。",
|
|
19
29
|
POWERSHELL_EXECUTION_POLICY_BLOCKED: "Windows 脚本执行受到系统或组织策略限制,设备连接未完成。安装器没有更改执行策略。",
|
|
20
30
|
INSTALLATION_FAILED: "本地安装未完成,请检查现有文件状态后重试。",
|
|
21
31
|
SKILL_PAIR_UPGRADE_REQUIRED: "检测到无法安全配套迁移的本地 Seedream Skill,已停止升级。请保留旧 Skill 和任务文件并联系支持。",
|
|
@@ -34,7 +44,8 @@ export async function main(args, runtime = {}) {
|
|
|
34
44
|
"install [--agent codex|workbuddy|universal | --skills-dir <absolute-directory>] [--no-login]",
|
|
35
45
|
"start-skill skill.<id> [version] [--agent codex|workbuddy|universal | --skills-dir <absolute-directory>]",
|
|
36
46
|
"client [--agent codex|workbuddy|universal | --skills-dir <absolute-directory>] -- <command> [arguments]",
|
|
37
|
-
"Default:
|
|
47
|
+
"Default: automatically detect Codex or WorkBuddy. If unknown or conflicting, select one; non-interactive calls return selection-required (exit 3).",
|
|
48
|
+
"Codex: existing CODEX_HOME is preserved, otherwise ~/.codex/skills. WorkBuddy: its runtime config directory/skills, otherwise ~/.workbuddy/skills; existing legacy ~/.codebuddy installs are reused. Explicit legacy universal/custom targets remain supported.",
|
|
38
49
|
"Use the same target for install and subsequent commands. --no-login installs verified files without opening a browser.",
|
|
39
50
|
"client examples: -- status, -- login, -- account-status, -- workflows, -- history, -- disconnect",
|
|
40
51
|
"",
|
|
@@ -52,7 +63,8 @@ export async function main(args, runtime = {}) {
|
|
|
52
63
|
if (positional.length)
|
|
53
64
|
throw new CliError("INVALID_INPUT");
|
|
54
65
|
process.once("SIGINT", interrupt);
|
|
55
|
-
const
|
|
66
|
+
const selectedLocation = await selectCommandLocation(location, runtime.agentSelection);
|
|
67
|
+
const result = await (runtime.client ?? runClientCommand)(args.slice(separator + 1), selectedLocation, {
|
|
56
68
|
signal: controller.signal,
|
|
57
69
|
browserManualLink: (url) => errorOutput(`如果没有看到授权网页,请在本机浏览器打开此一次性链接;不要转发或保存:\n${url}\n`),
|
|
58
70
|
browserFallback: (url) => errorOutput(`浏览器未能自动打开,请在本机手动打开此一次性链接;不要转发或保存:\n${url}\n`),
|
|
@@ -61,7 +73,11 @@ export async function main(args, runtime = {}) {
|
|
|
61
73
|
return 0;
|
|
62
74
|
}
|
|
63
75
|
catch (error) {
|
|
64
|
-
|
|
76
|
+
if (error instanceof AgentSelectionRequired) {
|
|
77
|
+
output(`${JSON.stringify(selectionRequiredResult(error))}\n`);
|
|
78
|
+
return 3;
|
|
79
|
+
}
|
|
80
|
+
errorOutput(`${JSON.stringify({ error: { code: fixedErrorCode(error) ?? "CLIENT_UNAVAILABLE", ...safeConnectionDiagnostics(error) } })}\n`);
|
|
65
81
|
return 1;
|
|
66
82
|
}
|
|
67
83
|
finally {
|
|
@@ -80,11 +96,16 @@ export async function main(args, runtime = {}) {
|
|
|
80
96
|
if (args[0] === "start-skill" &&
|
|
81
97
|
(parameters.length === 1 || parameters.length === 2)) {
|
|
82
98
|
try {
|
|
83
|
-
const
|
|
99
|
+
const location = await selectCommandLocation({ ...runtime.skillOptions, ...parsed.location }, runtime.agentSelection);
|
|
100
|
+
const result = await (runtime.startSkill ?? runSkillStartCommand)(parameters[0], parameters[1], location);
|
|
84
101
|
output(`${JSON.stringify({ status: "ready", ...result })}\n`);
|
|
85
102
|
return 0;
|
|
86
103
|
}
|
|
87
104
|
catch (error) {
|
|
105
|
+
if (error instanceof AgentSelectionRequired) {
|
|
106
|
+
output(`${JSON.stringify(selectionRequiredResult(error))}\n`);
|
|
107
|
+
return 3;
|
|
108
|
+
}
|
|
88
109
|
const code = fixedErrorCode(error) ?? "SKILL_START_UNAVAILABLE";
|
|
89
110
|
errorOutput(`${JSON.stringify({ error: { code } })}\n`);
|
|
90
111
|
return 1;
|
|
@@ -97,8 +118,10 @@ export async function main(args, runtime = {}) {
|
|
|
97
118
|
return 1;
|
|
98
119
|
}
|
|
99
120
|
try {
|
|
121
|
+
const location = await selectCommandLocation(parsed.location, runtime.agentSelection);
|
|
122
|
+
const { skillsDirectory } = resolveSkillLocation(location);
|
|
100
123
|
const result = await (runtime.install ?? runInstall)({
|
|
101
|
-
...
|
|
124
|
+
...location,
|
|
102
125
|
...(parameters[0] === "--no-login" ? { connect: false } : {}),
|
|
103
126
|
reporter: (event) => output(`${messages[event]}\n`),
|
|
104
127
|
launcherOptionsFactory: () => ({
|
|
@@ -112,18 +135,24 @@ export async function main(args, runtime = {}) {
|
|
|
112
135
|
},
|
|
113
136
|
}),
|
|
114
137
|
});
|
|
138
|
+
output(`${JSON.stringify({
|
|
139
|
+
...result,
|
|
140
|
+
...(location.agent ? { agent: location.agent } : {}),
|
|
141
|
+
skillsDirectory,
|
|
142
|
+
skillPath: path.join(skillsDirectory, "nggaigc", "SKILL.md"),
|
|
143
|
+
guidance: "在当前 AI 助手中调用 NGGAIGC;若未发现新 Skill,请新开一个对话。后续安装、更新和工作流加载沿用此 skillsDirectory。",
|
|
144
|
+
})}\n`);
|
|
115
145
|
if (result.status === "installed-unconnected") {
|
|
116
146
|
errorOutput(`NGGAIGC Skill ${result.version} 文件已${result.installation === "unchanged" ? "存在" : "安装"},但设备尚未连接。${errorMessages[result.connectionError] ?? "请在当前 Agent 中检查连接状态。"}\n`);
|
|
117
147
|
return 2;
|
|
118
148
|
}
|
|
119
|
-
if (result.status === "installed" ||
|
|
120
|
-
Object.keys(parsed.location).length > 0) {
|
|
121
|
-
const { skillsDirectory } = resolveSkillLocation(parsed.location);
|
|
122
|
-
output(`${JSON.stringify({ ...result, skillsDirectory, skillPath: path.join(skillsDirectory, "nggaigc", "SKILL.md") })}\n`);
|
|
123
|
-
}
|
|
124
149
|
return 0;
|
|
125
150
|
}
|
|
126
151
|
catch (error) {
|
|
152
|
+
if (error instanceof AgentSelectionRequired) {
|
|
153
|
+
output(`${JSON.stringify(selectionRequiredResult(error))}\n`);
|
|
154
|
+
return 3;
|
|
155
|
+
}
|
|
127
156
|
const code = error instanceof CliError ? error.code : "INSTALLATION_FAILED";
|
|
128
157
|
errorOutput(`${errorMessages[code] ?? errorMessages.INSTALLATION_FAILED}\n`);
|
|
129
158
|
return 1;
|
package/dist/skill-command.js
CHANGED
|
@@ -15,7 +15,7 @@ function record(value) {
|
|
|
15
15
|
export async function productionDependencies(skillsDirectory) {
|
|
16
16
|
const vendor = fileURLToPath(new URL("../vendor/", import.meta.url));
|
|
17
17
|
const bundle = await verifyBundle({
|
|
18
|
-
archive: path.join(vendor, "nggaigc-plugin-1.1.
|
|
18
|
+
archive: path.join(vendor, "nggaigc-plugin-1.1.46.zip"),
|
|
19
19
|
manifest: path.join(vendor, "manifest.json"),
|
|
20
20
|
trust: path.join(vendor, "trusted-keys.json"),
|
|
21
21
|
});
|
package/dist/skill-location.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import os from "node:os";
|
|
2
2
|
import path from "node:path";
|
|
3
|
+
import { lstatSync } from "node:fs";
|
|
3
4
|
import { CliError } from "./errors.js";
|
|
4
5
|
export function absoluteDirectory(value) {
|
|
5
6
|
if (!path.isAbsolute(value) || /[\0\r\n]/u.test(value))
|
|
@@ -16,6 +17,30 @@ export function stateDirectoryForSkills(skillsDirectory) {
|
|
|
16
17
|
? path.join(path.dirname(skillsDirectory), ".nggaigc-managed")
|
|
17
18
|
: path.join(skillsDirectory, ".nggaigc-managed", "custom-target");
|
|
18
19
|
}
|
|
20
|
+
function hasInstalledRoot(home) {
|
|
21
|
+
try {
|
|
22
|
+
lstatSync(path.join(home, "skills", "nggaigc"));
|
|
23
|
+
return true;
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
if (error.code === "ENOENT")
|
|
27
|
+
return false;
|
|
28
|
+
throw new CliError("INSTALLATION_FAILED");
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
function workbuddyHome(profile, environment) {
|
|
32
|
+
const configured = environment.WORKBUDDY_CONFIG_DIR ?? environment.CODEBUDDY_CONFIG_DIR;
|
|
33
|
+
if (configured !== undefined)
|
|
34
|
+
return absoluteDirectory(configured);
|
|
35
|
+
const current = path.join(profile, ".workbuddy");
|
|
36
|
+
const legacy = path.join(profile, ".codebuddy");
|
|
37
|
+
// Upgrade an existing legacy global installation in place when outside the
|
|
38
|
+
// host. Inside WorkBuddy, its actual runtime configuration takes precedence.
|
|
39
|
+
// The installer still verifies ownership/signatures before changing files.
|
|
40
|
+
return !hasInstalledRoot(current) && hasInstalledRoot(legacy)
|
|
41
|
+
? legacy
|
|
42
|
+
: current;
|
|
43
|
+
}
|
|
19
44
|
/** One explicit location for root installation and every dependent Skill. */
|
|
20
45
|
export function resolveSkillLocation(options = {}, environment = process.env) {
|
|
21
46
|
if ([options.agent, options.skillsDirectory, options.codexHome].filter((value) => value !== undefined).length > 1)
|
|
@@ -36,7 +61,9 @@ export function resolveSkillLocation(options = {}, environment = process.env) {
|
|
|
36
61
|
? ((options.profile === undefined
|
|
37
62
|
? environment.CODEX_HOME
|
|
38
63
|
: undefined) ?? path.join(profile, ".codex"))
|
|
39
|
-
:
|
|
64
|
+
: agent === "workbuddy"
|
|
65
|
+
? workbuddyHome(profile, options.profile === undefined ? environment : {})
|
|
66
|
+
: path.join(profile, ".agents")));
|
|
40
67
|
return {
|
|
41
68
|
skillsDirectory: path.join(home, "skills"),
|
|
42
69
|
// Explicit and named-host calls for the same directory share one journal.
|
package/package.json
CHANGED
package/vendor/manifest.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": "nggaigc-plugin-package/v1",
|
|
3
3
|
"artifactId": "plugin.nggaigc",
|
|
4
|
-
"version": "1.1.
|
|
5
|
-
"sourceCommit": "
|
|
6
|
-
"artifactPath": "packages/plugins/nggaigc-plugin-1.1.
|
|
7
|
-
"sha256": "
|
|
8
|
-
"sizeBytes":
|
|
4
|
+
"version": "1.1.46",
|
|
5
|
+
"sourceCommit": "890744f5f9d7687c8edb182b78a308f883495109",
|
|
6
|
+
"artifactPath": "packages/plugins/nggaigc-plugin-1.1.46.zip",
|
|
7
|
+
"sha256": "9e419880e02ad7e578708e36ced067f75a073f9f0fac19a35041607b60571489",
|
|
8
|
+
"sizeBytes": 502681,
|
|
9
9
|
"fileCount": 24,
|
|
10
10
|
"platforms": [
|
|
11
11
|
"win32-x64",
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"darwin-arm64"
|
|
14
14
|
],
|
|
15
15
|
"files": {
|
|
16
|
-
".codex-plugin/plugin.json": "
|
|
16
|
+
".codex-plugin/plugin.json": "41aa7f0e7d6769b1fef20e103390a1e1ad404f0ea43db80000026231a82b6076",
|
|
17
17
|
"installer/install.cjs": "76f4ed73233fd39900fb0bedbc434dea39e52e6b6b4622f3fd388a5ca09c6f62",
|
|
18
18
|
"installer/legacy-root-digests.json": "922552646a5aa6cff8616c372912a37b1d5f263351206b85785ed9b2eae31641",
|
|
19
19
|
"installer/signed-pair-1.1.16.json": "ccb22a90302cc5c9c585067ebc211a27b0c9d8a177c2740a5678a58a3d70bfe9",
|
|
@@ -24,24 +24,24 @@
|
|
|
24
24
|
"migration/seedream-1.1.3/scripts/seedream.mjs": "dcc6af4d945790d9dfd7fac21c60934759d7ac2576a14507d0299f4833942a96",
|
|
25
25
|
"migration/seedream-1.1.3/SKILL.md": "5c5cf3c2d99376f246425e873c5566436ed528256372ac3208abb60364c4517c",
|
|
26
26
|
"skills/nggaigc/agents/openai.yaml": "8936d97b9821e687e224e9349cc42be2ee5fc20988562efffbcb70080aedf87c",
|
|
27
|
-
"skills/nggaigc/references/catalog-and-updates.md": "
|
|
28
|
-
"skills/nggaigc/references/source.json": "
|
|
27
|
+
"skills/nggaigc/references/catalog-and-updates.md": "a43bee94a480aa2bf0b1e7038cee6f27fb86d2bd8fa88a28a63678963d7c1530",
|
|
28
|
+
"skills/nggaigc/references/source.json": "7a1409d6cad2a629191a0f57ff0dc5a0ff956cf9d6e045174f6d33bdd7f576c4",
|
|
29
29
|
"skills/nggaigc/scripts/api_client.mjs": "e16bf750a297ef7e88e4843d2fba9c33b412a66516bfe76822d7deec6c153069",
|
|
30
30
|
"skills/nggaigc/scripts/api_package.mjs": "6beee22aed770cbf501abe6d1d9d252f7a53893eeb9b6399bd26c4ef68470d5a",
|
|
31
|
-
"skills/nggaigc/scripts/bootstrap-public.json": "
|
|
32
|
-
"skills/nggaigc/scripts/launch-ngg-client.cjs": "
|
|
31
|
+
"skills/nggaigc/scripts/bootstrap-public.json": "1f713cba932651902d4e14073bc8da5e2eb3d219ae50ee6ae3d00e1469435e2a",
|
|
32
|
+
"skills/nggaigc/scripts/launch-ngg-client.cjs": "898d29a42ebddee6ab6e17765f3f56e2e4d588d23d3878592dfe20ea82a99b17",
|
|
33
33
|
"skills/nggaigc/scripts/macos-keychain": "b0bdf29d14219d38ca18c7e5c599deb0daa8c8ac70b0babbc7d4fb23673079ec",
|
|
34
34
|
"skills/nggaigc/scripts/macos-keychain.swift": "1b57e74fde66c824fe970547dd8ca0883a3334c34c065e85a8a2a90d4556a7f5",
|
|
35
|
-
"skills/nggaigc/scripts/ngg_client.mjs": "
|
|
36
|
-
"skills/nggaigc/scripts/ngg-session.mjs": "
|
|
35
|
+
"skills/nggaigc/scripts/ngg_client.mjs": "5534b95177394a6a12d2f205f3ab5884d39412b4b13622c372d66b945d07b715",
|
|
36
|
+
"skills/nggaigc/scripts/ngg-session.mjs": "678be2fd81166a884f0b4a3515042e350658d46779ee16bf9d976dacd32ad9a9",
|
|
37
37
|
"skills/nggaigc/scripts/supported-platforms.json": "ec8b0754c489e04534a1d9880dd6664ba9c5bcd07789e06d138e0923f23575ff",
|
|
38
38
|
"skills/nggaigc/scripts/windows-credential.ps1": "80d470fb0c9473d26bd599cafa9f1c2ad69056d4a835888ddcbb5c1548f9d059",
|
|
39
|
-
"skills/nggaigc/SKILL.md": "
|
|
39
|
+
"skills/nggaigc/SKILL.md": "8cb3eb8a03cf144ce15fa01d7d342495c2b11ba0f6a0cf61a493e1e43c83a11f"
|
|
40
40
|
},
|
|
41
41
|
"signature": {
|
|
42
42
|
"algorithm": "ed25519",
|
|
43
43
|
"keyId": "ngg-signing-skill-release-1",
|
|
44
44
|
"scope": "artifact-bytes",
|
|
45
|
-
"value": "
|
|
45
|
+
"value": "ZUj0GmKZYNe+4wgBznW3BKBBNoSErTVlIB8MgqQvEe27Pnc2MsKepzkMVGGhd6GpGsqaukdD3gENuOhiclpsDg=="
|
|
46
46
|
}
|
|
47
47
|
}
|
|
index b07c405..4e2828f 100644
|
|
|
Binary file
|