@nggaigc/cli 0.1.10 → 0.1.12

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.14.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) {
@@ -162,12 +171,14 @@ export async function runInstall(options = {}) {
162
171
  const report = options.reporter ?? (() => undefined);
163
172
  report("verifying");
164
173
  const bundle = await verifyBundle(options.bundle ?? defaultBundle());
174
+ if (!bundle.platforms.includes(`${options.platform ?? process.platform}-${options.architecture ?? process.arch}`))
175
+ throw new CliError("UNSUPPORTED_PLATFORM");
165
176
  const temporaryParent = path.resolve(options.temporaryRoot ?? os.tmpdir());
166
177
  const temporary = await mkdtemp(path.join(temporaryParent, "nggaigc-cli-"));
167
178
  assertDisposableRoot(temporary, temporaryParent);
168
179
  try {
169
180
  const extracted = path.join(temporary, "plugin");
170
- await extractBundle(bundle.archive, extracted);
181
+ await extractBundle(bundle.archive, extracted, bundle.sha256);
171
182
  await verifyExtractedBundle(extracted, bundle.files);
172
183
  report("installing");
173
184
  const require = createRequire(import.meta.url);
@@ -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.14.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.12",
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,39 @@
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,
10
- "platforms": [
11
- "win32-x64",
12
- "win32-arm64"
13
- ],
4
+ "version": "1.1.14",
5
+ "sourceCommit": "d7e68a4311bfc9c34cff1419197906417b50c6ec",
6
+ "artifactPath": "packages/plugins/nggaigc-plugin-1.1.14.zip",
7
+ "sha256": "3610b002a56703534a4975c506f2e90a9d589a671ce42a4557d4282d1d6852aa",
8
+ "sizeBytes": 337385,
9
+ "fileCount": 20,
10
+ "platforms": ["win32-x64", "win32-arm64", "darwin-arm64"],
14
11
  "files": {
15
- ".codex-plugin/plugin.json": "b9e38baab4fb64421058eb4ef50680ff59679bfe56488a0b13b49785430f7a0b",
16
- "installer/install.cjs": "34f4196d59a911f983311b0a79192b23112cdeeb5455cb57609f121bb3e55ea8",
12
+ ".codex-plugin/plugin.json": "35d8cde373c830a9dd8ebf4616d8c8b32f62034c8ae9a4c0df710c5e094041bc",
13
+ "installer/install.cjs": "69e4c8a6b54c0393c4b3186a14ca29ccc2915997ac05b379549128ffa9e3fc93",
14
+ "installer/legacy-root-digests.json": "922552646a5aa6cff8616c372912a37b1d5f263351206b85785ed9b2eae31641",
15
+ "migration/seedream-1.1.1/SKILL.md": "c45ee501af0b28ca9e66c81a75827ca83dfa6c7420cfd142952512a1fccc2c37",
16
+ "migration/seedream-1.1.1/agents/openai.yaml": "3cbf034ddccd64a7972acd37e7433683a3944f3d8c7b5bdccbbd70e517bf5a8c",
17
+ "migration/seedream-1.1.1/references/image-generation.md": "b27a8ac38099d3aea4ad00351887437e3d79c537e318a463108fb017d05b838e",
18
+ "migration/seedream-1.1.1/references/source.json": "fb89c461b7ef587ebd8e9ceaa7b3128d0766f2004ee437c261c0d5ec25a31ce8",
19
+ "migration/seedream-1.1.1/scripts/seedream.mjs": "195e0e8eaca0b62c7e89262a05bfc27fa8caa9d59d5ea6418ec3a72239ee2ad5",
20
+ "skills/nggaigc/SKILL.md": "935970e818e5a60839c5f68738889f22eaae4fc85a0c4bf9a0a89f0571d17403",
17
21
  "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"
22
+ "skills/nggaigc/references/catalog-and-updates.md": "638357c1d7a5170dc4a0ce635a08e148ef440f69ce51251bc2a053b0871589a9",
23
+ "skills/nggaigc/references/source.json": "7c69604cd85211e2d4ba15a79b81ab81e08caf5808f94b20af972e3e475377fc",
24
+ "skills/nggaigc/scripts/bootstrap-public.json": "78670a0a52ee878cc66107c282fcdda35e6d3ad372a8aacaf5986fd773bf3d43",
25
+ "skills/nggaigc/scripts/launch-ngg-client.cjs": "c2f76f3fc10796904158a4b56d6d0a43581b3e4b7583837a8aed44f0c727eb84",
26
+ "skills/nggaigc/scripts/macos-keychain": "b0bdf29d14219d38ca18c7e5c599deb0daa8c8ac70b0babbc7d4fb23673079ec",
27
+ "skills/nggaigc/scripts/macos-keychain.swift": "1b57e74fde66c824fe970547dd8ca0883a3334c34c065e85a8a2a90d4556a7f5",
28
+ "skills/nggaigc/scripts/ngg-session.mjs": "8904c71d66cef8140bb758bbfa0d3cea429ffa3a20fef1c871bcaa530243b698",
29
+ "skills/nggaigc/scripts/ngg_client.mjs": "588722bcc25a127a53d8f84e37f59c97f03963f67e55fa64773e6fd8eec4aa57",
30
+ "skills/nggaigc/scripts/supported-platforms.json": "ec8b0754c489e04534a1d9880dd6664ba9c5bcd07789e06d138e0923f23575ff",
31
+ "skills/nggaigc/scripts/windows-credential.ps1": "ce097f2a8601664522fcfa8c9505243439ff786a45f15a1dba702b8f9b13dab1"
26
32
  },
27
33
  "signature": {
28
34
  "algorithm": "ed25519",
29
35
  "keyId": "ngg-signing-skill-release-1",
30
36
  "scope": "artifact-bytes",
31
- "value": "LUKadwdAcUeqqRqp5aE3kH1GiIObpIqhkEXFpNXdrYi9cNYoVDyIF5pItmDHd9tnDq1KS38jluQf/m6StwnlCA=="
37
+ "value": "RUaaTuzklZJdr2Mj7OAkWZ703UVkj77q7+GPjVBugivClX/86fMLf2ugqEEEjpxLxTPItqS7J1piN53VFyf0DA=="
32
38
  }
33
39
  }
Binary file
Binary file