@nggaigc/cli 0.1.15 → 0.1.17

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 CHANGED
@@ -8,6 +8,6 @@ npx --yes @nggaigc/cli@latest install
8
8
 
9
9
  安装器会先验证内置 Plugin 的 Ed25519 签名、归档哈希和逐文件哈希,再原子安装 Skill。首次运行会打开 NGGAIGC 浏览器授权页;浏览器仅接收短期连接挑战,安装器通过内存中的独立轮询凭据获取连接结果,设备凭据只通过标准输入进入操作系统受保护的凭据存储(Windows Credential Manager 或 macOS Keychain)。安装器不接受 API Key、授权码或设备凭据参数,也不从环境变量读取这些值。
10
10
 
11
- 截至本地核对,npm 已发布 CLI 0.1.14;本源码的 CLI 0.1.15 / Plugin 1.1.17 只是待整合验收与正式签名的候选,不是当前 `@latest`。候选保留 Windows x64/arm64 与 Apple 芯片 Mac arm64 声明,使用本机 Node.js 22.x(22.13 起)或 24.x,不下载或内嵌 Node.js。Windows PowerShell 5.1 默认 `Restricted` 时,安装器仅为受信凭据辅助脚本的子进程指定 `RemoteSigned`;不修改系统或用户执行策略。安装成功但连接失败会明确分开报告,无需重装;由于系统 URL 处理器退出码不能证明浏览器窗口已显示,安装器会同时给出短期一次性手动授权链接。
11
+ 本源码的 CLI 0.1.17 / Plugin 1.1.18 是待整合验收与正式签名的候选,不代表当前 `@latest`。候选保留 Windows x64/arm64 与 Apple 芯片 Mac arm64 声明,使用本机 Node.js 22.x(22.13 起)或 24.x,不下载或内嵌 Node.js。Windows PowerShell 5.1 默认 `Restricted` 时,安装器仅为受信凭据辅助脚本的子进程指定 `RemoteSigned`;不修改系统或用户执行策略。安装成功但连接失败会明确分开报告,无需重装;由于系统 URL 处理器退出码不能证明浏览器窗口已显示,安装器会同时给出短期一次性手动授权链接。
12
12
 
13
13
  macOS arm64 辅助程序沿用已编译并通过完整性校验的产物;本次 Windows 修复未进行 Mac 实机回归。Intel Mac 不在支持范围内。签名和 registry 读回前,不要将本候选标为已发布。
package/dist/bin.js CHANGED
File without changes
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.17" ||
50
+ manifestValue.version !== "1.1.18" ||
51
51
  manifestValue.artifactPath !==
52
52
  `packages/plugins/nggaigc-plugin-${manifestValue.version}.zip` ||
53
53
  typeof manifestValue.sourceCommit !== "string" ||
