@petercjl/cloud-hug-style-transfer 0.3.1 → 0.4.0
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 +2 -2
- package/capabilities.json +245 -1
- package/npm/arguments.mjs +28 -0
- package/npm/cli.mjs +29 -35
- package/npm/integrity.json +3 -2
- package/npm/metadata.mjs +18 -0
- package/npm/pack.mjs +8 -0
- package/npm/skills.mjs +29 -14
- package/npm/update.mjs +49 -34
- package/package.json +6 -3
- package/skills/cloud-hug-style-transfer/SKILL.md +5 -1
- package/skills/cloud-hug-style-transfer/agents/openai.yaml +0 -1
- package/skills/cloud-hug-style-transfer/references/maintenance.md +9 -0
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
将旧详情页、产品摄影、主 KV 或 SKU 转换为抱抱云朵社品牌视觉,保留当次商品事实、文案与用途。包内包含完整 19 页定稿、品牌标识、人物设定与摄影排版方法,约 41 MB 素材。
|
|
4
4
|
|
|
5
|
-
支持 Codex、SealSeek、WorkBuddy。需要 Node.js 22+、宿主命令执行和看图能力。生图统一通过必需的 `@petercjl/sealseek-media-cli`(0.6.1+)及其配套 `sealseek-media` Skill
|
|
5
|
+
支持 Codex、SealSeek、WorkBuddy。需要 Node.js 22+、宿主命令执行和看图能力。生图统一通过必需的 `@petercjl/sealseek-media-cli`(0.6.1+)及其配套 `sealseek-media` Skill 执行;每次业务任务先检查,缺失或不兼容时暂停整个任务,安装并复查通过后继续。有效 SealSeek 登录、网络及额度由使用者准备,包不附带账号或额度。宿主生图效果仍需分别实测。
|
|
6
6
|
|
|
7
7
|
先安装生图依赖,将提示词发送给 Agent:
|
|
8
8
|
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
|
|
29
29
|
> 请诊断并修复 cloud-hug-style-transfer 的这次报错:粘贴报错内容。
|
|
30
30
|
|
|
31
|
-
安装、更新与检查由 Agent 执行包内 CLI。包的 `skill source --json` 提供规范来源;Agent 随后调用 `skill install --agent <当前宿主>`,支持 `--root` 指定实际技能目录。普通任务不联网检查或自动更新。显式更新使用 stable latest,备份旧包并同步已登记的受管 Skill
|
|
31
|
+
安装、更新与检查由 Agent 执行包内 CLI。包的 `skill source --json` 提供规范来源;Agent 随后调用 `skill install --agent <当前宿主>`,支持 `--root` 指定实际技能目录。普通任务不联网检查或自动更新。显式更新使用 stable latest,备份旧包并同步已登记的受管 Skill;npm 已是最新版时仍修复旧 Skill 与兼容元数据,返回安装位置、来源、校验、备份和耗时。包升级失败时恢复旧包;离线保留当前安装。已有独立安装或本地修改将停止覆盖并报告。源码或上层工具管理的包由其拥有者更新。
|
|
32
32
|
|
|
33
33
|
兼容证据分别记录安装机制与生图效果。CI 覆盖 macOS、Windows、Linux 的包管理机制;宿主实际生成需使用各自账户独立验证。品牌与输入素材须具备相应使用权;公开 npm 分发不转让商标与素材的独立再分发权。
|
|
34
34
|
|
package/capabilities.json
CHANGED
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"nested_skills": [
|
|
25
25
|
"sealseek-media"
|
|
26
26
|
],
|
|
27
|
-
"generation": "Required
|
|
27
|
+
"generation": "Required for business planning and generation; maintenance is independent of media service dependencies.",
|
|
28
28
|
"host_capability_skills": {
|
|
29
29
|
"codex": [],
|
|
30
30
|
"sealseek": [],
|
|
@@ -70,5 +70,249 @@
|
|
|
70
70
|
"archive": "none during generation; explicit pair batch after each success",
|
|
71
71
|
"planner": "canvas row --input JSON_FILE --json",
|
|
72
72
|
"recovery": "same canvas/task/row IDs; inspect before replay"
|
|
73
|
+
},
|
|
74
|
+
"commandContracts": {
|
|
75
|
+
"version": {
|
|
76
|
+
"options": {
|
|
77
|
+
"--json": {
|
|
78
|
+
"type": "boolean",
|
|
79
|
+
"description": "Machine-readable JSON (also the default)."
|
|
80
|
+
},
|
|
81
|
+
"--help": {
|
|
82
|
+
"type": "boolean",
|
|
83
|
+
"description": "Read-only help for this command."
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
"sideEffects": "none"
|
|
87
|
+
},
|
|
88
|
+
"capabilities": {
|
|
89
|
+
"options": {
|
|
90
|
+
"--json": {
|
|
91
|
+
"type": "boolean",
|
|
92
|
+
"description": "Machine-readable JSON (also the default)."
|
|
93
|
+
},
|
|
94
|
+
"--help": {
|
|
95
|
+
"type": "boolean",
|
|
96
|
+
"description": "Read-only help for this command."
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
"sideEffects": "none"
|
|
100
|
+
},
|
|
101
|
+
"doctor": {
|
|
102
|
+
"options": {
|
|
103
|
+
"--json": {
|
|
104
|
+
"type": "boolean",
|
|
105
|
+
"description": "Machine-readable JSON (also the default)."
|
|
106
|
+
},
|
|
107
|
+
"--help": {
|
|
108
|
+
"type": "boolean",
|
|
109
|
+
"description": "Read-only help for this command."
|
|
110
|
+
},
|
|
111
|
+
"--agent": {
|
|
112
|
+
"type": "string",
|
|
113
|
+
"enum": [
|
|
114
|
+
"codex",
|
|
115
|
+
"sealseek",
|
|
116
|
+
"workbuddy"
|
|
117
|
+
],
|
|
118
|
+
"description": "Target host; defaults to codex."
|
|
119
|
+
},
|
|
120
|
+
"--root": {
|
|
121
|
+
"type": "string",
|
|
122
|
+
"description": "Skill parent directory; the CLI appends cloud-hug-style-transfer. Requires --agent on doctor and update."
|
|
123
|
+
}
|
|
124
|
+
},
|
|
125
|
+
"sideEffects": "none"
|
|
126
|
+
},
|
|
127
|
+
"skill source": {
|
|
128
|
+
"options": {
|
|
129
|
+
"--json": {
|
|
130
|
+
"type": "boolean",
|
|
131
|
+
"description": "Machine-readable JSON (also the default)."
|
|
132
|
+
},
|
|
133
|
+
"--help": {
|
|
134
|
+
"type": "boolean",
|
|
135
|
+
"description": "Read-only help for this command."
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
"sideEffects": "none"
|
|
139
|
+
},
|
|
140
|
+
"skill status": {
|
|
141
|
+
"options": {
|
|
142
|
+
"--json": {
|
|
143
|
+
"type": "boolean",
|
|
144
|
+
"description": "Machine-readable JSON (also the default)."
|
|
145
|
+
},
|
|
146
|
+
"--help": {
|
|
147
|
+
"type": "boolean",
|
|
148
|
+
"description": "Read-only help for this command."
|
|
149
|
+
},
|
|
150
|
+
"--agent": {
|
|
151
|
+
"type": "string",
|
|
152
|
+
"enum": [
|
|
153
|
+
"codex",
|
|
154
|
+
"sealseek",
|
|
155
|
+
"workbuddy"
|
|
156
|
+
],
|
|
157
|
+
"description": "Target host; defaults to codex."
|
|
158
|
+
},
|
|
159
|
+
"--root": {
|
|
160
|
+
"type": "string",
|
|
161
|
+
"description": "Skill parent directory; the CLI appends cloud-hug-style-transfer. Requires --agent on doctor and update."
|
|
162
|
+
}
|
|
163
|
+
},
|
|
164
|
+
"sideEffects": "none"
|
|
165
|
+
},
|
|
166
|
+
"skill install": {
|
|
167
|
+
"options": {
|
|
168
|
+
"--json": {
|
|
169
|
+
"type": "boolean",
|
|
170
|
+
"description": "Machine-readable JSON (also the default)."
|
|
171
|
+
},
|
|
172
|
+
"--help": {
|
|
173
|
+
"type": "boolean",
|
|
174
|
+
"description": "Read-only help for this command."
|
|
175
|
+
},
|
|
176
|
+
"--agent": {
|
|
177
|
+
"type": "string",
|
|
178
|
+
"enum": [
|
|
179
|
+
"codex",
|
|
180
|
+
"sealseek",
|
|
181
|
+
"workbuddy"
|
|
182
|
+
],
|
|
183
|
+
"description": "Target host; defaults to codex."
|
|
184
|
+
},
|
|
185
|
+
"--root": {
|
|
186
|
+
"type": "string",
|
|
187
|
+
"description": "Skill parent directory; the CLI appends cloud-hug-style-transfer. Requires --agent on doctor and update."
|
|
188
|
+
}
|
|
189
|
+
},
|
|
190
|
+
"sideEffects": "local-write"
|
|
191
|
+
},
|
|
192
|
+
"skill update": {
|
|
193
|
+
"options": {
|
|
194
|
+
"--json": {
|
|
195
|
+
"type": "boolean",
|
|
196
|
+
"description": "Machine-readable JSON (also the default)."
|
|
197
|
+
},
|
|
198
|
+
"--help": {
|
|
199
|
+
"type": "boolean",
|
|
200
|
+
"description": "Read-only help for this command."
|
|
201
|
+
},
|
|
202
|
+
"--agent": {
|
|
203
|
+
"type": "string",
|
|
204
|
+
"enum": [
|
|
205
|
+
"codex",
|
|
206
|
+
"sealseek",
|
|
207
|
+
"workbuddy"
|
|
208
|
+
],
|
|
209
|
+
"description": "Target host; defaults to codex."
|
|
210
|
+
},
|
|
211
|
+
"--root": {
|
|
212
|
+
"type": "string",
|
|
213
|
+
"description": "Skill parent directory; the CLI appends cloud-hug-style-transfer. Requires --agent on doctor and update."
|
|
214
|
+
}
|
|
215
|
+
},
|
|
216
|
+
"sideEffects": "local-write"
|
|
217
|
+
},
|
|
218
|
+
"update check": {
|
|
219
|
+
"options": {
|
|
220
|
+
"--json": {
|
|
221
|
+
"type": "boolean",
|
|
222
|
+
"description": "Machine-readable JSON (also the default)."
|
|
223
|
+
},
|
|
224
|
+
"--help": {
|
|
225
|
+
"type": "boolean",
|
|
226
|
+
"description": "Read-only help for this command."
|
|
227
|
+
},
|
|
228
|
+
"--agent": {
|
|
229
|
+
"type": "string",
|
|
230
|
+
"enum": [
|
|
231
|
+
"codex",
|
|
232
|
+
"sealseek",
|
|
233
|
+
"workbuddy"
|
|
234
|
+
],
|
|
235
|
+
"description": "Target host; defaults to codex."
|
|
236
|
+
},
|
|
237
|
+
"--root": {
|
|
238
|
+
"type": "string",
|
|
239
|
+
"description": "Skill parent directory; the CLI appends cloud-hug-style-transfer. Requires --agent on doctor and update."
|
|
240
|
+
}
|
|
241
|
+
},
|
|
242
|
+
"sideEffects": "none"
|
|
243
|
+
},
|
|
244
|
+
"update install": {
|
|
245
|
+
"options": {
|
|
246
|
+
"--json": {
|
|
247
|
+
"type": "boolean",
|
|
248
|
+
"description": "Machine-readable JSON (also the default)."
|
|
249
|
+
},
|
|
250
|
+
"--help": {
|
|
251
|
+
"type": "boolean",
|
|
252
|
+
"description": "Read-only help for this command."
|
|
253
|
+
},
|
|
254
|
+
"--agent": {
|
|
255
|
+
"type": "string",
|
|
256
|
+
"enum": [
|
|
257
|
+
"codex",
|
|
258
|
+
"sealseek",
|
|
259
|
+
"workbuddy"
|
|
260
|
+
],
|
|
261
|
+
"description": "Target host; defaults to codex."
|
|
262
|
+
},
|
|
263
|
+
"--root": {
|
|
264
|
+
"type": "string",
|
|
265
|
+
"description": "Skill parent directory; the CLI appends cloud-hug-style-transfer. Requires --agent on doctor and update."
|
|
266
|
+
},
|
|
267
|
+
"--yes": {
|
|
268
|
+
"type": "boolean",
|
|
269
|
+
"required": true,
|
|
270
|
+
"description": "Authorize package and managed Skill reconciliation."
|
|
271
|
+
}
|
|
272
|
+
},
|
|
273
|
+
"sideEffects": "package-and-skill-update"
|
|
274
|
+
},
|
|
275
|
+
"canvas row": {
|
|
276
|
+
"options": {
|
|
277
|
+
"--json": {
|
|
278
|
+
"type": "boolean",
|
|
279
|
+
"description": "Machine-readable JSON (also the default)."
|
|
280
|
+
},
|
|
281
|
+
"--help": {
|
|
282
|
+
"type": "boolean",
|
|
283
|
+
"description": "Read-only help for this command."
|
|
284
|
+
},
|
|
285
|
+
"--input": {
|
|
286
|
+
"type": "string",
|
|
287
|
+
"required": true,
|
|
288
|
+
"description": "Comparison input JSON file."
|
|
289
|
+
}
|
|
290
|
+
},
|
|
291
|
+
"sideEffects": "none"
|
|
292
|
+
}
|
|
293
|
+
},
|
|
294
|
+
"maintenance": {
|
|
295
|
+
"targetPrecedence": [
|
|
296
|
+
"explicit --root",
|
|
297
|
+
"host skills directory environment",
|
|
298
|
+
"Agent home/default"
|
|
299
|
+
],
|
|
300
|
+
"codexSkillsEnvironment": "CODEX_SKILLS_DIR",
|
|
301
|
+
"defaultUpdateScope": "registered and current-host managed targets; explicit --agent selects one target",
|
|
302
|
+
"receipt": [
|
|
303
|
+
"package",
|
|
304
|
+
"version",
|
|
305
|
+
"source",
|
|
306
|
+
"entry",
|
|
307
|
+
"owner",
|
|
308
|
+
"packageChanged",
|
|
309
|
+
"skills",
|
|
310
|
+
"verified",
|
|
311
|
+
"backup",
|
|
312
|
+
"warnings",
|
|
313
|
+
"timingsMs"
|
|
314
|
+
],
|
|
315
|
+
"sameVersion": "reconcile managed Skills and metadata; verified no-op when current",
|
|
316
|
+
"metadata": "preserve customization; remove known unsupported api product with backup; unknown invalid schema requires reconciliation"
|
|
73
317
|
}
|
|
74
318
|
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { root, fail } from './runtime.mjs';
|
|
4
|
+
export const manifest=JSON.parse(fs.readFileSync(path.join(root,'capabilities.json'),'utf8'));
|
|
5
|
+
export function parse(args) {
|
|
6
|
+
const tokens=[...args];
|
|
7
|
+
if(tokens[0]==='--version')tokens[0]='version';
|
|
8
|
+
if(tokens[0]==='help') {tokens.shift();tokens.push('--help');}
|
|
9
|
+
const words=[];while(tokens.length&&!tokens[0].startsWith('-'))words.push(tokens.shift());
|
|
10
|
+
const command=words.join(' '), contract=manifest.commandContracts[command];
|
|
11
|
+
if(!command&&(!tokens.length||tokens.every(x=>['--help','-h','--json'].includes(x))))return {command:'help',options:{}};
|
|
12
|
+
if(!contract)throw fail('INVALID_COMMAND','Unknown command; use --help.');
|
|
13
|
+
const options={};
|
|
14
|
+
while(tokens.length) {
|
|
15
|
+
let flag=tokens.shift();if(flag==='-h')flag='--help';
|
|
16
|
+
const spec=contract.options[flag];
|
|
17
|
+
if(!spec||flag in options)throw fail('INVALID_ARGUMENT',`Unknown or duplicate option ${flag}; use ${command} --help.`);
|
|
18
|
+
const value=spec.type==='boolean'?true:tokens.shift();
|
|
19
|
+
if(value===undefined || (spec.type==='string'&&value.startsWith('-')))throw fail('INVALID_ARGUMENT',`${flag} needs a value.`);
|
|
20
|
+
if(spec.enum&&!spec.enum.includes(value))throw fail('INVALID_AGENT',`Choose ${spec.enum.join(', ')}.`);
|
|
21
|
+
options[flag]=value;
|
|
22
|
+
}
|
|
23
|
+
if(!options['--help']) {
|
|
24
|
+
for(const [flag,spec]of Object.entries(contract.options))if(spec.required&&!options[flag])throw fail(flag==='--yes'?'PERMISSION_REQUIRED':'INVALID_ARGUMENT',`${command} requires ${flag}.`);
|
|
25
|
+
if(['doctor','update check','update install'].includes(command)&&options['--root']&&!options['--agent'])throw fail('INVALID_ARGUMENT','--root requires an explicit --agent for this command.');
|
|
26
|
+
}
|
|
27
|
+
return {command,options,contract};
|
|
28
|
+
}
|
package/npm/cli.mjs
CHANGED
|
@@ -2,44 +2,38 @@
|
|
|
2
2
|
import fs from 'node:fs';
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import { root, pkg, fail } from './runtime.mjs';
|
|
5
|
-
import { source,
|
|
6
|
-
import { checkUpdate, installUpdate } from './update.mjs';
|
|
5
|
+
import { source, resolveTarget, status, install, inventory, skillMetadata } from './skills.mjs';
|
|
6
|
+
import { checkUpdate, installUpdate, globalPrefix } from './update.mjs';
|
|
7
7
|
import { mediaDependency } from './media-dependency.mjs';
|
|
8
8
|
import { comparisonRow } from './canvas-layout.mjs';
|
|
9
|
-
|
|
10
|
-
const
|
|
9
|
+
import { parse, manifest } from './arguments.mjs';
|
|
10
|
+
const started=performance.now();
|
|
11
11
|
const out=value=>console.log(JSON.stringify(value,null,2));
|
|
12
12
|
try {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
}
|
|
19
|
-
else if(
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
}
|
|
28
|
-
} else if(args[0]==='doctor') {
|
|
29
|
-
const files=inventory(source), expected=JSON.parse(fs.readFileSync(path.join(root,'npm','integrity.json'),'utf8'));
|
|
13
|
+
const {command,options:o,contract}=parse(process.argv.slice(2));
|
|
14
|
+
const identity={package:pkg.name,version:pkg.version,source,entry:{node:process.execPath,cli:path.join(root,'npm/cli.mjs')},owner:globalPrefix()?'global-npm':'source-or-parent'};
|
|
15
|
+
if(command==='help')out({ok:true,...identity,commands:manifest.commandContracts});
|
|
16
|
+
else if(o['--help'])out({ok:true,command,...contract});
|
|
17
|
+
else if(command==='version')out({ok:true,name:pkg.name,...identity});
|
|
18
|
+
else if(command==='capabilities')out({...manifest,...identity});
|
|
19
|
+
else if(command==='canvas row')out(comparisonRow(JSON.parse(fs.readFileSync(o['--input'],'utf8'))));
|
|
20
|
+
else if(command==='skill source')out({ok:true,...identity});
|
|
21
|
+
else if(command.startsWith('skill ')) {
|
|
22
|
+
const resolution=resolveTarget(o['--agent']||'codex',o['--root']);
|
|
23
|
+
const result=command==='skill status'?{ok:true,...status(resolution.target),record:undefined}:install(resolution.target);
|
|
24
|
+
out({...identity,...result,resolution});
|
|
25
|
+
} else if(command==='doctor') {
|
|
26
|
+
const files=inventory(source),expected=JSON.parse(fs.readFileSync(path.join(root,'npm/integrity.json'),'utf8'));
|
|
30
27
|
const problems=Object.entries(expected).filter(([name,hash])=>files[name]!==hash).map(([name])=>name);
|
|
31
|
-
const
|
|
32
|
-
const
|
|
33
|
-
const result={ok:Number(process.versions.node.split('.')[0])>=22&&problems.length===0&&media.ok,package:pkg.name,version:pkg.version,node:process.versions.node,source,files:Object.keys(files).length,integrity:{ok:problems.length===0,problems},installationReady:problems.length===0,dependencies:{media},hostCapabilityDependencies:capabilities.requirements.host_capability_skills,generation:{provider:'@petercjl/sealseek-media-cli',state:media.ok?'requires-live-preflight':'paused',runtimeTested:false,requiredFeatures:['image-inspection','multiple-reference-edit','local-reference-input','viewable-output']}};
|
|
28
|
+
const media=mediaDependency();const metadata=skillMetadata(source);
|
|
29
|
+
const result={ok:Number(process.versions.node.split('.')[0])>=22&&!problems.length&&metadata.valid&&media.ok,...identity,node:process.versions.node,files:Object.keys(files).length,integrity:{ok:!problems.length,problems},metadata:{valid:metadata.valid},installationReady:!problems.length&&metadata.valid,dependencies:{media},hostCapabilityDependencies:manifest.requirements.host_capability_skills,generation:{provider:'@petercjl/sealseek-media-cli',state:media.ok?'requires-live-preflight':'paused',runtimeTested:false,requiredFeatures:['image-inspection','multiple-reference-edit','local-reference-input','viewable-output']}};
|
|
34
30
|
if(!media.ok){result.code=media.code;result.action='pause';result.installPrompt=media.installPrompt;}
|
|
35
|
-
if(
|
|
36
|
-
out(result);if(!result.ok)process.exitCode=1;
|
|
37
|
-
} else if(
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
if(
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
else throw fail('INVALID_COMMAND','Unknown command; use --help.');
|
|
45
|
-
} catch(e){out({ok:false,code:e.code||'COMMAND_FAILED',message:e.message});process.exitCode=1;}
|
|
31
|
+
if(o['--agent']){result.resolution=resolveTarget(o['--agent'],o['--root']);result.installation={...status(result.resolution.target),record:undefined};if(!result.installation.current){result.ok=false;result.code||='SKILL_RECONCILIATION_REQUIRED';}}
|
|
32
|
+
out({...result,timingsMs:{total:performance.now()-started}});if(!result.ok)process.exitCode=1;
|
|
33
|
+
} else if(command.startsWith('update ')) {
|
|
34
|
+
const resolution=o['--agent']?resolveTarget(o['--agent'],o['--root']):undefined;
|
|
35
|
+
const registryStarted=performance.now();const check=await checkUpdate();const registryMs=performance.now()-registryStarted;
|
|
36
|
+
if(command==='update check'){out({...check,...identity,...(resolution?{resolution,installation:{...status(resolution.target),record:undefined}}:{}),timingsMs:{total:performance.now()-started}});if(!check.ok)process.exitCode=1;}
|
|
37
|
+
else {if(!check.ok)throw fail(check.code,'Registry unavailable; installed version retained.');const result=installUpdate(check,{resolution});out({...result,timingsMs:{...result.timingsMs,registry:registryMs,total:performance.now()-started}});}
|
|
38
|
+
}
|
|
39
|
+
} catch(e){out({ok:false,code:e.code||'COMMAND_FAILED',message:e.message,...(e.causeCode?{causeCode:e.causeCode}:{}),...(e.backup?{backup:e.backup}:{}),...(e.details?{details:e.details}:{}),timingsMs:{total:performance.now()-started}});process.exitCode=1;}
|
package/npm/integrity.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
|
-
"SKILL.md": "
|
|
2
|
+
"SKILL.md": "98df8d4271e525c687a1f0b3e877345bd42f3ca537515c0f84a9c0d58b17612b",
|
|
3
3
|
"adapters/codex.json": "bea8d59e6e0dafae7439693b33356825023516a6f52be02a64c976d7ce47ce76",
|
|
4
4
|
"adapters/sealseek.json": "04ef053762fd4cfc2309573ec87425afad14b2df85a1ea8ef0aa06d98fee1aee",
|
|
5
5
|
"adapters/workbuddy.json": "cd0a1d8d5b9fcebc5a709b8c7523911f41973adb95f71af2c0f644473a43a6b4",
|
|
6
|
-
"agents/openai.yaml": "
|
|
6
|
+
"agents/openai.yaml": "d8ebec24c4e3034f4b45aa052b9468ab35790ec7fd93febcfde512c746d2d1d1",
|
|
7
7
|
"assets/approved/all-colors-user-finish.webp": "539c77de8ec0dd46a29793befecf813e97ce6ae66f7cbe69486846383b2ae936",
|
|
8
8
|
"assets/approved/brand-kv-user-finish-20261012.png": "cb09198481e779444696864b265c689f467207bf7de9610f7adc2b850f0be7b4",
|
|
9
9
|
"assets/approved/detail-final-20261016/01.jpg": "ecb481a422b3eadb0050b8c1080a1781e3fbd50ce4479f92e9f4a8beffd91187",
|
|
@@ -62,6 +62,7 @@
|
|
|
62
62
|
"references/cases.md": "9d0d2d3d210e367411d5a291fc78ef6c9c733afd79c9da76451c580fcbcd4d3e",
|
|
63
63
|
"references/detail-final-20261016.md": "d9311413420db743466bbecfe98c31b9753eeead905472d69839afec9578c557",
|
|
64
64
|
"references/kv-layout-case-20261012.md": "845b287cfc57912aabedc48e558ca661cf86bf136304ea841030205a806ef06f",
|
|
65
|
+
"references/maintenance.md": "ccaa22cbe537885c7936d76b9091ef681491fd75d3791f6dbcf803d2337cee8e",
|
|
65
66
|
"references/model-generation.json": "21daa2c3bf7d2000c7ddf52ab0b980cb7ee95d6c9d345602dc59ecbc128ec147",
|
|
66
67
|
"references/model.md": "c4da688e22e2ada3f251fe0dc87effcaf5cb6ed6176f9d9c20a9661414bffab5",
|
|
67
68
|
"references/page-patterns.md": "bdd6756e303c95e432d0239be27ec5af1faf75abf71594917f2e11467255a1b4",
|
package/npm/metadata.mjs
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { parseDocument } from 'yaml';
|
|
2
|
+
import { fail } from './runtime.mjs';
|
|
3
|
+
const allowed=new Set(['chatgpt','codex','atlas','CHATGPT','CODEX','ATLAS']);
|
|
4
|
+
export function metadataPlan(text) {
|
|
5
|
+
const doc=parseDocument(text,{uniqueKeys:true});
|
|
6
|
+
if(doc.errors.length)throw fail('SKILL_METADATA_INVALID','Invalid agents/openai.yaml; preserve and repair the YAML before updating.');
|
|
7
|
+
const value=doc.toJS();
|
|
8
|
+
if(!value||typeof value!=='object'||Array.isArray(value))throw fail('SKILL_METADATA_INVALID','Skill metadata must be a mapping.');
|
|
9
|
+
if(value.interface!==undefined&&(!value.interface||typeof value.interface!=='object'||Array.isArray(value.interface)||Object.values(value.interface).some(v=>typeof v!=='string')))throw fail('SKILL_METADATA_INVALID','Skill interface values must be strings.');
|
|
10
|
+
if(value.policy!==undefined&&(!value.policy||typeof value.policy!=='object'||Array.isArray(value.policy)))throw fail('SKILL_METADATA_INVALID','Skill policy must be a mapping.');
|
|
11
|
+
const policy=value.policy;
|
|
12
|
+
if(policy?.allow_implicit_invocation!==undefined&&typeof policy.allow_implicit_invocation!=='boolean')throw fail('SKILL_METADATA_INVALID','allow_implicit_invocation must be boolean.');
|
|
13
|
+
const products=policy?.products;
|
|
14
|
+
if(products!==undefined&&(!Array.isArray(products)||products.some(p=>!allowed.has(p)&&p!=='api')))throw fail('SKILL_METADATA_INVALID','Unsupported policy.products; preserve and resolve the custom policy before updating.');
|
|
15
|
+
const changed=products?.includes('api')||false;
|
|
16
|
+
if(changed){const valid=products.filter(p=>p!=='api');if(!valid.length)throw fail('SKILL_METADATA_INVALID','Removing api would leave an empty custom product policy.');doc.setIn(['policy','products'],valid);}
|
|
17
|
+
return {valid:!changed,changed,text:changed?doc.toString():text,warnings:changed?['Removed unsupported legacy api product; custom interface and other policy fields preserved.']:[]};
|
|
18
|
+
}
|
package/npm/pack.mjs
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { pkg, fail } from './runtime.mjs';
|
|
3
|
+
export function packReceipt(text) {
|
|
4
|
+
let value;try{value=JSON.parse(text);}catch{throw fail('UPDATE_BACKUP_FAILED','npm pack did not return valid JSON.');}
|
|
5
|
+
const receipt=Array.isArray(value)&&value.length===1?value[0]:value?.[pkg.name];
|
|
6
|
+
if(!receipt||typeof receipt.filename!=='string'||!receipt.filename.endsWith('.tgz')||receipt.filename.includes('\\')||path.basename(receipt.filename)!==receipt.filename||(receipt.name&&receipt.name!==pkg.name))throw fail('UPDATE_BACKUP_FAILED','Invalid npm pack receipt.');
|
|
7
|
+
return receipt;
|
|
8
|
+
}
|
package/npm/skills.mjs
CHANGED
|
@@ -2,6 +2,7 @@ import fs from 'node:fs';
|
|
|
2
2
|
import os from 'node:os';
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import crypto from 'node:crypto';
|
|
5
|
+
import { metadataPlan } from './metadata.mjs';
|
|
5
6
|
import { stateRoot } from './update.mjs';
|
|
6
7
|
import { root, pkg, fail } from './runtime.mjs';
|
|
7
8
|
|
|
@@ -23,14 +24,19 @@ export function inventory(dir) {
|
|
|
23
24
|
walk(dir);
|
|
24
25
|
return result;
|
|
25
26
|
}
|
|
26
|
-
export function
|
|
27
|
+
export function resolveTarget(agent='codex', targetRoot) {
|
|
27
28
|
if (!['codex', 'sealseek', 'workbuddy'].includes(agent)) throw fail('INVALID_AGENT', 'Choose --agent codex, sealseek or workbuddy.');
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
29
|
+
const envName={codex:'CODEX_SKILLS_DIR',sealseek:'SEALSEEK_SKILLS_DIR',workbuddy:'WORKBUDDY_SKILLS_DIR'}[agent];
|
|
30
|
+
const homeBase=agent==='codex' ? path.join(process.env.CODEX_HOME || path.join(os.homedir(),'.codex'),'skills') : agent==='sealseek' ? path.join(os.homedir(),'.sealseek','workspaces','default','skills') : path.join(os.homedir(),'.workbuddy','skills');
|
|
31
|
+
const candidates=[targetRoot&&{source:'--root',root:targetRoot},process.env[envName]&&{source:envName,root:process.env[envName]},{source:agent==='codex'&&process.env.CODEX_HOME?'CODEX_HOME':'agent-default',root:homeBase}].filter(Boolean).map(v=>({...v,root:path.resolve(v.root)}));
|
|
32
|
+
const selected=candidates[0];
|
|
33
|
+
return {agent,target:path.join(selected.root,'cloud-hug-style-transfer'),root:selected.root,resolvedFrom:selected.source,candidates,warnings:[...new Set(candidates.filter(c=>c.root!==selected.root).map(c=>`${selected.source} takes precedence over ${c.source}.`))]};
|
|
34
|
+
}
|
|
35
|
+
export const targetPath=(agent,targetRoot)=>resolveTarget(agent,targetRoot).target;
|
|
36
|
+
export function skillMetadata(target) {
|
|
37
|
+
const file=path.join(target,metadata);
|
|
38
|
+
if(!exists(file))return {valid:false,changed:false,missing:true,warnings:['Skill UI metadata is missing.']};
|
|
39
|
+
return metadataPlan(fs.readFileSync(file,'utf8'));
|
|
34
40
|
}
|
|
35
41
|
export function status(target) {
|
|
36
42
|
const st = exists(target);
|
|
@@ -43,18 +49,21 @@ export function status(target) {
|
|
|
43
49
|
const files = inventory(target);
|
|
44
50
|
const edited = Object.entries(record.files).some(([file, hash]) => file !== metadata && files[file] !== hash);
|
|
45
51
|
const expected = inventory(source);
|
|
46
|
-
const
|
|
47
|
-
|
|
52
|
+
const ui=skillMetadata(target);
|
|
53
|
+
const current = record.version === pkg.version && ui.valid && !edited && Object.entries(expected).every(([file, hash]) => file === metadata || files[file] === hash);
|
|
54
|
+
return { installed: true, managed: true, current, edited, target, version: record.version, metadata:{valid:ui.valid,migrationRequired:ui.changed,warnings:ui.warnings}, record };
|
|
48
55
|
}
|
|
49
56
|
export function install(target) {
|
|
50
|
-
const
|
|
57
|
+
const started=performance.now();
|
|
58
|
+
let state = status(target);
|
|
51
59
|
if (state.installed && !state.managed) throw fail('SKILL_UNMANAGED', 'An existing user-owned Skill occupies this target; preserve it and choose a new root or explicitly migrate it.');
|
|
52
60
|
if (state.edited) throw fail('SKILL_EDITED', 'Managed Skill files contain local edits; preserve and reconcile those edits before updating.');
|
|
53
61
|
const registry = path.join(stateRoot(), 'skill-targets');
|
|
54
62
|
fs.mkdirSync(registry, { recursive: true });
|
|
55
63
|
const registration = path.join(registry, crypto.createHash('sha256').update(target).digest('hex') + '.json');
|
|
56
64
|
if (!exists(registration)) fs.writeFileSync(registration, JSON.stringify({ target }), { flag: 'wx', mode: 0o600 });
|
|
57
|
-
|
|
65
|
+
const receipt={package:pkg.name,source,owner:'package-managed',verified:true};
|
|
66
|
+
if (state.current && state.version === pkg.version) return { ...state, record: undefined, ...receipt, ok: true, changed: false, timingsMs:{total:performance.now()-started} };
|
|
58
67
|
const expected = inventory(source);
|
|
59
68
|
for (const file of Object.keys(expected)) {
|
|
60
69
|
if (state.installed && exists(path.join(target, file)) && !(file in state.record.files) && file !== metadata) throw fail('SKILL_UNMANAGED_FILE', 'A new bundled file would overwrite a user-owned file.');
|
|
@@ -65,6 +74,11 @@ export function install(target) {
|
|
|
65
74
|
try { lockfd = fs.openSync(lock, 'wx', 0o600); } catch (e) { if (e.code === 'EEXIST') throw fail('SKILL_BUSY', 'Another Skill installation holds the lock.'); throw e; }
|
|
66
75
|
let backup;
|
|
67
76
|
try {
|
|
77
|
+
state=status(target);
|
|
78
|
+
if(state.installed&&!state.managed)throw fail('SKILL_UNMANAGED','Target ownership changed while waiting for the lock.');
|
|
79
|
+
if(state.edited)throw fail('SKILL_EDITED','Target changed while waiting for the lock.');
|
|
80
|
+
for(const file of Object.keys(expected))if(state.installed&&exists(path.join(target,file))&&!(file in state.record.files)&&file!==metadata)throw fail('SKILL_UNMANAGED_FILE','Target file ownership changed before the lock.');
|
|
81
|
+
const ui=state.installed?skillMetadata(target):null;
|
|
68
82
|
if (state.installed) {
|
|
69
83
|
backup = path.join(stateRoot(), 'skill-backups', crypto.randomUUID());
|
|
70
84
|
fs.mkdirSync(path.dirname(backup), { recursive: true });
|
|
@@ -72,7 +86,7 @@ export function install(target) {
|
|
|
72
86
|
} else fs.mkdirSync(target);
|
|
73
87
|
// In-place updates support hosts holding a directory handle open. Backup is recoverable.
|
|
74
88
|
for (const file of Object.keys(expected)) {
|
|
75
|
-
if (file === metadata && exists(path.join(target, file))) continue;
|
|
89
|
+
if (file === metadata && exists(path.join(target, file))) { if(ui.changed)fs.writeFileSync(path.join(target,file),ui.text); continue; }
|
|
76
90
|
fs.mkdirSync(path.dirname(path.join(target, file)), { recursive: true });
|
|
77
91
|
fs.copyFileSync(path.join(source, file), path.join(target, file));
|
|
78
92
|
}
|
|
@@ -81,9 +95,10 @@ export function install(target) {
|
|
|
81
95
|
}
|
|
82
96
|
const actual = inventory(target);
|
|
83
97
|
if (Object.entries(expected).some(([file, hash]) => file !== metadata && actual[file] !== hash)) throw fail('SKILL_VERIFY_FAILED', 'Installed Skill hashes differ from the package.');
|
|
98
|
+
if(!skillMetadata(target).valid)throw fail('SKILL_VERIFY_FAILED','Skill UI metadata validation failed.');
|
|
84
99
|
fs.writeFileSync(path.join(target, marker), JSON.stringify({ package: pkg.name, version: pkg.version, files: expected }, null, 2));
|
|
85
|
-
return { ok: true, installed: true, managed: true, current: true, changed: true, target, version: pkg.version, backup: backup || null };
|
|
100
|
+
return { ...receipt, metadata:{valid:true,migrated:ui?.changed||false}, warnings:ui?.warnings||[], timingsMs:{total:performance.now()-started}, ok: true, installed: true, managed: true, current: true, changed: true, target, version: pkg.version, backup: backup || null };
|
|
86
101
|
} catch (e) {
|
|
87
|
-
throw fail('SKILL_INSTALL_FAILED', `Skill installation failed; ${backup ? 'restore from ' + backup : 'inspect the partial target at ' + target}.`);
|
|
102
|
+
throw Object.assign(fail('SKILL_INSTALL_FAILED', `Skill installation failed; ${backup ? 'restore from ' + backup : 'inspect the partial target at ' + target}.`),{causeCode:e.code,backup:backup||null,target});
|
|
88
103
|
} finally { fs.closeSync(lockfd); fs.unlinkSync(lock); }
|
|
89
104
|
}
|
package/npm/update.mjs
CHANGED
|
@@ -3,6 +3,8 @@ import os from 'node:os';
|
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import crypto from 'node:crypto';
|
|
5
5
|
import { spawnSync } from 'node:child_process';
|
|
6
|
+
import { packReceipt } from './pack.mjs';
|
|
7
|
+
import { source, resolveTarget, status } from './skills.mjs';
|
|
6
8
|
import { root, pkg, fail } from './runtime.mjs';
|
|
7
9
|
|
|
8
10
|
export const stateRoot = () => process.env.CLOUD_HUG_STATE_DIR || (process.platform === 'win32' ? path.join(process.env.LOCALAPPDATA || os.homedir(), 'cloud-hug-style-transfer') : path.join(os.homedir(), '.local', 'state', 'cloud-hug-style-transfer'));
|
|
@@ -40,45 +42,58 @@ function npm(args) {
|
|
|
40
42
|
return r.stdout;
|
|
41
43
|
}
|
|
42
44
|
export function installUpdate(check, services={}) {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
const state=stateRoot();
|
|
45
|
+
if(!check.ok)throw fail(check.code||'REGISTRY_UNAVAILABLE','Registry check failed; installation retained.');
|
|
46
|
+
const started=performance.now(), prefix=services.prefix || globalPrefix();
|
|
47
|
+
const state=stateRoot();fs.mkdirSync(state,{recursive:true});
|
|
46
48
|
const lock=path.join(state,'update.lock');
|
|
47
|
-
try {
|
|
48
|
-
const run=services.npm
|
|
49
|
-
const
|
|
50
|
-
const
|
|
49
|
+
try {fs.mkdirSync(lock);}catch{throw fail('UPDATE_BUSY','Another update is running. Retry after it finishes.');}
|
|
50
|
+
const run=services.npm||npm, spawn=services.spawn||spawnSync;
|
|
51
|
+
const entry=path.join(root,'npm','cli.mjs'), targets=[], skills=[];
|
|
52
|
+
const sync=target=>{
|
|
53
|
+
const r=spawn(process.execPath,[entry,'skill','update','--agent',target.agent||'codex','--root',path.dirname(target.target),'--json'],{encoding:'utf8',timeout:30000,env:{...process.env,CLOUD_HUG_AUTO_UPDATE:'0'}});
|
|
54
|
+
let receipt;try{receipt=JSON.parse(r.stdout);}catch{/* malformed receipt is a failure */}
|
|
55
|
+
if(r.status!==0||!receipt?.ok||!receipt.current||!receipt.verified)throw Object.assign(fail('SKILL_SYNC_FAILED','Managed Skill reconciliation failed.'),{details:{target:target.target,result:receipt||null}});
|
|
56
|
+
return {...receipt,resolution:target};
|
|
57
|
+
};
|
|
58
|
+
let archivePath,mutated=false,version;
|
|
51
59
|
try {
|
|
52
|
-
// Recheck the live package under the lock; another process may have updated it.
|
|
53
60
|
const live=JSON.parse(fs.readFileSync(path.join(root,'package.json'),'utf8'));
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
61
|
+
const packageChanged=newer(check.available,live.version);
|
|
62
|
+
if(packageChanged&&!prefix)throw fail('UPDATE_OWNER_REQUIRED','This installation is managed by its source checkout or parent package.');
|
|
63
|
+
if(services.resolution)targets.push(services.resolution);
|
|
64
|
+
else {
|
|
65
|
+
const known=[resolveTarget('codex'),resolveTarget('sealseek'),resolveTarget('workbuddy')];
|
|
66
|
+
const registered=path.join(state,'skill-targets');
|
|
67
|
+
for(const file of fs.existsSync(registered)?fs.readdirSync(registered):[]) {
|
|
68
|
+
try{const r=JSON.parse(fs.readFileSync(path.join(registered,file),'utf8'));if(typeof r.target==='string'&&path.isAbsolute(r.target)&&path.basename(r.target)==='cloud-hug-style-transfer')known.push({target:r.target,resolvedFrom:'managed-registration'});}catch{/* invalid registration is ignored */}
|
|
69
|
+
}
|
|
70
|
+
for(const r of known)if(!targets.some(t=>t.target===r.target)&&status(r.target).managed)targets.push(r);
|
|
64
71
|
}
|
|
65
|
-
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
-
|
|
72
|
+
// Ownership, local edits and metadata conflicts are checked before replacing the package.
|
|
73
|
+
for(const t of targets){const s=status(t.target);if(s.installed&&!s.managed)throw fail('SKILL_UNMANAGED','Selected Skill is user-owned.');if(s.edited)throw fail('SKILL_EDITED','Managed Skill contains local edits; reconcile before updating.');}
|
|
74
|
+
const preflightMs=performance.now()-started;
|
|
75
|
+
if(packageChanged) {
|
|
76
|
+
const backup=path.join(state,'package-backups',crypto.randomUUID());fs.mkdirSync(backup,{recursive:true});
|
|
77
|
+
const archive=packReceipt(run(['pack',root,'--ignore-scripts','--pack-destination',backup,'--json']));
|
|
78
|
+
if(!archive?.filename||path.basename(archive.filename)!==archive.filename)throw fail('UPDATE_BACKUP_FAILED','Invalid package backup receipt.');
|
|
79
|
+
archivePath=path.join(backup,archive.filename);
|
|
80
|
+
if(!fs.statSync(archivePath).size)throw fail('UPDATE_BACKUP_FAILED','Package backup is empty.');
|
|
69
81
|
mutated=true;
|
|
70
82
|
run(['install','--global','--prefix',prefix,'--prefer-online','--ignore-scripts','--no-audit','--no-fund',`${pkg.name}@${check.available}`]);
|
|
71
|
-
const version=JSON.parse(fs.readFileSync(path.join(root,'package.json'),'utf8')).version;
|
|
72
|
-
if(version!==check.available) throw fail('UPDATE_VERIFY_FAILED','Installed package version mismatch.');
|
|
73
|
-
for(const target of targets) if(sync(target).status!==0) throw fail('SKILL_SYNC_FAILED','A managed Skill needs reconciliation.');
|
|
74
|
-
return {ok:true,changed:true,from:pkg.version,version,backup:path.join(backup,archive.filename)};
|
|
75
|
-
} catch(e) {
|
|
76
|
-
if(mutated) {
|
|
77
|
-
try { run(['install','--global','--prefix',prefix,'--ignore-scripts',path.join(backup,archive.filename)]); }
|
|
78
|
-
catch { throw fail('ROLLBACK_REQUIRED','Automatic recovery failed; restore the package archive before running commands.'); }
|
|
79
|
-
for(const target of targets) if(sync(target).status!==0) throw fail('ROLLBACK_SYNC_REQUIRED','Package restored; reconcile edited Skill files before updating.');
|
|
80
|
-
}
|
|
81
|
-
throw e;
|
|
82
83
|
}
|
|
83
|
-
|
|
84
|
+
version=JSON.parse(fs.readFileSync(path.join(root,'package.json'),'utf8')).version;
|
|
85
|
+
if(version!==(packageChanged?check.available:live.version))throw fail('UPDATE_VERIFY_FAILED','Installed package version mismatch.');
|
|
86
|
+
const packageMs=performance.now()-started-preflightMs;
|
|
87
|
+
for(const t of targets)skills.push(sync(t));
|
|
88
|
+
if(skills.some(r=>r.version!==version))throw fail('SKILL_VERIFY_FAILED','Package and Skill versions differ.');
|
|
89
|
+
return {ok:true,package:pkg.name,source,entry:{node:process.execPath,cli:entry},owner:prefix?'global-npm':'source-or-parent',from:live.version,version,packageChanged,changed:packageChanged||skills.some(r=>r.changed),skills,verified:true,backup:archivePath||null,warnings:targets.length?[]:['No managed Skill target discovered; use an explicit --agent to install one.'],timingsMs:{preflight:preflightMs,package:packageMs,skills:performance.now()-started-preflightMs-packageMs,total:performance.now()-started}};
|
|
90
|
+
} catch(e) {
|
|
91
|
+
if(mutated) {
|
|
92
|
+
try{run(['install','--global','--prefix',prefix,'--ignore-scripts',archivePath]);const restored=JSON.parse(fs.readFileSync(path.join(root,'package.json'),'utf8')).version;if(restored!==pkg.version)throw Error('Rollback version mismatch');}
|
|
93
|
+
catch{throw Object.assign(fail('ROLLBACK_REQUIRED','Restore the package archive before continuing.'),{backup:archivePath});}
|
|
94
|
+
for(const t of targets)try{sync(t);}catch{throw Object.assign(fail('ROLLBACK_SYNC_REQUIRED','Package restored; restore affected Skill backups or reconcile local edits.'),{backup:archivePath,details:{skills,cause:e.details||e.message}});}
|
|
95
|
+
}
|
|
96
|
+
if(archivePath)e.backup=archivePath;
|
|
97
|
+
throw e;
|
|
98
|
+
} finally {fs.rmdirSync(lock);}
|
|
84
99
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@petercjl/cloud-hug-style-transfer",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "抱抱云朵社品牌风格转换 Skill,支持 Codex、SealSeek 与 WorkBuddy",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
},
|
|
19
19
|
"scripts": {
|
|
20
20
|
"test": "node --test test/*.test.mjs",
|
|
21
|
-
"check": "node --check npm/cli.mjs && node --check npm/skills.mjs && node --check npm/update.mjs",
|
|
21
|
+
"check": "node --check npm/cli.mjs && node --check npm/skills.mjs && node --check npm/update.mjs && node --check npm/arguments.mjs && node --check npm/metadata.mjs && node --check npm/pack.mjs",
|
|
22
22
|
"prepack": "npm run check && npm test"
|
|
23
23
|
},
|
|
24
24
|
"publishConfig": {
|
|
@@ -28,5 +28,8 @@
|
|
|
28
28
|
"type": "git",
|
|
29
29
|
"url": "git+https://github.com/petercjl/cloud-hug-style-transfer.git"
|
|
30
30
|
},
|
|
31
|
-
"license": "UNLICENSED"
|
|
31
|
+
"license": "UNLICENSED",
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"yaml": "^2.9.1"
|
|
34
|
+
}
|
|
32
35
|
}
|
|
@@ -11,9 +11,13 @@ description: 独立把旧详情页、产品摄影、主KV或SKU转换为抱抱
|
|
|
11
11
|
|
|
12
12
|
输入是当前源页、商品资料和本次目标;输出是约定数量的独立成图、原图与成图逐行对照的无限画板及简短验收说明,或用户仅要求的规划。本 Skill 负责品牌方法、素材选择、提示词、版式和业务验收;`@petercjl/sealseek-media-cli` 负责生图服务、认证、参考图传输、任务恢复和结果下载;宿主负责命令执行、实际看图和交付。
|
|
13
13
|
|
|
14
|
+
### 维护入口:安装、更新和诊断
|
|
15
|
+
|
|
16
|
+
维护请求先执行本入口;业务规划与生图进入下面的必需依赖检查。维护只读取包合同与安装状态,按需加载 [维护说明](references/maintenance.md),无需加载品牌图片或生图服务。
|
|
17
|
+
|
|
14
18
|
### 入口:必需依赖检查
|
|
15
19
|
|
|
16
|
-
|
|
20
|
+
**每次业务任务先检查依赖,通过后才进入第 1 节;规划任务也遵守此入口。** 执行 `cloud-hug-style-transfer doctor --json`,核对 `dependencies.media.ok`。检查支持当前 npm 安装树、PATH 安装及显式配置的 `CLOUD_HUG_MEDIA_ROOT`;返回的 `dependencies.media.invocation` 是经过包身份核验的 CLI 调用入口,使用宿主当前 Node 运行时,可用于 Agent 管理的运行时或套件组件。
|
|
17
21
|
|
|
18
22
|
未检测到 `@petercjl/sealseek-media-cli` 时返回 `DEPENDENCY_MISSING` 并**暂停整个任务**,保留输入和进度,给出最简安装提示词:“请安装 npm 包 @petercjl/sealseek-media-cli。”等待安装并重新检查通过后,从本入口恢复。版本低于 0.6.1、CLI 无法执行、规范 Skill 缺失或合同不兼容同样暂停,按诊断修复后复查。不得以宿主内置生图、其他提供商或继续规划代替依赖通过;本入口不自动安装软件或提交生成。
|
|
19
23
|
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# 安装与维护合同
|
|
2
|
+
|
|
3
|
+
1. 通过当前 CLI 的 `capabilities --json` 获取参数合同;用 `skill source --json` 定位规范 Skill。首次安装执行 `skill install --agent 当前宿主 --json`。
|
|
4
|
+
2. 显式更新执行 `update install --yes --json`,在默认范围核对已登记和当前宿主约定位置的受管 Skill;仅更新一个宿主时传 `--agent`。npm 已最新时仍同步旧 Skill 与可迁移元数据。源码或上层工具拥有的包由其拥有者升级;当前版本的 Skill 同步仍可执行。
|
|
5
|
+
3. 需要指定位置时,`--root` 是技能父目录,CLI 自动附加本 Skill 目录名;`doctor` 与 `update` 的 `--root` 同时要求 `--agent`。Codex 优先级为显式 root、`CODEX_SKILLS_DIR`、`CODEX_HOME/skills`、平台默认;其他宿主见实时合同及回执。读取 resolution 核对目标与来源。
|
|
6
|
+
4. 检查回执 `verified`、`packageChanged`、各 `skills` 的 `current/version/target` 和备份。完全当前即 verified no-op。未知参数报错后读取该命令的 `--help --json`;避免猜其他工具的选项。
|
|
7
|
+
5. 本地编辑或非受管目录保留原文件并报告。失败时保留回执中的 backup;先检查包版本与受管状态,再按错误恢复,避免重复升级。元数据只迁移已知不受支持的字段值,自定义展示字段保留。
|
|
8
|
+
|
|
9
|
+
`doctor --json` 同时报告安装完整性与生图依赖;媒体依赖缺失不阻止独立的 `skill` 或 `update` 维护操作。普通业务任务不自动更新。
|