@nggaigc/cli 0.1.10 → 0.1.13

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/dist/install.js CHANGED
@@ -8,7 +8,7 @@ import { CliError, fixedErrorCode } from "./errors.js";
8
8
  function defaultBundle() {
9
9
  const vendor = fileURLToPath(new URL("../vendor/", import.meta.url));
10
10
  return {
11
- archive: path.join(vendor, "nggaigc-plugin-1.1.11.zip"),
11
+ archive: path.join(vendor, "nggaigc-plugin-1.1.15.zip"),
12
12
  manifest: path.join(vendor, "manifest.json"),
13
13
  trust: path.join(vendor, "trusted-keys.json"),
14
14
  };
@@ -17,9 +17,10 @@ function validateRuntime(platform, architecture) {
17
17
  const [major, minor] = process.versions.node.split(".").map(Number);
18
18
  if (!((major === 22 && (minor ?? 0) >= 13) || major === 24))
19
19
  throw new CliError("RUNTIME_UNSUPPORTED");
20
- if (platform !== "win32")
20
+ if (platform !== "win32" && platform !== "darwin")
21
21
  throw new CliError("UNSUPPORTED_PLATFORM");
22
- if (architecture !== "x64" && architecture !== "arm64")
22
+ if ((platform === "darwin" && architecture !== "arm64") ||
23
+ (platform === "win32" && architecture !== "x64" && architecture !== "arm64"))
23
24
  throw new CliError("UNSUPPORTED_PLATFORM");
24
25
  }
25
26
  function safeProfile(value) {
@@ -27,6 +28,14 @@ function safeProfile(value) {
27
28
  throw new CliError("INVALID_INPUT");
28
29
  return path.resolve(value);
29
30
  }
31
+ function installationError(error) {
32
+ const code = fixedErrorCode(error);
33
+ if (["SKILL_PAIR_UPGRADE_REQUIRED", "SKILL_PAIR_UNSAFE"].includes(code ?? ""))
34
+ return new CliError("SKILL_PAIR_UPGRADE_REQUIRED");
35
+ if (["SKILL_PAIR_RECOVERY_REQUIRED", "SKILL_PAIR_SOURCE_INVALID"].includes(code ?? ""))
36
+ return new CliError("SKILL_PAIR_RECOVERY_REQUIRED");
37
+ return new CliError("INSTALLATION_FAILED");
38
+ }
30
39
  async function installedVersion(target) {
31
40
  try {
32
41
  const marker = JSON.parse(await readFile(path.join(target, ".nggaigc-install.json"), "utf8"));
@@ -64,7 +73,7 @@ async function installSkill(installer, source, profile, codexHome, expectedVersi
64
73
  }
65
74
  catch (error) {
66
75
  if (fixedErrorCode(error) !== "ALREADY_INSTALLED")
67
- throw new CliError("INSTALLATION_FAILED");
76
+ throw installationError(error);
68
77
  }
69
78
  const currentVersion = await installedVersion(target);
70
79
  if (!currentVersion)
@@ -83,8 +92,8 @@ async function installSkill(installer, source, profile, codexHome, expectedVersi
83
92
  await verifyInstalledSkill(target, bundleFiles);
84
93
  return "updated";
85
94
  }
86
- catch {
87
- throw new CliError("INSTALLATION_FAILED");
95
+ catch (error) {
96
+ throw installationError(error);
88
97
  }
89
98
  }
90
99
  async function connect(launcher, options, report, probe) {
@@ -106,6 +115,8 @@ async function connect(launcher, options, report, probe) {
106
115
  catch (error) {
107
116
  if (!probe && fixedErrorCode(error) === "SETUP_REQUIRED")
108
117
  configured = false;
118
+ else if (fixedErrorCode(error) === "POWERSHELL_EXECUTION_POLICY_BLOCKED")
119
+ throw new CliError("POWERSHELL_EXECUTION_POLICY_BLOCKED");
109
120
  else
110
121
  throw new CliError("CONNECTION_VERIFICATION_FAILED");
111
122
  }
@@ -118,6 +129,9 @@ async function connect(launcher, options, report, probe) {
118
129
  const upstreamBrowserOpened = typeof options?.browserOpened === "function"
119
130
  ? options.browserOpened
120
131
  : undefined;
132
+ const upstreamBrowserFallback = typeof options?.browserFallback === "function"
133
+ ? options.browserFallback
134
+ : undefined;
121
135
  const upstreamSignal = options?.signal;
122
136
  const result = await launcher.main(["login"], {
123
137
  ...options,
@@ -128,6 +142,12 @@ async function connect(launcher, options, report, probe) {
128
142
  upstreamBrowserOpened?.();
129
143
  report("authorizing");
130
144
  },
145
+ browserFallback: upstreamBrowserFallback
146
+ ? async (url) => {
147
+ await upstreamBrowserFallback(url);
148
+ report("manual-authorizing");
149
+ }
150
+ : undefined,
131
151
  });
132
152
  if (result === null ||
133
153
  typeof result !== "object" ||
@@ -138,6 +158,8 @@ async function connect(launcher, options, report, probe) {
138
158
  catch (error) {
139
159
  if (fixedErrorCode(error) === "BROWSER_OPEN_FAILED")
140
160
  throw new CliError("BROWSER_OPEN_FAILED");
161
+ if (fixedErrorCode(error) === "POWERSHELL_EXECUTION_POLICY_BLOCKED")
162
+ throw new CliError("POWERSHELL_EXECUTION_POLICY_BLOCKED");
141
163
  throw new CliError("BROWSER_AUTHORIZATION_FAILED");
142
164
  }
143
165
  finally {
@@ -162,12 +184,14 @@ export async function runInstall(options = {}) {
162
184
  const report = options.reporter ?? (() => undefined);
163
185
  report("verifying");
164
186
  const bundle = await verifyBundle(options.bundle ?? defaultBundle());
187
+ if (!bundle.platforms.includes(`${options.platform ?? process.platform}-${options.architecture ?? process.arch}`))
188
+ throw new CliError("UNSUPPORTED_PLATFORM");
165
189
  const temporaryParent = path.resolve(options.temporaryRoot ?? os.tmpdir());
166
190
  const temporary = await mkdtemp(path.join(temporaryParent, "nggaigc-cli-"));
167
191
  assertDisposableRoot(temporary, temporaryParent);
168
192
  try {
169
193
  const extracted = path.join(temporary, "plugin");
170
- await extractBundle(bundle.archive, extracted);
194
+ await extractBundle(bundle.archive, extracted, bundle.sha256);
171
195
  await verifyExtractedBundle(extracted, bundle.files);
172
196
  report("installing");
173
197
  const require = createRequire(import.meta.url);
@@ -181,8 +205,20 @@ export async function runInstall(options = {}) {
181
205
  typeof launcher.main !== "function" ||
182
206
  typeof launcher.LauncherError !== "function")
183
207
  throw new CliError("INSTALLATION_FAILED");
184
- await connect(launcher, options.launcherOptionsFactory?.(launcher), report, options.connectionProbe);
185
- return { status: "connected", installation, version: bundle.version };
208
+ try {
209
+ await connect(launcher, options.launcherOptionsFactory?.(launcher), report, options.connectionProbe);
210
+ return { status: "connected", installation, version: bundle.version };
211
+ }
212
+ catch (error) {
213
+ if (!(error instanceof CliError))
214
+ throw error;
215
+ return {
216
+ status: "installed-unconnected",
217
+ installation,
218
+ version: bundle.version,
219
+ connectionError: error.code,
220
+ };
221
+ }
186
222
  }
187
223
  finally {
188
224
  assertDisposableRoot(temporary, temporaryParent);
@@ -0,0 +1,115 @@
1
+ import { createHash, createPublicKey } from "node:crypto";
2
+ import { readFile } from "node:fs/promises";
3
+ import { createRequire } from "node:module";
4
+ import os from "node:os";
5
+ import path from "node:path";
6
+ import { fileURLToPath } from "node:url";
7
+ import { trustedKeyId, trustedKeySpkiSha256, verifyBundle, verifyInstalledSkill, } from "./bundle.js";
8
+ import { IndependentSkillError, projectActiveSkillCatalog, startIndependentSkill, } from "./independent-skill.js";
9
+ function fail(code) {
10
+ throw new IndependentSkillError(code);
11
+ }
12
+ function record(value) {
13
+ return value !== null && typeof value === "object" && !Array.isArray(value);
14
+ }
15
+ async function productionDependencies(codexHome) {
16
+ const vendor = fileURLToPath(new URL("../vendor/", import.meta.url));
17
+ const bundle = await verifyBundle({
18
+ archive: path.join(vendor, "nggaigc-plugin-1.1.15.zip"),
19
+ manifest: path.join(vendor, "manifest.json"),
20
+ trust: path.join(vendor, "trusted-keys.json"),
21
+ });
22
+ const root = path.join(codexHome, "skills", "nggaigc");
23
+ await verifyInstalledSkill(root, bundle.files);
24
+ const source = JSON.parse(await readFile(path.join(root, "references", "source.json"), "utf8"));
25
+ if (!record(source) ||
26
+ source.id !== "skill.nggaigc" ||
27
+ typeof source.version !== "string" ||
28
+ !/^\d+\.\d+\.\d+$/.test(source.version) ||
29
+ source.clientProtocol !== 1)
30
+ fail("ROOT_UNAVAILABLE");
31
+ const keys = JSON.parse(await readFile(path.join(vendor, "trusted-keys.json"), "utf8"));
32
+ if (!record(keys) ||
33
+ keys.schemaVersion !== "ngg-trusted-package-keys/v1" ||
34
+ !Array.isArray(keys.keys))
35
+ fail("TRUST_UNAVAILABLE");
36
+ const match = keys.keys.find((key) => record(key) &&
37
+ key.keyId === trustedKeyId &&
38
+ typeof key.publicKeyPem === "string");
39
+ if (!record(match) || typeof match.publicKeyPem !== "string")
40
+ fail("TRUST_UNAVAILABLE");
41
+ const key = createPublicKey(match.publicKeyPem);
42
+ const fingerprint = createHash("sha256")
43
+ .update(key.export({ type: "spki", format: "der" }))
44
+ .digest("hex");
45
+ if (fingerprint !== trustedKeySpkiSha256)
46
+ fail("TRUST_UNAVAILABLE");
47
+ const require = createRequire(import.meta.url);
48
+ const launcher = require(path.join(root, "scripts", "launch-ngg-client.cjs"));
49
+ if (!record(launcher) || typeof launcher.main !== "function")
50
+ fail("ROOT_UNAVAILABLE");
51
+ return {
52
+ launcher: launcher,
53
+ trust: {
54
+ keyId: trustedKeyId,
55
+ publicKeyPem: match.publicKeyPem,
56
+ spkiSha256: fingerprint,
57
+ },
58
+ rootSkillVersion: source.version,
59
+ };
60
+ }
61
+ /** Candidate npm entry: active catalog → server admission → verified local Skill path. */
62
+ export async function runSkillStartCommand(skillId, skillVersion, options = {}) {
63
+ if (!/^skill\.[a-z0-9][a-z0-9.-]{0,79}$/.test(skillId) ||
64
+ (skillVersion !== undefined && !/^\d+\.\d+\.\d+$/.test(skillVersion)))
65
+ fail("INVALID_INPUT");
66
+ const codexHome = path.resolve(options.codexHome ??
67
+ process.env.CODEX_HOME ??
68
+ path.join(os.homedir(), ".codex"));
69
+ if (!path.isAbsolute(codexHome))
70
+ fail("INSTALL_PATH_UNSAFE");
71
+ const production = options.launcher && options.trust && options.rootSkillVersion
72
+ ? null
73
+ : await productionDependencies(codexHome);
74
+ const launcher = options.launcher ?? production.launcher;
75
+ const trust = options.trust ?? production.trust;
76
+ const rootSkillVersion = options.rootSkillVersion ?? production.rootSkillVersion;
77
+ const platformVersion = options.platformVersion ??
78
+ JSON.parse(await readFile(new URL("../package.json", import.meta.url), "utf8")).version;
79
+ let snapshot;
80
+ try {
81
+ snapshot = await launcher.main(["catalog-snapshot"]);
82
+ }
83
+ catch {
84
+ fail("CATALOG_UNAVAILABLE");
85
+ }
86
+ const index = projectActiveSkillCatalog(snapshot);
87
+ const matches = index.entries.filter((entry) => entry.id === skillId &&
88
+ entry.state === "active" &&
89
+ entry.sourceManifest?.role === "independent_skill" &&
90
+ (skillVersion === undefined || entry.version === skillVersion));
91
+ if (matches.length !== 1)
92
+ fail("SKILL_UNAVAILABLE");
93
+ const selected = matches[0];
94
+ return startIndependentSkill({
95
+ index,
96
+ skillId: selected.id,
97
+ skillVersion: selected.version,
98
+ rootSkillVersion,
99
+ platformVersion,
100
+ codexHome,
101
+ trust,
102
+ fetcher: options.fetcher,
103
+ admit: async (identity) => {
104
+ const answer = await launcher.main([
105
+ "skill-admit",
106
+ identity.kind,
107
+ identity.id,
108
+ identity.version,
109
+ identity.manifestSha256,
110
+ identity.releaseId,
111
+ ]);
112
+ return answer;
113
+ },
114
+ });
115
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@nggaigc/cli",
3
- "version": "0.1.10",
4
- "description": "Secure one-command NGGAIGC Skill installer for Codex on Windows.",
3
+ "version": "0.1.13",
4
+ "description": "Secure one-command NGGAIGC Skill installer for Codex.",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "nggaigc": "dist/bin.js"
@@ -15,18 +15,18 @@
15
15
  "node": ">=22.13.0 <23 || >=24.0.0 <25"
16
16
  },
17
17
  "os": [
18
- "win32"
18
+ "win32",
19
+ "darwin"
19
20
  ],
20
21
  "cpu": [
21
22
  "x64",
22
23
  "arm64"
23
24
  ],
25
+ "license": "UNLICENSED",
24
26
  "scripts": {
25
27
  "build": "tsc -p tsconfig.build.json",
26
- "prepack": "tsc -p tsconfig.build.json && node scripts/stage-assets.mjs",
27
28
  "test": "vitest run src --exclude 'src/windows-secure-store.integration.test.ts'",
28
29
  "test:credential:os": "tsc -p tsconfig.build.json && vitest run src/windows-secure-store.integration.test.ts",
29
30
  "typecheck": "tsc -p tsconfig.json --noEmit"
30
- },
31
- "license": "UNLICENSED"
32
- }
31
+ }
32
+ }
@@ -1,33 +1,43 @@
1
1
  {
2
2
  "schemaVersion": "nggaigc-plugin-package/v1",
3
3
  "artifactId": "plugin.nggaigc",
4
- "version": "1.1.11",
5
- "sourceCommit": "8140d08b8361a46f6b2df6e18fab2343b80e1e8c",
6
- "artifactPath": "packages/plugins/nggaigc-plugin-1.1.11.zip",
7
- "sha256": "0bfd5f96468b3bf380e8620c1f425638f82c025561d957f456585b9b4762aa89",
8
- "sizeBytes": 125253,
9
- "fileCount": 11,
4
+ "version": "1.1.15",
5
+ "sourceCommit": "c62957847daec8e60105d31e083a1309c8dd5846",
6
+ "artifactPath": "packages/plugins/nggaigc-plugin-1.1.15.zip",
7
+ "sha256": "ef47a2e18e55eb21512f094796cacda1915056cd09d88b04c89e2074537d9d22",
8
+ "sizeBytes": 339122,
9
+ "fileCount": 20,
10
10
  "platforms": [
11
11
  "win32-x64",
12
- "win32-arm64"
12
+ "win32-arm64",
13
+ "darwin-arm64"
13
14
  ],
14
15
  "files": {
15
- ".codex-plugin/plugin.json": "b9e38baab4fb64421058eb4ef50680ff59679bfe56488a0b13b49785430f7a0b",
16
- "installer/install.cjs": "34f4196d59a911f983311b0a79192b23112cdeeb5455cb57609f121bb3e55ea8",
16
+ ".codex-plugin/plugin.json": "0e7bbafaf6cab9f7eb5f7836c6579f7544c236e1de678b825922c87b6cb4c781",
17
+ "installer/install.cjs": "73d2c16f2a3697007576835bd9b87ea0ecc4c9b7d9616db1b70c45c1350a4f41",
18
+ "installer/legacy-root-digests.json": "922552646a5aa6cff8616c372912a37b1d5f263351206b85785ed9b2eae31641",
19
+ "migration/seedream-1.1.1/SKILL.md": "a1b49a9440443547c65f3dd4a77efc61feffcc53f1462084a5512c67af83d18c",
20
+ "migration/seedream-1.1.1/agents/openai.yaml": "3cbf034ddccd64a7972acd37e7433683a3944f3d8c7b5bdccbbd70e517bf5a8c",
21
+ "migration/seedream-1.1.1/references/image-generation.md": "a69a9ae3e1e42bdeb5e8a168ec598cc8e1af9caa1d50a76732bd85d47283f2ca",
22
+ "migration/seedream-1.1.1/references/source.json": "fb89c461b7ef587ebd8e9ceaa7b3128d0766f2004ee437c261c0d5ec25a31ce8",
23
+ "migration/seedream-1.1.1/scripts/seedream.mjs": "67334b3de175c47f994448723a946c87fcd56f4ef1882206346b44e301a82054",
24
+ "skills/nggaigc/SKILL.md": "935970e818e5a60839c5f68738889f22eaae4fc85a0c4bf9a0a89f0571d17403",
17
25
  "skills/nggaigc/agents/openai.yaml": "8936d97b9821e687e224e9349cc42be2ee5fc20988562efffbcb70080aedf87c",
18
- "skills/nggaigc/references/catalog-and-updates.md": "415116b71650282322ef37407d12799a5292ea2d60e9e0d2f8a6346c1c86c1d4",
19
- "skills/nggaigc/references/source.json": "bcf6e14101db192ff9079c788df131c6b94ccd6d5abfd667dfc8c838b7d6dc1e",
20
- "skills/nggaigc/scripts/bootstrap-public.json": "743d7e79ff50dce837475841cda075ff33bb4e4fa32ee5771aa68e47e10b546a",
21
- "skills/nggaigc/scripts/launch-ngg-client.cjs": "dc4587a196c0fba4daa00124034b4726ec099eb78d48c926bd2622ed9faa551b",
22
- "skills/nggaigc/scripts/ngg_client.mjs": "b375237938a3c99339d0efaa31a0df7503651a87f5e02d3cef795e15d3d72245",
23
- "skills/nggaigc/scripts/ngg-session.mjs": "6d535b051b71204847865c0f0130d3dd44fc0ad003b1be85f5e37e1040aada37",
24
- "skills/nggaigc/scripts/windows-credential.ps1": "ce097f2a8601664522fcfa8c9505243439ff786a45f15a1dba702b8f9b13dab1",
25
- "skills/nggaigc/SKILL.md": "4dc2709af3022c34772eebadb98f36cde5d141fde59dfa9a0e0559535ae56f54"
26
+ "skills/nggaigc/references/catalog-and-updates.md": "638357c1d7a5170dc4a0ce635a08e148ef440f69ce51251bc2a053b0871589a9",
27
+ "skills/nggaigc/references/source.json": "73d451f17beb6e4dcbee7a03f0d77d3b4c60a0660d4d8d108abe1ddd9dda9884",
28
+ "skills/nggaigc/scripts/bootstrap-public.json": "adff59ac1ee2347b43d49f679f9e5f5073d594cfaea374788c63a747ad7047e3",
29
+ "skills/nggaigc/scripts/launch-ngg-client.cjs": "2afb99bcbc2cbbb90372a3853e69f38d6d21188d35e221c2c685df012edc5434",
30
+ "skills/nggaigc/scripts/macos-keychain": "b0bdf29d14219d38ca18c7e5c599deb0daa8c8ac70b0babbc7d4fb23673079ec",
31
+ "skills/nggaigc/scripts/macos-keychain.swift": "1b57e74fde66c824fe970547dd8ca0883a3334c34c065e85a8a2a90d4556a7f5",
32
+ "skills/nggaigc/scripts/ngg-session.mjs": "b97506546f049f0f5a2fb8f585ab66136485aae88f4bffa0c24ec672837935dc",
33
+ "skills/nggaigc/scripts/ngg_client.mjs": "3775891ddc4ed344358bbd0af8cfc403cee226ca9a12c383c701e84264079b4d",
34
+ "skills/nggaigc/scripts/supported-platforms.json": "ec8b0754c489e04534a1d9880dd6664ba9c5bcd07789e06d138e0923f23575ff",
35
+ "skills/nggaigc/scripts/windows-credential.ps1": "ce097f2a8601664522fcfa8c9505243439ff786a45f15a1dba702b8f9b13dab1"
26
36
  },
27
37
  "signature": {
28
38
  "algorithm": "ed25519",
29
39
  "keyId": "ngg-signing-skill-release-1",
30
40
  "scope": "artifact-bytes",
31
- "value": "LUKadwdAcUeqqRqp5aE3kH1GiIObpIqhkEXFpNXdrYi9cNYoVDyIF5pItmDHd9tnDq1KS38jluQf/m6StwnlCA=="
41
+ "value": "k8qg2D/I4XxwQ4YDroE3sVH7C2IlSusEoxeoEVuUwZmyb3O2Q5+jl6P+s+LWDFD2hi8S8xbAiruLb2G4kivXBA=="
32
42
  }
33
43
  }
Binary file
Binary file