@@ -381,6 +381,16 @@ async function existingReceipt(target, entry, trust) {
381
381
  const facts = await lstat(target);
382
382
  if (!facts.isDirectory() || facts.isSymbolicLink())
383
383
  fail("INSTALL_CONFLICT");
384
+ for (const [name, maximum] of [
385
+ [".nggaigc-package.json", 65536],
386
+ [".nggaigc-package.bin", MAX_PACKAGE_BYTES],
387
+ ]) {
388
+ const metadata = await lstat(path.join(target, name));
389
+ if (!metadata.isFile() ||
390
+ metadata.isSymbolicLink() ||
391
+ metadata.size > maximum)
392
+ return false;
393
+ }
384
394
  const value = JSON.parse(await readFile(path.join(target, ".nggaigc-package.json"), "utf8"));
385
395
  if (!record(value) ||
386
396
  typeof value.id !== "string" ||
@@ -485,6 +495,184 @@ async function download(entry, releaseId, origin, fetcher) {
485
495
  fail("PACKAGE_DOWNLOAD_FAILED");
486
496
  return bytes;
487
497
  }
498
+ /** Historical authenticity cannot grant start/rollback eligibility. The active
499
+ * catalog and online admission remain the only source of new-start authority. */
500
+ async function replacementEntry(directory, id, options) {
501
+ let receipt;
502
+ try {
503
+ const facts = await lstat(directory);
504
+ if (!facts.isDirectory() || facts.isSymbolicLink())
505
+ fail("INSTALL_CONFLICT");
506
+ const receiptFacts = await lstat(path.join(directory, ".nggaigc-package.json"));
507
+ if (!receiptFacts.isFile() ||
508
+ receiptFacts.isSymbolicLink() ||
509
+ receiptFacts.size > 65536)
510
+ fail("INSTALL_CONFLICT");
511
+ const value = JSON.parse(await readFile(path.join(directory, ".nggaigc-package.json"), "utf8"));
512
+ if (!record(value) ||
513
+ value.id !== id ||
514
+ typeof value.version !== "string" ||
515
+ !VERSION.test(value.version) ||
516
+ typeof value.manifestSha256 !== "string" ||
517
+ !DIGEST.test(value.manifestSha256))
518
+ fail("INSTALL_CONFLICT");
519
+ receipt = value;
520
+ }
521
+ catch {
522
+ fail("INSTALL_CONFLICT");
523
+ }
524
+ const current = options.index.entries.filter((entry) => entry.id === id && entry.version === receipt.version);
525
+ if (current.length) {
526
+ if (current.length === 1 && current[0].state === "disabled")
527
+ fail("HISTORICAL_VERSION_BLOCKED");
528
+ if (current.length !== 1)
529
+ fail("INSTALL_CONFLICT");
530
+ if (!(await existingReceipt(directory, current[0], options.trust)))
531
+ fail("INSTALL_CONFLICT");
532
+ return current[0];
533
+ }
534
+ const origin = options.origin ?? "https://api.nggaigc.com/";
535
+ if (origin !== "https://api.nggaigc.com/" &&
536
+ origin !== "https://api.nggaigc.com")
537
+ fail("PACKAGE_SOURCE_REJECTED");
538
+ const url = new URL(`/v1/skill-packages/${encodeURIComponent(id)}/${encodeURIComponent(receipt.version)}/verification`, origin);
539
+ url.searchParams.set("manifestSha256", receipt.manifestSha256);
540
+ let value;
541
+ try {
542
+ const response = await (options.fetcher ?? fetch)(url, {
543
+ method: "GET",
544
+ redirect: "error",
545
+ credentials: "omit",
546
+ cache: "no-store",
547
+ signal: AbortSignal.timeout(15000),
548
+ });
549
+ if (response.status === 410 &&
550
+ !response.redirected &&
551
+ response.url === url.href)
552
+ fail("HISTORICAL_VERSION_BLOCKED");
553
+ if (!response.ok ||
554
+ response.redirected ||
555
+ response.url !== url.href ||
556
+ Number(response.headers.get("content-length") ?? 0) > 16384)
557
+ fail("HISTORICAL_VERIFICATION_UNAVAILABLE");
558
+ const reader = response.body?.getReader();
559
+ if (!reader)
560
+ fail("HISTORICAL_VERIFICATION_UNAVAILABLE");
561
+ const chunks = [];
562
+ let size = 0;
563
+ try {
564
+ while (true) {
565
+ const chunk = await reader.read();
566
+ if (chunk.done)
567
+ break;
568
+ size += chunk.value.length;
569
+ if (size > 16384)
570
+ fail("HISTORICAL_VERIFICATION_UNAVAILABLE");
571
+ chunks.push(chunk.value);
572
+ }
573
+ }
574
+ finally {
575
+ await reader.cancel();
576
+ }
577
+ value = JSON.parse(Buffer.concat(chunks).toString("utf8"));
578
+ }
579
+ catch (error) {
580
+ if (error instanceof IndependentSkillError)
581
+ throw error;
582
+ fail("HISTORICAL_VERIFICATION_UNAVAILABLE");
583
+ }
584
+ if (!record(value) ||
585
+ value.schemaVersion !== "nggaigc-skill-verification/v1" ||
586
+ value.scope !== "replacement-verification" ||
587
+ value.status !== "verified-published" ||
588
+ value.id !== id ||
589
+ value.version !== receipt.version ||
590
+ value.manifestSha256 !== receipt.manifestSha256 ||
591
+ !record(value.package))
592
+ fail("HISTORICAL_VERIFICATION_UNAVAILABLE");
593
+ const pkg = value.package;
594
+ if (typeof pkg.sha256 !== "string" ||
595
+ !DIGEST.test(pkg.sha256) ||
596
+ !Number.isSafeInteger(pkg.sizeBytes) ||
597
+ pkg.sizeBytes < 1 ||
598
+ pkg.sizeBytes > MAX_PACKAGE_BYTES ||
599
+ !record(pkg.signature) ||
600
+ pkg.signature.algorithm !== "ed25519" ||
601
+ typeof pkg.signature.keyId !== "string" ||
602
+ typeof pkg.signature.value !== "string" ||
603
+ !record(pkg.compatibility) ||
604
+ !record(pkg.compatibility.rootSkill) ||
605
+ !record(pkg.compatibility.platform))
606
+ fail("HISTORICAL_VERIFICATION_UNAVAILABLE");
607
+ const entry = {
608
+ id,
609
+ version: value.version,
610
+ manifestSha256: value.manifestSha256,
611
+ state: "superseded",
612
+ manifest: {
613
+ id,
614
+ version: value.version,
615
+ lifecycle: { status: "published" },
616
+ requires: [],
617
+ package: pkg,
618
+ },
619
+ };
620
+ // Never trust a locally editable receipt as file ownership evidence: the cached
621
+ // ZIP must verify against the pinned signing key, and EVERY installed file.
622
+ if (!(await existingReceipt(directory, entry, options.trust)))
623
+ fail("INSTALL_CONFLICT");
624
+ return entry;
625
+ }
626
+ async function acquireInstallLock(lock) {
627
+ for (let attempt = 0; attempt < 2; attempt++) {
628
+ try {
629
+ const handle = await open(lock, "wx", 0o600);
630
+ await handle.writeFile(JSON.stringify({ schemaVersion: 1, pid: process.pid }));
631
+ await handle.sync();
632
+ return handle;
633
+ }
634
+ catch {
635
+ // Only our positively identified, dead-owner locks may be recovered. Legacy
636
+ // empty locks, malformed state and permission errors remain fail-closed.
637
+ if (attempt)
638
+ fail("INSTALL_BUSY");
639
+ let reclaim;
640
+ try {
641
+ // Serialize reclaimers so one cannot unlink a newly acquired live lock
642
+ // after another has recovered the dead owner.
643
+ reclaim = await open(`${lock}.reclaim`, "wx", 0o600);
644
+ const facts = await lstat(lock);
645
+ if (!facts.isFile() || facts.isSymbolicLink() || facts.size > 1024)
646
+ fail("INSTALL_BUSY");
647
+ const state = JSON.parse(await readFile(lock, "utf8"));
648
+ if (!record(state) ||
649
+ state.schemaVersion !== 1 ||
650
+ !Number.isSafeInteger(state.pid) ||
651
+ state.pid <= 0)
652
+ fail("INSTALL_BUSY");
653
+ try {
654
+ process.kill(state.pid, 0);
655
+ fail("INSTALL_BUSY");
656
+ }
657
+ catch (error) {
658
+ if (!record(error) || error.code !== "ESRCH")
659
+ fail("INSTALL_BUSY");
660
+ }
661
+ await rm(lock);
662
+ }
663
+ catch {
664
+ fail("INSTALL_BUSY");
665
+ }
666
+ finally {
667
+ if (reclaim) {
668
+ await reclaim.close();
669
+ await rm(`${lock}.reclaim`);
670
+ }
671
+ }
672
+ }
673
+ }
674
+ return fail("INSTALL_BUSY");
675
+ }
488
676
  export async function prepareIndependentSkill(options) {
489
677
  const ordered = resolve(options.index, options.skillId, options.skillVersion, options.rootSkillVersion, options.platformVersion);
490
678
  if (!path.isAbsolute(options.codexHome))
@@ -505,33 +693,17 @@ export async function prepareIndependentSkill(options) {
505
693
  fail("INSTALL_CONFLICT");
506
694
  const target = path.join(skillsRoot, slug);
507
695
  const lock = path.join(stateRoot, `.nggaigc-${slug}.lock`);
508
- let handle;
509
- try {
510
- handle = await open(lock, "wx", 0o600);
511
- }
512
- catch {
513
- fail("INSTALL_BUSY");
514
- }
696
+ const handle = await acquireInstallLock(lock);
515
697
  try {
516
698
  const backup = path.join(stateRoot, `.nggaigc-backup-${slug}`);
517
699
  if ((await lstat(backup).then(() => true, () => false)) &&
518
700
  !(await lstat(target).then(() => true, () => false))) {
519
- let version;
520
701
  try {
521
- const receipt = JSON.parse(await readFile(path.join(backup, ".nggaigc-package.json"), "utf8"));
522
- if (!record(receipt) || typeof receipt.version !== "string")
523
- fail("ROLLBACK_PENDING");
524
- version = receipt.version;
702
+ await replacementEntry(backup, entry.id, options);
525
703
  }
526
704
  catch {
527
705
  fail("ROLLBACK_PENDING");
528
706
  }
529
- const previous = options.index.entries.find((candidate) => candidate.id === entry.id &&
530
- candidate.version === version &&
531
- candidate.state === "active");
532
- if (!previous ||
533
- !(await existingReceipt(backup, previous, options.trust)))
534
- fail("ROLLBACK_PENDING");
535
707
  await rename(backup, target);
536
708
  }
537
709
  if (await existingReceipt(target, entry, options.trust)) {
@@ -560,26 +732,13 @@ export async function prepareIndependentSkill(options) {
560
732
  });
561
733
  const targetExists = await lstat(target).then(() => true, () => false);
562
734
  if (targetExists) {
563
- let oldReceipt;
564
- try {
565
- const value = JSON.parse(await readFile(path.join(target, ".nggaigc-package.json"), "utf8"));
566
- if (!record(value) ||
567
- typeof value.id !== "string" ||
568
- typeof value.version !== "string")
569
- fail("INSTALL_CONFLICT");
570
- oldReceipt = { id: value.id, version: value.version };
571
- }
572
- catch {
573
- fail("INSTALL_CONFLICT");
735
+ await replacementEntry(target, entry.id, options);
736
+ if (await lstat(backup).then(() => true, () => false)) {
737
+ // Retain exactly the immediately previous verified version. Do not
738
+ // delete a tampered/unowned backup merely to make an update succeed.
739
+ await replacementEntry(backup, entry.id, options);
740
+ await rm(backup, { recursive: true });
574
741
  }
575
- const oldEntry = options.index.entries.find((candidate) => candidate.id === oldReceipt.id &&
576
- candidate.version === oldReceipt.version);
577
- if (oldReceipt.id !== entry.id ||
578
- !oldEntry ||
579
- !(await existingReceipt(target, oldEntry, options.trust)))
580
- fail("INSTALL_CONFLICT");
581
- if (await lstat(backup).then(() => true, () => false))
582
- fail("ROLLBACK_PENDING");
583
742
  await rename(target, backup);
584
743
  }
585
744
  try {
@@ -591,6 +750,20 @@ export async function prepareIndependentSkill(options) {
591
750
  await rename(backup, target);
592
751
  fail("INSTALL_FAILED");
593
752
  }
753
+ let activatedValid = false;
754
+ try {
755
+ await options.afterActivate?.(target);
756
+ activatedValid = await existingReceipt(target, entry, options.trust);
757
+ }
758
+ catch {
759
+ activatedValid = false;
760
+ }
761
+ if (!activatedValid) {
762
+ await rm(target, { recursive: true, force: true });
763
+ if (targetExists)
764
+ await rename(backup, target);
765
+ fail("INSTALL_FAILED");
766
+ }
594
767
  result = {
595
768
  id: entry.id,
596
769
  version: entry.version,
@@ -655,13 +828,7 @@ export async function rollbackIndependentSkill(options) {
655
828
  const target = path.join(skillsRoot, slug);
656
829
  const backup = path.join(stateRoot, `.nggaigc-backup-${slug}`);
657
830
  const lock = path.join(stateRoot, `.nggaigc-${slug}.lock`);
658
- let handle;
659
- try {
660
- handle = await open(lock, "wx", 0o600);
661
- }
662
- catch {
663
- fail("INSTALL_BUSY");
664
- }
831
+ const handle = await acquireInstallLock(lock);
665
832
  const retired = path.join(stateRoot, `.nggaigc-retired-${slug}-${randomUUID()}`);
666
833
  try {
667
834
  if (!(await existingReceipt(target, current, options.trust)) ||
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.17.zip"),
11
+ archive: path.join(vendor, "nggaigc-plugin-1.1.18.zip"),
12
12
  manifest: path.join(vendor, "manifest.json"),
13
13
  trust: path.join(vendor, "trusted-keys.json"),
14
14
  };
@@ -15,7 +15,7 @@ function record(value) {
15
15
  async function productionDependencies(codexHome) {
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.17.zip"),
18
+ archive: path.join(vendor, "nggaigc-plugin-1.1.18.zip"),
19
19
  manifest: path.join(vendor, "manifest.json"),
20
20
  trust: path.join(vendor, "trusted-keys.json"),
21
21
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nggaigc/cli",
3
- "version": "0.1.15",
3
+ "version": "0.1.17",
4
4
  "description": "Secure one-command NGGAIGC Skill installer for Codex.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -22,12 +22,11 @@
22
22
  "x64",
23
23
  "arm64"
24
24
  ],
25
+ "license": "UNLICENSED",
25
26
  "scripts": {
26
27
  "build": "tsc -p tsconfig.build.json",
27
- "prepack": "tsc -p tsconfig.build.json && node scripts/stage-assets.mjs",
28
28
  "test": "vitest run src --exclude 'src/windows-secure-store.integration.test.ts'",
29
29
  "test:credential:os": "tsc -p tsconfig.build.json && vitest run src/windows-secure-store.integration.test.ts",
30
30
  "typecheck": "tsc -p tsconfig.json --noEmit"
31
- },
32
- "license": "UNLICENSED"
33
- }
31
+ }
32
+ }
@@ -1,40 +1,41 @@
1
1
  {
2
2
  "schemaVersion": "nggaigc-plugin-package/v1",
3
3
  "artifactId": "plugin.nggaigc",
4
- "version": "1.1.17",
5
- "sourceCommit": "c7f5c09ee376c47e2c3263e04588821ca7be149e",
6
- "artifactPath": "packages/plugins/nggaigc-plugin-1.1.17.zip",
7
- "sha256": "c75143fa55bf7ea42cbe87a39f9d89de4d6051db66061ec18eef969a069e7ea6",
8
- "sizeBytes": 367844,
9
- "fileCount": 21,
4
+ "version": "1.1.18",
5
+ "sourceCommit": "44a6a19b363015ab1774c568ffdd509689c3444b",
6
+ "artifactPath": "packages/plugins/nggaigc-plugin-1.1.18.zip",
7
+ "sha256": "9d8da5a4100c05e5a7daa9071fbe0bcca36a414d7f34f60093a21a4f90316db4",
8
+ "sizeBytes": 395352,
9
+ "fileCount": 22,
10
10
  "platforms": ["win32-x64", "win32-arm64", "darwin-arm64"],
11
11
  "files": {
12
- ".codex-plugin/plugin.json": "5f425e4a4d07c5b8678a95376b0d6b57e5181d22590baa398774f228efd4143f",
13
- "installer/install.cjs": "779733bd3994f072c1ac322a7b493e93104e1e7c07b4d268b80da7d4294bc934",
12
+ ".codex-plugin/plugin.json": "b450ba745df8d2d041e8b63cc56261b028078eb6c0b1a943c209b20d26af32d4",
13
+ "installer/install.cjs": "85b3ebd5a82968384e2868956e62088be27014681bf373ca601a70d007e66e7c",
14
14
  "installer/legacy-root-digests.json": "922552646a5aa6cff8616c372912a37b1d5f263351206b85785ed9b2eae31641",
15
15
  "installer/signed-pair-1.1.16.json": "ccb22a90302cc5c9c585067ebc211a27b0c9d8a177c2740a5678a58a3d70bfe9",
16
- "migration/seedream-1.1.2/agents/openai.yaml": "3cbf034ddccd64a7972acd37e7433683a3944f3d8c7b5bdccbbd70e517bf5a8c",
17
- "migration/seedream-1.1.2/references/image-generation.md": "5cb3094c7a313dea152787be50979e0b145e46d5e8bf3629dd1fa47c7ab9c424",
18
- "migration/seedream-1.1.2/references/source.json": "3b0d89d9b5b7b786e9b60633a639e7f77844a9aec8d723fd380ff22c74dfa3b9",
19
- "migration/seedream-1.1.2/scripts/seedream.mjs": "76854d6880696be7836525fd2c2b0f9c296d67dd5d56b3cc11d1f5c4b2f123bc",
20
- "migration/seedream-1.1.2/SKILL.md": "38ce21f895e32223d0dac55fb2eafb9627ffb32132ac2d45c66cef24d37e0d75",
16
+ "installer/signed-pair-1.1.17.json": "a3697506c929aaa085a6d994fc3a1b9a87e522ec6e1e32f3f760e6a534effa2b",
17
+ "migration/seedream-1.1.3/agents/openai.yaml": "3cbf034ddccd64a7972acd37e7433683a3944f3d8c7b5bdccbbd70e517bf5a8c",
18
+ "migration/seedream-1.1.3/references/image-generation.md": "91e70d577c9990cc1315b3ef41144dbb40ca420b7ae36376def23f0b0c1fd7e4",
19
+ "migration/seedream-1.1.3/references/source.json": "75998d079a229435d1097b00bd008703bd38026fc6485c312254925bf55398a8",
20
+ "migration/seedream-1.1.3/scripts/seedream.mjs": "f235aa1222d88a4c888417dca02f4830ab90fa241d1511aaf6565087bc0347f7",
21
+ "migration/seedream-1.1.3/SKILL.md": "e71b612fc05ab2a0f8a45a745b01a83a5565163f2c671c91b3403b2d8e0b37f4",
21
22
  "skills/nggaigc/agents/openai.yaml": "8936d97b9821e687e224e9349cc42be2ee5fc20988562efffbcb70080aedf87c",
22
- "skills/nggaigc/references/catalog-and-updates.md": "0c85490d57ee8eac28255decb320c2880a5ab24f08a33baefe4faccca03fb4c6",
23
- "skills/nggaigc/references/source.json": "c78895bf0ae5effeed138342e4853b932ec66d4903a1a2a965d81d7d013f734b",
24
- "skills/nggaigc/scripts/bootstrap-public.json": "b562cdb786cd50724bc81a93daf9cfcbb39f6eefe30ec8e909e3439e704efabf",
25
- "skills/nggaigc/scripts/launch-ngg-client.cjs": "59fbd6d43907752ba3c1242ccc09b74383132d7f7035c27f96a1c4f9b8609eec",
23
+ "skills/nggaigc/references/catalog-and-updates.md": "d4ef563e4c0b23d917275da1fb91e5f7f7e652cf2b072a230087bb3702bdef9a",
24
+ "skills/nggaigc/references/source.json": "932b9d5ebf25af8ff195f94a5fb2149655b2d6dbabf8303f70c946044311a9dd",
25
+ "skills/nggaigc/scripts/bootstrap-public.json": "d616d9e0ff7e27717ff40b75727786a9a1ea35a9e8c34073ea4b142515dea1cf",
26
+ "skills/nggaigc/scripts/launch-ngg-client.cjs": "f948a4fa2a5d1867f8e58a08bdf53cf03611e0ea60d2d39c8aee8be09de2210e",
26
27
  "skills/nggaigc/scripts/macos-keychain": "b0bdf29d14219d38ca18c7e5c599deb0daa8c8ac70b0babbc7d4fb23673079ec",
27
28
  "skills/nggaigc/scripts/macos-keychain.swift": "1b57e74fde66c824fe970547dd8ca0883a3334c34c065e85a8a2a90d4556a7f5",
28
- "skills/nggaigc/scripts/ngg_client.mjs": "b35cf3a01c667b252ff680a5452bb918ed3a0ab4e26345120794819dd896780c",
29
- "skills/nggaigc/scripts/ngg-session.mjs": "6d213a204fe0db7777ed69a7f46d1fbd3e99e11baa8011db7f4f3f53d6dbd42d",
29
+ "skills/nggaigc/scripts/ngg_client.mjs": "703a6f7dfe7f1bc70716da7c880887ccece4733c14704f27a5856630dddc0bc6",
30
+ "skills/nggaigc/scripts/ngg-session.mjs": "e4d8b4eec48fc55a2533fbd9ba933bc5f56b5fe0226b7bbaf00cbb6223b34853",
30
31
  "skills/nggaigc/scripts/supported-platforms.json": "ec8b0754c489e04534a1d9880dd6664ba9c5bcd07789e06d138e0923f23575ff",
31
32
  "skills/nggaigc/scripts/windows-credential.ps1": "ce097f2a8601664522fcfa8c9505243439ff786a45f15a1dba702b8f9b13dab1",
32
- "skills/nggaigc/SKILL.md": "cb05429a10dbe79ccc0800b0c190c42f855ce428f541bdf94f2fc9f61bde244a"
33
+ "skills/nggaigc/SKILL.md": "4dc24674e0aa4058beb7c4940ef2fe6c60b28eae05a6e38d0d74190d47c048e5"
33
34
  },
34
35
  "signature": {
35
36
  "algorithm": "ed25519",
36
37
  "keyId": "ngg-signing-skill-release-1",
37
38
  "scope": "artifact-bytes",
38
- "value": "4ERtPG1JcJNav97OBfdrAp4iZLxLCAbjOuzG/QPlBU62sC6Q1nGdiBsnsVOqoUCe2aeGn9uMf33ToltsU6/9DQ=="
39
+ "value": "ZAYCQgoT4dYK1GYyWd9STOlImKO7sMdOjpfREUvsocBBnZOCZGYlsr+9FLIM/ZwdasMtMsWmZZFR91hDxQZLBw=="
39
40
  }
40
41
  }
index d34f0d1..6bb8ad5 100644
Binary file