yxyl-cli-plugin 0.2.19

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 ADDED
@@ -0,0 +1,7 @@
1
+ # yxyl-cli-plugin
2
+
3
+ Accio Work 插件的原生 Skill 执行入口。首次运行下载当前系统的版本固定运行包;Windows x64、macOS Intel 与 Apple Silicon。
4
+
5
+ 新任务使用 `npx -y --prefer-online yxyl-cli-plugin@latest --version` 确定版本,后续命令固定该版本。业务由 Rust 执行,受保护功能需要授权。Chrome 扩展独立安装。
6
+
7
+ 下载和诊断写 stderr,业务不自动重试。安装锁遗留或缓存损坏时,先结束相关任务并联系维护者处理;勿删除授权或额度数据库。
@@ -0,0 +1,27 @@
1
+ import {unzipSync} from 'fflate';
2
+ import {hash,safePath,fail} from './model.mjs';
3
+ // Inspect the central directory before decompression; never trust archive-provided paths or sizes.
4
+ export function extractVerified(bytes,item){
5
+ if(bytes.length!==item.size||hash(bytes)!==item.sha256)fail('RUNTIME_INTEGRITY_ERROR','运行包下载校验失败。');
6
+ let end=-1;for(let i=bytes.length-22;i>=Math.max(0,bytes.length-65557);i--)if(bytes.readUInt32LE(i)===0x06054b50){end=i;break;}
7
+ if(end<0||bytes.readUInt16LE(end+4)||bytes.readUInt16LE(end+6)||end+22+bytes.readUInt16LE(end+20)!==bytes.length)fail('INVALID_ARCHIVE','不支持此 ZIP 格式。');
8
+ const count=bytes.readUInt16LE(end+10),start=bytes.readUInt32LE(end+16),size=bytes.readUInt32LE(end+12);
9
+ if(count!==Object.keys(item.files).length||start+size!==end)fail('INVALID_ARCHIVE','ZIP 文件清单不一致。');
10
+ let offset=start;const seen=new Set();
11
+ for(let i=0;i<count;i++){
12
+ if(offset+46>end||bytes.readUInt32LE(offset)!==0x02014b50)fail('INVALID_ARCHIVE','ZIP 目录损坏。');
13
+ const length=bytes.readUInt16LE(offset+28),extra=bytes.readUInt16LE(offset+30),comment=bytes.readUInt16LE(offset+32);
14
+ const next=offset+46+length+extra+comment;if(next>end)fail('INVALID_ARCHIVE','ZIP 目录越界。');
15
+ const name=safePath(bytes.subarray(offset+46,offset+46+length).toString('utf8'));
16
+ const file=item.files[name],mode=bytes.readUInt32LE(offset+38)>>>16,type=mode&0xf000;
17
+ if(!file||seen.has(name.toLowerCase())||bytes.readUInt16LE(offset+8)&1||![0,0x8000].includes(type)||bytes.readUInt32LE(offset+24)!==file.size)fail('INVALID_ARCHIVE','ZIP 含额外文件、链接或大小异常。');
18
+ seen.add(name.toLowerCase());offset=next;
19
+ }
20
+ if(offset!==end)fail('INVALID_ARCHIVE','ZIP 目录大小不符。');
21
+ const files=unzipSync(bytes,{filter:entry=>{
22
+ const file=item.files[entry.name];if(!file||entry.originalSize!==file.size)fail('INVALID_ARCHIVE','ZIP 本地记录与清单不符。');return true;
23
+ }});
24
+ if(Object.keys(files).length!==count)fail('INVALID_ARCHIVE','ZIP 文件数量不符。');
25
+ for(const [name,data]of Object.entries(files)){const file=item.files[name];if(!file||data.length!==file.size||hash(data)!==file.sha256)fail('RUNTIME_INTEGRITY_ERROR','运行文件校验失败。');}
26
+ return files;
27
+ }
package/lib/cache.mjs ADDED
@@ -0,0 +1,31 @@
1
+ import {mkdir,readFile,writeFile,lstat,readdir,rename,rm,realpath} from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ import {randomUUID} from 'node:crypto';
4
+ import {setTimeout as delay} from 'node:timers/promises';
5
+ import {hash,fail} from './model.mjs';
6
+ export async function verifyCache(root,item){
7
+ try{const info=await lstat(root);if(!info.isDirectory()||info.isSymbolicLink())fail('CACHE_CORRUPT','运行缓存目录异常。');}catch(error){if(error.code==='ENOENT')return false;throw error;}
8
+ const seen=[];
9
+ async function walk(dir,prefix=''){for(const entry of await readdir(dir,{withFileTypes:true})){const name=prefix+entry.name;if(entry.isSymbolicLink())fail('CACHE_CORRUPT','缓存中不允许链接。');if(entry.isDirectory())await walk(path.join(dir,entry.name),name+'/');else seen.push(name);}}
10
+ await walk(root);if(JSON.stringify(seen.sort())!==JSON.stringify([...Object.keys(item.files),'installed.json'].sort()))fail('CACHE_CORRUPT','运行缓存文件不完整,请结束任务后修复缓存。');
11
+ const marker=JSON.parse(await readFile(path.join(root,'installed.json'),'utf8'));if(marker.archiveSha256!==item.sha256)fail('CACHE_CORRUPT','缓存对应其他运行包。');
12
+ for(const [name,file]of Object.entries(item.files)){const data=await readFile(path.join(root,name));if(data.length!==file.size||hash(data)!==file.sha256)fail('CACHE_CORRUPT','运行缓存校验失败;不执行、不覆盖活跃缓存。');}
13
+ return true;
14
+ }
15
+ export async function withInstallLock(home,key,signal,action){
16
+ const parent=path.join(home,'runtime','locks');await mkdir(parent,{recursive:true});const lock=path.join(parent,key+'.lock');const deadline=Date.now()+30000;
17
+ for(;;){signal?.throwIfAborted();try{await mkdir(lock);break;}catch(error){if(error.code!=='EEXIST')throw error;if(Date.now()>=deadline)fail('INSTALL_BUSY','同版本正在安装或遗留安装锁未释放,请检查安装进程。');await delay(100,undefined,{signal});}}
18
+ try{await writeFile(path.join(lock,'owner.json'),JSON.stringify({pid:process.pid,createdAt:Date.now()}),{flag:'wx'});return await action();}finally{await rm(lock,{recursive:true,force:true});}
19
+ }
20
+ export async function commitCache(home,version,platform,item,files,signal){
21
+ const parent=path.join(home,'runtime','versions',version);await mkdir(parent,{recursive:true});
22
+ const base=await realpath(parent),target=path.join(base,platform),stage=path.join(base,`.staging-${platform}-${randomUUID()}`);
23
+ await mkdir(stage);
24
+ try{
25
+ for(const [name,bytes]of Object.entries(files)){signal?.throwIfAborted();const output=path.join(stage,name);await mkdir(path.dirname(output),{recursive:true});await writeFile(output,bytes,{flag:'wx',mode:item.files[name].executable?0o755:0o600});}
26
+ await writeFile(path.join(stage,'installed.json'),JSON.stringify({archiveSha256:item.sha256}),{flag:'wx'});
27
+ await verifyCache(stage,item);signal?.throwIfAborted();
28
+ try{await lstat(target);fail('CACHE_EXISTS','目标运行版本已存在,不覆盖。');}catch(error){if(error.code!=='ENOENT')throw error;}
29
+ await rename(stage,target);return target;
30
+ }finally{await rm(stage,{recursive:true,force:true});}
31
+ }
@@ -0,0 +1,15 @@
1
+ import path from 'node:path';
2
+ import {realpath} from 'node:fs/promises';
3
+ import {validateRelease,fail} from './model.mjs';
4
+ import {download} from './download.mjs';
5
+ import {extractVerified} from './archive.mjs';
6
+ import {verifyCache,withInstallLock,commitCache} from './cache.mjs';
7
+ export async function ensureRuntime({release,version,platform,home,signal,transport=download}){
8
+ const item=validateRelease(release,version,platform),target=path.join(home,'runtime','versions',version,platform);
9
+ return withInstallLock(home,`${version}-${platform}`,signal,async()=>{
10
+ if(await verifyCache(target,item))return realpath(target);
11
+ let bytes;for(const url of item.urls){signal?.throwIfAborted();try{bytes=await transport(url,item,release.redirectHosts,signal);break;}catch(error){if(signal?.aborted)throw error;}}
12
+ if(!bytes)fail('DOWNLOAD_FAILED','无法下载当前版本运行包;检查网络后重试,业务尚未执行。');
13
+ const files=extractVerified(bytes,item);return commitCache(home,version,platform,item,files,signal);
14
+ });
15
+ }
@@ -0,0 +1,18 @@
1
+ import https from 'node:https';
2
+ import {fail} from './model.mjs';
3
+ export async function download(url,item,redirectHosts,signal,remaining=5){
4
+ const parsed=new URL(url),allowed=new Set([...item.urls.map(u=>new URL(u).hostname),...redirectHosts]);
5
+ if(parsed.protocol!=='https:'||parsed.username||parsed.password||!allowed.has(parsed.hostname))fail('DOWNLOAD_SOURCE_DENIED','拒绝未登记的下载地址。');
6
+ return new Promise((resolve,reject)=>{
7
+ const request=https.get(parsed,{signal,headers:{'User-Agent':'yxyl-cli-plugin','Accept':'application/octet-stream'}},response=>{
8
+ if([301,302,303,307,308].includes(response.statusCode)){
9
+ response.resume();if(remaining<=0||!response.headers.location){reject(Object.assign(new Error('下载重定向失败。'),{code:'DOWNLOAD_FAILED'}));return;}
10
+ resolve(download(new URL(response.headers.location,parsed).href,item,redirectHosts,signal,remaining-1));return;
11
+ }
12
+ if(response.statusCode!==200){response.resume();reject(Object.assign(new Error(`运行包下载 HTTP ${response.statusCode}。`),{code:'DOWNLOAD_FAILED'}));return;}
13
+ const chunks=[];let length=0;
14
+ response.on('data',chunk=>{length+=chunk.length;if(length>item.size)response.destroy(Object.assign(new Error('下载超过声明大小。'),{code:'DOWNLOAD_TOO_LARGE'}));else chunks.push(chunk);});
15
+ response.on('end',()=>resolve(Buffer.concat(chunks)));response.on('error',reject);
16
+ });request.on('error',reject);request.setTimeout(30000,()=>request.destroy(Object.assign(new Error('下载超时。'),{code:'DOWNLOAD_TIMEOUT'})));
17
+ });
18
+ }
package/lib/entry.mjs ADDED
@@ -0,0 +1,25 @@
1
+ #!/usr/bin/env node
2
+ import {readFile} from 'node:fs/promises';
3
+ import {fileURLToPath} from 'node:url';
4
+ import path from 'node:path';
5
+ import os from 'node:os';
6
+ import {spawn} from 'node:child_process';
7
+ import {ensureRuntime} from './controller.mjs';
8
+ const root=fileURLToPath(new URL('../',import.meta.url));
9
+ const control=new AbortController();
10
+ let child;
11
+ for(const name of ['SIGINT','SIGTERM'])process.on(name,()=>{control.abort();if(child)child.kill(name);});
12
+ try{
13
+ const pkg=JSON.parse(await readFile(path.join(root,'package.json'),'utf8'));
14
+ const args=process.argv.slice(2);
15
+ if(args.length===1&&args[0]==='--version'){console.log(pkg.version);}else{
16
+ const release=JSON.parse(await readFile(path.join(root,'release.json'),'utf8'));
17
+ const platform=`${process.platform}-${process.arch}`,home=path.resolve(process.env.YXYL_HOME||path.join(os.homedir(),'.yxyl-plugin'));
18
+ const directory=await ensureRuntime({release,version:pkg.version,platform,home,signal:AbortSignal.any([control.signal,AbortSignal.timeout(180000)])});
19
+ control.signal.throwIfAborted();
20
+ const binary=path.join(directory,'native-bin',platform,process.platform==='win32'?'yxyl.exe':'yxyl');
21
+ // There is deliberately no retry after the native business process starts.
22
+ child=spawn(binary,args,{stdio:'inherit',shell:false,windowsHide:true});
23
+ process.exitCode=await new Promise((resolve,reject)=>{child.once('error',reject);child.once('close',(code,signal)=>resolve(code??(signal==='SIGINT'?130:1)));});
24
+ }
25
+ }catch(error){console.log(JSON.stringify({ok:false,error:{code:control.signal.aborted?'CANCELLED':(error.code||'RUNTIME_INSTALL_FAILED'),message:'运行程序准备或启动失败;业务不会自动重试。'+(typeof error.code==='string'&&/^[A-Z_]+$/.test(error.code)?` 错误:${error.code}`:'')}}));process.exitCode=1;}
package/lib/model.mjs ADDED
@@ -0,0 +1,25 @@
1
+ import {createHash} from 'node:crypto';
2
+ export const platforms=['win32-x64','darwin-x64','darwin-arm64'];
3
+ export const hash=bytes=>createHash('sha256').update(bytes).digest('hex');
4
+ export function fail(code,message){const error=new Error(message);error.code=code;throw error;}
5
+ export function safePath(name){
6
+ if(typeof name!=='string'||name.length>240||!name||/[\\:\x00-\x1f]/.test(name)||name.startsWith('/')||name.split('/').some(p=>!p||p==='.'||p==='..'||/[. ]$/.test(p)||/^(con|prn|aux|nul|com[1-9]|lpt[1-9])(?:\.|$)/i.test(p)))fail('UNSAFE_ARCHIVE_PATH','运行包包含不安全路径。');
7
+ return name;
8
+ }
9
+ export function validateRelease(release,version,platform){
10
+ if(!/^\d+\.\d+\.\d+$/.test(version)||release.schemaVersion!==1||release.packageName!=='yxyl-cli-plugin'||release.version!==version)fail('INVALID_RELEASE','发行清单与 npm 版本不一致。');
11
+ if(!platforms.includes(platform)||!release.platforms?.[platform])fail('UNSUPPORTED_PLATFORM','未提供当前系统的原生运行包。');
12
+ const item=release.platforms[platform];
13
+ if(!Array.isArray(item.urls)||!item.urls.length||!item.urls.every(url=>{try{const u=new URL(url);return u.protocol==='https:'&&!u.username&&!u.password&&!u.hash;}catch{return false;}}))fail('INVALID_RELEASE','下载源必须使用 HTTPS 且不含凭据。');
14
+ if(!Array.isArray(release.redirectHosts)||!release.redirectHosts.every(h=>typeof h==='string'&&/^[a-z0-9.-]+$/.test(h)))fail('INVALID_RELEASE','重定向主机清单无效。');
15
+ if(!/^[a-f0-9]{64}$/.test(item.sha256)||!Number.isSafeInteger(item.size)||item.size<=0||item.size>256*1024*1024)fail('INVALID_RELEASE','运行包大小或摘要无效。');
16
+ const names=Object.keys(item.files||{}),seen=new Set();let total=0;
17
+ if(!names.length||names.length>2000)fail('INVALID_RELEASE','文件清单为空或过大。');
18
+ for(const name of names){safePath(name);const key=name.toLowerCase();if(seen.has(key))fail('INVALID_RELEASE','文件路径重复。');seen.add(key);
19
+ const file=item.files[name];if(!/^[a-f0-9]{64}$/.test(file.sha256)||!Number.isSafeInteger(file.size)||file.size<0||typeof file.executable!=='boolean')fail('INVALID_RELEASE','文件校验清单无效。');total+=file.size;
20
+ }
21
+ const suffix=platform==='win32-x64'?'.exe':'';
22
+ for(const name of [`native-bin/${platform}/yxyl${suffix}`,`native-bin/${platform}/yxyl-bridge${suffix}`,'runtime/skills.json','runtime/native-manifest.json'])if(!item.files[name])fail('INVALID_RELEASE','运行包缺少 CLI、桥接或注册表。');
23
+ if(total>512*1024*1024)fail('INVALID_RELEASE','运行包解压大小超过限制。');
24
+ return item;
25
+ }
package/package.json ADDED
@@ -0,0 +1,21 @@
1
+ {
2
+ "name": "yxyl-cli-plugin",
3
+ "version": "0.2.19",
4
+ "type": "module",
5
+ "description": "Native Rust skill runtime for the YXyl Accio Work plugin",
6
+ "license": "UNLICENSED",
7
+ "engines": {
8
+ "node": ">=22"
9
+ },
10
+ "bin": {
11
+ "yxyl": "lib/entry.mjs"
12
+ },
13
+ "files": [
14
+ "lib/",
15
+ "release.json",
16
+ "README.md"
17
+ ],
18
+ "dependencies": {
19
+ "fflate": "0.8.3"
20
+ }
21
+ }
package/release.json ADDED
@@ -0,0 +1,355 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "packageName": "yxyl-cli-plugin",
4
+ "version": "0.2.19",
5
+ "runtimeProtocol": 1,
6
+ "bridgeUpgradeProtocol": 1,
7
+ "sourceCommit": "d13b137955e6fba24fa7116472efbec19566d574",
8
+ "redirectHosts": [
9
+ "release-assets.githubusercontent.com"
10
+ ],
11
+ "platforms": {
12
+ "win32-x64": {
13
+ "urls": [
14
+ "https://github.com/areter/yxyl-cli-plugin-releases/releases/download/v0.2.19/yxyl-runtime-0.2.19-win32-x64.zip"
15
+ ],
16
+ "size": 13582521,
17
+ "sha256": "c8ae89cfb60cc4aca8e163f683beaf34039e528e1bbbc82641df7fcd77136b8b",
18
+ "files": {
19
+ "runtime/skills.json": {
20
+ "size": 1552,
21
+ "sha256": "6a38350966a9cbe2492cbf6facbfcf77abe7d0d00a874fa0150602759ab62320",
22
+ "executable": false
23
+ },
24
+ "skills/framework-demo/SKILL.md": {
25
+ "size": 1649,
26
+ "sha256": "05336f97b6c72764a1a596e6db6c869ed79e54e7a25a5a278faede28ca425203",
27
+ "executable": false
28
+ },
29
+ "skills/okki-mail-draft/SKILL.md": {
30
+ "size": 11375,
31
+ "sha256": "42b07afb6516a3a7a37d46095b278b01c539d6a90dea7a494b414b9c490593b4",
32
+ "executable": false
33
+ },
34
+ "skills/okki-prospect-research/SKILL.md": {
35
+ "size": 9366,
36
+ "sha256": "8bbdf6ea4988dda78cfab55d4d68a458f662326c11d30a00c929ad175ffa7a35",
37
+ "executable": false
38
+ },
39
+ "skills/okki-prospect-research/references/personalized-email.md": {
40
+ "size": 2237,
41
+ "sha256": "854c291534507a2bc062c71d3c563e07d0c7c9faa673f9b6085aa6fbefb8857a",
42
+ "executable": false
43
+ },
44
+ "skills/yxyl-setup/SKILL.md": {
45
+ "size": 6108,
46
+ "sha256": "13cdbbd00461172ea34ea97bbe4484fe4261c1962f3d6c247ac8142e332e3b86",
47
+ "executable": false
48
+ },
49
+ "resources/icon.svg": {
50
+ "size": 324,
51
+ "sha256": "ef3554d8d5e11e313ca439293f7b0f7faa4e60905e24cc75053637b28f6431c5",
52
+ "executable": false
53
+ },
54
+ "resources/licenses/agent-browser-cli-MIT.txt": {
55
+ "size": 1073,
56
+ "sha256": "3e843ba4e2cb604e38759d8a18e2e10672a54180c9b2873166bc07a76449662e",
57
+ "executable": false
58
+ },
59
+ "tools/crawl4ai/server.py": {
60
+ "size": 230,
61
+ "sha256": "d808fa350f5e31260bbc8f2bf730d2c972f78ff297fc29e063dea6d1d6162c2d",
62
+ "executable": false
63
+ },
64
+ "tools/crawl4ai/models.py": {
65
+ "size": 795,
66
+ "sha256": "bd389a35d7d1451b72f4808001d0fac34218c7f6bbab7139e8636143b0bdb8d5",
67
+ "executable": false
68
+ },
69
+ "tools/crawl4ai/controllers.py": {
70
+ "size": 2983,
71
+ "sha256": "8d49d8b5d8193041a459ec9275fe0a664364672725b4cc3827248cfaf2abaf4f",
72
+ "executable": false
73
+ },
74
+ "tools/crawl4ai/page_quality.py": {
75
+ "size": 365,
76
+ "sha256": "22348c47722a2bc08e7060fcfc4aec05044992769629aa352acf59f039c31cd7",
77
+ "executable": false
78
+ },
79
+ "tools/crawl4ai/browser_service.py": {
80
+ "size": 5922,
81
+ "sha256": "d2419f27718bb5733583c5da194670208f8c340689997499a703378d50879ce8",
82
+ "executable": false
83
+ },
84
+ "tools/crawl4ai/requirements-lock.txt": {
85
+ "size": 1716,
86
+ "sha256": "88544830933cad01f90cf2bb51c39f6ebd568be3444120fd2d01d9f764e99f75",
87
+ "executable": false
88
+ },
89
+ "package.json": {
90
+ "size": 61,
91
+ "sha256": "645345d78d7a2d92a37c551383dc0fd2e6ed8a582830812a165dcd46c1bc9665",
92
+ "executable": false
93
+ },
94
+ "runtime/native-manifest.json": {
95
+ "size": 808,
96
+ "sha256": "7a01e2772d4a3dee4dab959f8728f9411b3cb069d71b014673f46e758bad9b91",
97
+ "executable": false
98
+ },
99
+ "native-bin/win32-x64/yxyl.exe": {
100
+ "size": 7766016,
101
+ "sha256": "95bb00fe0ea6ccdb08d3443550040cd3d2a27891b011fdca2e285a2acae10031",
102
+ "executable": true
103
+ },
104
+ "native-bin/win32-x64/yxyl-bridge.exe": {
105
+ "size": 4575744,
106
+ "sha256": "140fd1eefd7f6b49c37cd42ac636041b4899f2fdc8cd6dc5af9182466203603c",
107
+ "executable": true
108
+ },
109
+ "native-bin/win32-x64/yxyl-framework-demo.exe": {
110
+ "size": 289280,
111
+ "sha256": "29711c259b944a9db82ffd346ff601c1b784cb22ef71033a4b4ea8cf3f396074",
112
+ "executable": true
113
+ },
114
+ "native-bin/win32-x64/yxyl-okki-mail-draft.exe": {
115
+ "size": 8129024,
116
+ "sha256": "c6d1d0a5086515579875542db01307177874419459fb8bbf4050d2d8542fe812",
117
+ "executable": true
118
+ },
119
+ "native-bin/win32-x64/yxyl-okki-prospect-research.exe": {
120
+ "size": 9651712,
121
+ "sha256": "e2f2a3a098ceb53680a7be28233682f9d638e957efe30914e650900d71135d99",
122
+ "executable": true
123
+ }
124
+ }
125
+ },
126
+ "darwin-x64": {
127
+ "urls": [
128
+ "https://github.com/areter/yxyl-cli-plugin-releases/releases/download/v0.2.19/yxyl-runtime-0.2.19-darwin-x64.zip"
129
+ ],
130
+ "size": 10294288,
131
+ "sha256": "a9bf83ea8924bfff8bba1c16d29c654cebbc6f70b3216570faeb1d17c82d486d",
132
+ "files": {
133
+ "runtime/skills.json": {
134
+ "size": 1552,
135
+ "sha256": "6a38350966a9cbe2492cbf6facbfcf77abe7d0d00a874fa0150602759ab62320",
136
+ "executable": false
137
+ },
138
+ "skills/framework-demo/SKILL.md": {
139
+ "size": 1649,
140
+ "sha256": "05336f97b6c72764a1a596e6db6c869ed79e54e7a25a5a278faede28ca425203",
141
+ "executable": false
142
+ },
143
+ "skills/okki-mail-draft/SKILL.md": {
144
+ "size": 11375,
145
+ "sha256": "42b07afb6516a3a7a37d46095b278b01c539d6a90dea7a494b414b9c490593b4",
146
+ "executable": false
147
+ },
148
+ "skills/okki-prospect-research/SKILL.md": {
149
+ "size": 9366,
150
+ "sha256": "8bbdf6ea4988dda78cfab55d4d68a458f662326c11d30a00c929ad175ffa7a35",
151
+ "executable": false
152
+ },
153
+ "skills/okki-prospect-research/references/personalized-email.md": {
154
+ "size": 2237,
155
+ "sha256": "854c291534507a2bc062c71d3c563e07d0c7c9faa673f9b6085aa6fbefb8857a",
156
+ "executable": false
157
+ },
158
+ "skills/yxyl-setup/SKILL.md": {
159
+ "size": 6108,
160
+ "sha256": "13cdbbd00461172ea34ea97bbe4484fe4261c1962f3d6c247ac8142e332e3b86",
161
+ "executable": false
162
+ },
163
+ "resources/icon.svg": {
164
+ "size": 324,
165
+ "sha256": "ef3554d8d5e11e313ca439293f7b0f7faa4e60905e24cc75053637b28f6431c5",
166
+ "executable": false
167
+ },
168
+ "resources/licenses/agent-browser-cli-MIT.txt": {
169
+ "size": 1073,
170
+ "sha256": "3e843ba4e2cb604e38759d8a18e2e10672a54180c9b2873166bc07a76449662e",
171
+ "executable": false
172
+ },
173
+ "tools/crawl4ai/server.py": {
174
+ "size": 230,
175
+ "sha256": "d808fa350f5e31260bbc8f2bf730d2c972f78ff297fc29e063dea6d1d6162c2d",
176
+ "executable": false
177
+ },
178
+ "tools/crawl4ai/models.py": {
179
+ "size": 795,
180
+ "sha256": "bd389a35d7d1451b72f4808001d0fac34218c7f6bbab7139e8636143b0bdb8d5",
181
+ "executable": false
182
+ },
183
+ "tools/crawl4ai/controllers.py": {
184
+ "size": 2983,
185
+ "sha256": "8d49d8b5d8193041a459ec9275fe0a664364672725b4cc3827248cfaf2abaf4f",
186
+ "executable": false
187
+ },
188
+ "tools/crawl4ai/page_quality.py": {
189
+ "size": 365,
190
+ "sha256": "22348c47722a2bc08e7060fcfc4aec05044992769629aa352acf59f039c31cd7",
191
+ "executable": false
192
+ },
193
+ "tools/crawl4ai/browser_service.py": {
194
+ "size": 5922,
195
+ "sha256": "d2419f27718bb5733583c5da194670208f8c340689997499a703378d50879ce8",
196
+ "executable": false
197
+ },
198
+ "tools/crawl4ai/requirements-lock.txt": {
199
+ "size": 1716,
200
+ "sha256": "88544830933cad01f90cf2bb51c39f6ebd568be3444120fd2d01d9f764e99f75",
201
+ "executable": false
202
+ },
203
+ "package.json": {
204
+ "size": 61,
205
+ "sha256": "645345d78d7a2d92a37c551383dc0fd2e6ed8a582830812a165dcd46c1bc9665",
206
+ "executable": false
207
+ },
208
+ "runtime/native-manifest.json": {
209
+ "size": 794,
210
+ "sha256": "33c7f8b999a7a98f8060eaf0703d3446f4735f706564e706e654cbcb0f8c725e",
211
+ "executable": false
212
+ },
213
+ "native-bin/darwin-x64/yxyl": {
214
+ "size": 4919808,
215
+ "sha256": "31b1bab5e6e12f135a6eedb0ce6d18046f6f00dbd81b87357eb51bf0cbea7ccd",
216
+ "executable": true
217
+ },
218
+ "native-bin/darwin-x64/yxyl-bridge": {
219
+ "size": 3815480,
220
+ "sha256": "2385fb223bd79f6b86e4c48c36f02935cdd08cd4113a76381a86b154b1ff9728",
221
+ "executable": true
222
+ },
223
+ "native-bin/darwin-x64/yxyl-framework-demo": {
224
+ "size": 479584,
225
+ "sha256": "eea294f74e7daa5cc798d63b7806da15ea31a80b5db160478df899fac12b18f8",
226
+ "executable": true
227
+ },
228
+ "native-bin/darwin-x64/yxyl-okki-mail-draft": {
229
+ "size": 5235496,
230
+ "sha256": "c2f0fe6a2af38b6743e8848c0db697c944cfc70271dcf1ba612c48c44279de71",
231
+ "executable": true
232
+ },
233
+ "native-bin/darwin-x64/yxyl-okki-prospect-research": {
234
+ "size": 6607008,
235
+ "sha256": "8d0af9c433077509f3d57f0a04d43528c9d3233ea322c804b2d9161ddb32033c",
236
+ "executable": true
237
+ }
238
+ }
239
+ },
240
+ "darwin-arm64": {
241
+ "urls": [
242
+ "https://github.com/areter/yxyl-cli-plugin-releases/releases/download/v0.2.19/yxyl-runtime-0.2.19-darwin-arm64.zip"
243
+ ],
244
+ "size": 9499970,
245
+ "sha256": "2a79b4faeaca1967a5e6ad61ddf8059d8c0c2f515e4753ec9c204f1a33c062c0",
246
+ "files": {
247
+ "runtime/skills.json": {
248
+ "size": 1552,
249
+ "sha256": "6a38350966a9cbe2492cbf6facbfcf77abe7d0d00a874fa0150602759ab62320",
250
+ "executable": false
251
+ },
252
+ "skills/framework-demo/SKILL.md": {
253
+ "size": 1649,
254
+ "sha256": "05336f97b6c72764a1a596e6db6c869ed79e54e7a25a5a278faede28ca425203",
255
+ "executable": false
256
+ },
257
+ "skills/okki-mail-draft/SKILL.md": {
258
+ "size": 11375,
259
+ "sha256": "42b07afb6516a3a7a37d46095b278b01c539d6a90dea7a494b414b9c490593b4",
260
+ "executable": false
261
+ },
262
+ "skills/okki-prospect-research/SKILL.md": {
263
+ "size": 9366,
264
+ "sha256": "8bbdf6ea4988dda78cfab55d4d68a458f662326c11d30a00c929ad175ffa7a35",
265
+ "executable": false
266
+ },
267
+ "skills/okki-prospect-research/references/personalized-email.md": {
268
+ "size": 2237,
269
+ "sha256": "854c291534507a2bc062c71d3c563e07d0c7c9faa673f9b6085aa6fbefb8857a",
270
+ "executable": false
271
+ },
272
+ "skills/yxyl-setup/SKILL.md": {
273
+ "size": 6108,
274
+ "sha256": "13cdbbd00461172ea34ea97bbe4484fe4261c1962f3d6c247ac8142e332e3b86",
275
+ "executable": false
276
+ },
277
+ "resources/icon.svg": {
278
+ "size": 324,
279
+ "sha256": "ef3554d8d5e11e313ca439293f7b0f7faa4e60905e24cc75053637b28f6431c5",
280
+ "executable": false
281
+ },
282
+ "resources/licenses/agent-browser-cli-MIT.txt": {
283
+ "size": 1073,
284
+ "sha256": "3e843ba4e2cb604e38759d8a18e2e10672a54180c9b2873166bc07a76449662e",
285
+ "executable": false
286
+ },
287
+ "tools/crawl4ai/server.py": {
288
+ "size": 230,
289
+ "sha256": "d808fa350f5e31260bbc8f2bf730d2c972f78ff297fc29e063dea6d1d6162c2d",
290
+ "executable": false
291
+ },
292
+ "tools/crawl4ai/models.py": {
293
+ "size": 795,
294
+ "sha256": "bd389a35d7d1451b72f4808001d0fac34218c7f6bbab7139e8636143b0bdb8d5",
295
+ "executable": false
296
+ },
297
+ "tools/crawl4ai/controllers.py": {
298
+ "size": 2983,
299
+ "sha256": "8d49d8b5d8193041a459ec9275fe0a664364672725b4cc3827248cfaf2abaf4f",
300
+ "executable": false
301
+ },
302
+ "tools/crawl4ai/page_quality.py": {
303
+ "size": 365,
304
+ "sha256": "22348c47722a2bc08e7060fcfc4aec05044992769629aa352acf59f039c31cd7",
305
+ "executable": false
306
+ },
307
+ "tools/crawl4ai/browser_service.py": {
308
+ "size": 5922,
309
+ "sha256": "d2419f27718bb5733583c5da194670208f8c340689997499a703378d50879ce8",
310
+ "executable": false
311
+ },
312
+ "tools/crawl4ai/requirements-lock.txt": {
313
+ "size": 1716,
314
+ "sha256": "88544830933cad01f90cf2bb51c39f6ebd568be3444120fd2d01d9f764e99f75",
315
+ "executable": false
316
+ },
317
+ "package.json": {
318
+ "size": 61,
319
+ "sha256": "645345d78d7a2d92a37c551383dc0fd2e6ed8a582830812a165dcd46c1bc9665",
320
+ "executable": false
321
+ },
322
+ "runtime/native-manifest.json": {
323
+ "size": 806,
324
+ "sha256": "873a423b771a0784f879e52d8cab8475ede0fa1d40d665ceca6035fd14e4cf8e",
325
+ "executable": false
326
+ },
327
+ "native-bin/darwin-arm64/yxyl": {
328
+ "size": 4650736,
329
+ "sha256": "498188962a4a93a2b127d427cf53595cdec313d67ee7b77b3e490c533f0863da",
330
+ "executable": true
331
+ },
332
+ "native-bin/darwin-arm64/yxyl-bridge": {
333
+ "size": 3696576,
334
+ "sha256": "d0b74f41e0b5acacbc44adb06c44642d672c1e3bd05b9bfbce11a84e4c11e241",
335
+ "executable": true
336
+ },
337
+ "native-bin/darwin-arm64/yxyl-framework-demo": {
338
+ "size": 474992,
339
+ "sha256": "c4a4ac7e25d2cc942528b1e88b5ffcef81ce53e414f6832033fb2436faab0a33",
340
+ "executable": true
341
+ },
342
+ "native-bin/darwin-arm64/yxyl-okki-mail-draft": {
343
+ "size": 4931664,
344
+ "sha256": "6a7d4c47f16f1cb56058aeaeec6584e26c1be4addc68b5d13b1871c01bc5b9a1",
345
+ "executable": true
346
+ },
347
+ "native-bin/darwin-arm64/yxyl-okki-prospect-research": {
348
+ "size": 6222864,
349
+ "sha256": "b96cfab9726d1afaba14902ea06c42dfd6caed86f92bbc6f7911c56f91a9f4c5",
350
+ "executable": true
351
+ }
352
+ }
353
+ }
354
+ }
355
+ }