@nggaigc/cli 0.1.48 → 0.1.50
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 +22 -0
- package/dist/bundle.js +1 -1
- package/dist/independent-skill.js +65 -5
- package/dist/install.js +1 -1
- package/dist/skill-command.js +1 -1
- package/package.json +1 -1
- package/vendor/manifest.json +14 -14
- package/vendor/{nggaigc-plugin-1.1.46.zip → nggaigc-plugin-1.1.48.zip} +0 -0
package/README.md
CHANGED
|
@@ -39,3 +39,25 @@ npx --yes @nggaigc/cli@latest client --skills-dir "/absolute/project/.codebuddy/
|
|
|
39
39
|
本地技能包导入可能复制文件,需核导入后的实际路径和独立包同级关系。交互使用宿主可用的提问工具或当前聊天,交付使用宿主可用的媒体/附件能力;不依赖 Codex 专用工具。切换宿主继续复用当前系统用户的系统凭证库和任务历史,不迁移凭据、不要求重新粘贴密钥。资金、权限与未知结果同幂等键恢复规则不变。
|
|
40
40
|
|
|
41
41
|
此功能不增加 Linux、Intel Mac 支持,也不代表已接入或认证 WorkBuddy 官方连接器市场;现有系统、Node.js 与正式发布门禁保持适用。
|
|
42
|
+
|
|
43
|
+
## 受信本地 Python 工具文件合同(开发候选)
|
|
44
|
+
|
|
45
|
+
纯文档包继续使用 `ngg-skill-package/v1`,原结构及字节生成规则不变。本地工具包使用内部元数据 `schemaVersion: "ngg-skill-package/v2"`;ZIP中的元数据文件名仍为 `skill-package.v1.json`。正式发布时须把该包的root/platform最低兼容版本绑定到实际支持v2的新版根包及CLI;本节不指定尚未冻结的发布版本。
|
|
46
|
+
|
|
47
|
+
v2须声明以下有限元数据:
|
|
48
|
+
|
|
49
|
+
```json
|
|
50
|
+
{
|
|
51
|
+
"localTools": {
|
|
52
|
+
"kind": "python",
|
|
53
|
+
"entrypoints": ["scripts/run.py"],
|
|
54
|
+
"runtimeLock": "references/runtime-lock.json"
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
仅此声明允许额外交付直接位于 `scripts/` 的Python源文件(文件名为ASCII字母/数字开头,后接字母、数字、下划线或连字符及`.py`)。入口必须存在且不重复;内部模块无需列作入口。全部源文件仍须列入已签名的逐文件清单,`executable=false`。不接受shell、pyc、任意YAML、嵌套脚本目录或根级runtime-lock。
|
|
60
|
+
|
|
61
|
+
运行清单是已签名的 `references/runtime-lock.json`,至少有 `schemaVersion: 1`及`files`路径到SHA256的映射。每个打包Python文件必须与其中同路径摘要一致;清单中不能出现未打包的scripts文件,也不能自引用运行清单。文档及同级依赖的摘要可继续由独立工具按自身范围复核;安装器不执行或解释其业务规则。
|
|
62
|
+
|
|
63
|
+
安装、复用、API合同加载和回滚只验证/交付字节,**不会执行Python、安装解释器/FFmpeg或调用付费服务**。工作流按实际阶段检查宿主依赖并明确调用已声明入口。全部既有签名、逐文件摘要、安全ZIP、32文件/4MiB、路径检查、原子替换及回滚规则继续生效。旧v1 loader明确拒绝v2;不能给旧包加脚本但保留v1声明,或把源码改成文档后缀绕过规则。
|
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.48" ||
|
|
51
51
|
manifestValue.artifactPath !==
|
|
52
52
|
`packages/plugins/nggaigc-plugin-${manifestValue.version}.zip` ||
|
|
53
53
|
typeof manifestValue.sourceCommit !== "string" ||
|
|
@@ -345,7 +345,8 @@ function storedZipEntries(input) {
|
|
|
345
345
|
localOffset + 30 > centralOffset)
|
|
346
346
|
fail("PACKAGE_VERIFICATION_FAILED");
|
|
347
347
|
const unixMode = externalAttributes >>> 16;
|
|
348
|
-
if (unixMode !== 0 &&
|
|
348
|
+
if (unixMode !== 0 &&
|
|
349
|
+
((unixMode & 0xf000) !== 0x8000 || (unixMode & 0o111) !== 0))
|
|
349
350
|
fail("PACKAGE_VERIFICATION_FAILED");
|
|
350
351
|
const nameBytes = bytes.subarray(cursor + 46, cursor + 46 + nameLength);
|
|
351
352
|
let name;
|
|
@@ -382,12 +383,60 @@ function storedZipEntries(input) {
|
|
|
382
383
|
fail("PACKAGE_VERIFICATION_FAILED");
|
|
383
384
|
return result;
|
|
384
385
|
}
|
|
385
|
-
|
|
386
|
+
const PYTHON_SCRIPT = /^scripts\/[A-Za-z0-9][A-Za-z0-9_-]*\.py$/;
|
|
387
|
+
const PYTHON_RUNTIME_LOCK = "references/runtime-lock.json";
|
|
388
|
+
function validLocalPythonTools(value, paths) {
|
|
389
|
+
if (!record(value) ||
|
|
390
|
+
!exactKeys(value, ["kind", "entrypoints", "runtimeLock"]) ||
|
|
391
|
+
value.kind !== "python" ||
|
|
392
|
+
value.runtimeLock !== PYTHON_RUNTIME_LOCK ||
|
|
393
|
+
!paths.includes(PYTHON_RUNTIME_LOCK) ||
|
|
394
|
+
!Array.isArray(value.entrypoints) ||
|
|
395
|
+
value.entrypoints.length < 1 ||
|
|
396
|
+
value.entrypoints.length > MAX_FILES)
|
|
397
|
+
return false;
|
|
398
|
+
const seen = new Set();
|
|
399
|
+
for (const entry of value.entrypoints) {
|
|
400
|
+
if (typeof entry !== "string" ||
|
|
401
|
+
!PYTHON_SCRIPT.test(entry) ||
|
|
402
|
+
!paths.includes(entry) ||
|
|
403
|
+
seen.has(entry.toLowerCase()))
|
|
404
|
+
return false;
|
|
405
|
+
seen.add(entry.toLowerCase());
|
|
406
|
+
}
|
|
407
|
+
return true;
|
|
408
|
+
}
|
|
409
|
+
function validLocalPythonRuntimeLock(bytes, files) {
|
|
410
|
+
try {
|
|
411
|
+
const lock = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes));
|
|
412
|
+
if (!record(lock) ||
|
|
413
|
+
lock.schemaVersion !== 1 ||
|
|
414
|
+
!record(lock.files) ||
|
|
415
|
+
Object.hasOwn(lock.files, PYTHON_RUNTIME_LOCK) ||
|
|
416
|
+
Object.values(lock.files).some((value) => typeof value !== "string" || !DIGEST.test(value)))
|
|
417
|
+
return false;
|
|
418
|
+
const locked = lock.files;
|
|
419
|
+
return (files
|
|
420
|
+
.filter((file) => PYTHON_SCRIPT.test(file.path))
|
|
421
|
+
.every((file) => locked[file.path] === file.sha256) &&
|
|
422
|
+
Object.keys(locked)
|
|
423
|
+
.filter((name) => name.startsWith("scripts/"))
|
|
424
|
+
.every((name) => files.some((file) => PYTHON_SCRIPT.test(file.path) &&
|
|
425
|
+
file.path === name &&
|
|
426
|
+
file.sha256 === locked[name])));
|
|
427
|
+
}
|
|
428
|
+
catch {
|
|
429
|
+
return false;
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
function packageFileType(value, localPython = false) {
|
|
386
433
|
if (value === "SKILL.md" ||
|
|
387
434
|
/^references\/[A-Za-z0-9._/-]+\.(md|json)$/.test(value))
|
|
388
435
|
return "document";
|
|
389
436
|
if (/^assets\/[A-Za-z0-9._/-]+\.png$/.test(value))
|
|
390
437
|
return "png";
|
|
438
|
+
if (localPython && PYTHON_SCRIPT.test(value))
|
|
439
|
+
return "python";
|
|
391
440
|
return undefined;
|
|
392
441
|
}
|
|
393
442
|
function validStaticPng(input) {
|
|
@@ -459,8 +508,9 @@ function decodePackage(bytes, entry, trust) {
|
|
|
459
508
|
catch {
|
|
460
509
|
fail("PACKAGE_VERIFICATION_FAILED");
|
|
461
510
|
}
|
|
511
|
+
const localPython = payload?.schemaVersion === "ngg-skill-package/v2";
|
|
462
512
|
if (!record(payload) ||
|
|
463
|
-
payload.schemaVersion !== "ngg-skill-package/v1" ||
|
|
513
|
+
(!localPython && payload.schemaVersion !== "ngg-skill-package/v1") ||
|
|
464
514
|
payload.artifactId !== entry.id ||
|
|
465
515
|
payload.packageVersion !== entry.version ||
|
|
466
516
|
canonical(payload.compatibility) !== canonical(metadata.compatibility) ||
|
|
@@ -473,8 +523,12 @@ function decodePackage(bytes, entry, trust) {
|
|
|
473
523
|
"packageVersion",
|
|
474
524
|
"compatibility",
|
|
475
525
|
"files",
|
|
526
|
+
...(localPython ? ["localTools"] : []),
|
|
476
527
|
]))
|
|
477
528
|
fail("PACKAGE_VERIFICATION_FAILED");
|
|
529
|
+
if (localPython &&
|
|
530
|
+
!validLocalPythonTools(payload.localTools, payload.files.map((file) => file?.path)))
|
|
531
|
+
fail("PACKAGE_VERIFICATION_FAILED");
|
|
478
532
|
const seen = new Set();
|
|
479
533
|
let total = 0;
|
|
480
534
|
for (const file of payload.files) {
|
|
@@ -490,7 +544,7 @@ function decodePackage(bytes, entry, trust) {
|
|
|
490
544
|
file.path
|
|
491
545
|
.split("/")
|
|
492
546
|
.some((part) => !part || part === "." || part === ".." || /[. ]$/.test(part)) ||
|
|
493
|
-
!packageFileType(file.path))
|
|
547
|
+
!packageFileType(file.path, localPython))
|
|
494
548
|
fail("PACKAGE_VERIFICATION_FAILED");
|
|
495
549
|
const folded = file.path.toLowerCase();
|
|
496
550
|
if (seen.has(folded) ||
|
|
@@ -511,6 +565,9 @@ function decodePackage(bytes, entry, trust) {
|
|
|
511
565
|
}
|
|
512
566
|
if (!seen.has("skill.md") || archive.size !== payload.files.length + 1)
|
|
513
567
|
fail("PACKAGE_VERIFICATION_FAILED");
|
|
568
|
+
if (localPython &&
|
|
569
|
+
!validLocalPythonRuntimeLock(archive.get(PYTHON_RUNTIME_LOCK), payload.files))
|
|
570
|
+
fail("PACKAGE_VERIFICATION_FAILED");
|
|
514
571
|
return payload.files.map((file) => ({
|
|
515
572
|
path: file.path,
|
|
516
573
|
sha256: file.sha256,
|
|
@@ -565,6 +622,9 @@ async function existingReceipt(target, entry, trust) {
|
|
|
565
622
|
try {
|
|
566
623
|
const packageBytes = await readFile(path.join(target, ".nggaigc-package.bin"));
|
|
567
624
|
const signedFiles = decodePackage(packageBytes, entry, trust);
|
|
625
|
+
// The signed archive's versioned verifier already checked each file type
|
|
626
|
+
// and local-tools declaration. Never infer Python permission from receipt data.
|
|
627
|
+
const signedPaths = new Set(signedFiles.map((file) => file.path));
|
|
568
628
|
if (JSON.stringify(Object.fromEntries(signedFiles.map((file) => [file.path, file.sha256]))) !== JSON.stringify(receipt.files))
|
|
569
629
|
return false;
|
|
570
630
|
const names = [];
|
|
@@ -590,7 +650,7 @@ async function existingReceipt(target, entry, trust) {
|
|
|
590
650
|
].sort()))
|
|
591
651
|
return false;
|
|
592
652
|
for (const [name, digest] of Object.entries(receipt.files)) {
|
|
593
|
-
if (!
|
|
653
|
+
if (!signedPaths.has(name) ||
|
|
594
654
|
name.split("/").some((part) => part === "." || part === ".."))
|
|
595
655
|
return false;
|
|
596
656
|
const file = path.join(target, ...name.split("/"));
|
package/dist/install.js
CHANGED
|
@@ -9,7 +9,7 @@ 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.48.zip"),
|
|
13
13
|
manifest: path.join(vendor, "manifest.json"),
|
|
14
14
|
trust: path.join(vendor, "trusted-keys.json"),
|
|
15
15
|
};
|
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.48.zip"),
|
|
19
19
|
manifest: path.join(vendor, "manifest.json"),
|
|
20
20
|
trust: path.join(vendor, "trusted-keys.json"),
|
|
21
21
|
});
|
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.48",
|
|
5
|
+
"sourceCommit": "17038f7181c59b72b968866e68547f248069a3c5",
|
|
6
|
+
"artifactPath": "packages/plugins/nggaigc-plugin-1.1.48.zip",
|
|
7
|
+
"sha256": "92831457de7bd2f3e60ccd3805c4b7846ec32df7fd255b6b552dee225a83acc3",
|
|
8
|
+
"sizeBytes": 508669,
|
|
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": "54daccc21f12195f2c44a1cd049e10bff5a73fa6daba245e201b3affe2e1ad7d",
|
|
17
17
|
"installer/install.cjs": "76f4ed73233fd39900fb0bedbc434dea39e52e6b6b4622f3fd388a5ca09c6f62",
|
|
18
18
|
"installer/legacy-root-digests.json": "922552646a5aa6cff8616c372912a37b1d5f263351206b85785ed9b2eae31641",
|
|
19
19
|
"installer/signed-pair-1.1.16.json": "ccb22a90302cc5c9c585067ebc211a27b0c9d8a177c2740a5678a58a3d70bfe9",
|
|
@@ -25,23 +25,23 @@
|
|
|
25
25
|
"migration/seedream-1.1.3/SKILL.md": "5c5cf3c2d99376f246425e873c5566436ed528256372ac3208abb60364c4517c",
|
|
26
26
|
"skills/nggaigc/agents/openai.yaml": "8936d97b9821e687e224e9349cc42be2ee5fc20988562efffbcb70080aedf87c",
|
|
27
27
|
"skills/nggaigc/references/catalog-and-updates.md": "a43bee94a480aa2bf0b1e7038cee6f27fb86d2bd8fa88a28a63678963d7c1530",
|
|
28
|
-
"skills/nggaigc/references/source.json": "
|
|
28
|
+
"skills/nggaigc/references/source.json": "5fb7443d94c522a22cd03e508bb8b1bb2c6f67983b719ce85f5bf88bef2f01d0",
|
|
29
29
|
"skills/nggaigc/scripts/api_client.mjs": "e16bf750a297ef7e88e4843d2fba9c33b412a66516bfe76822d7deec6c153069",
|
|
30
|
-
"skills/nggaigc/scripts/api_package.mjs": "
|
|
31
|
-
"skills/nggaigc/scripts/bootstrap-public.json": "
|
|
32
|
-
"skills/nggaigc/scripts/launch-ngg-client.cjs": "
|
|
30
|
+
"skills/nggaigc/scripts/api_package.mjs": "824ea8f935e2c3aec7ad5ea5c6ad043f1b77ccd9918c86687a9bd61558954fe4",
|
|
31
|
+
"skills/nggaigc/scripts/bootstrap-public.json": "6d0a7d79ae4364fb5fba5786d87417732af6f559e32592373031daf24db078d2",
|
|
32
|
+
"skills/nggaigc/scripts/launch-ngg-client.cjs": "4f4786c2e70fbac8e24fa2de1ba02aa713d68d3f36773f4c7c242f91364a005e",
|
|
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": "254f36fad2e0fb600c91b9ae22e8f35cfd602fbb36c25ef56ab494436a2e4a77",
|
|
36
|
+
"skills/nggaigc/scripts/ngg-session.mjs": "026a1d9d480712ee3e2f4d505e1448e78001800c88025cd048658b38d3c040ce",
|
|
37
37
|
"skills/nggaigc/scripts/supported-platforms.json": "ec8b0754c489e04534a1d9880dd6664ba9c5bcd07789e06d138e0923f23575ff",
|
|
38
|
-
"skills/nggaigc/scripts/windows-credential.ps1": "
|
|
38
|
+
"skills/nggaigc/scripts/windows-credential.ps1": "641888d8c6016bb84f18df19315322ed802c5709fbe5209250eaf1b0ce498aec",
|
|
39
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": "FQ+2ziXnms95GTjoiJcdjVxekqOjSBcsfpZrGh+0IKCChqXt18AZi59WSPRDfhdM1BQO8AEiqZtM1ge5gI+JDA=="
|
|
46
46
|
}
|
|
47
47
|
}
|
|
index 4e2828f..9711cc3 100644
|
|
|
Binary file
|