@petercjl/cloud-hug-style-transfer 0.4.0 → 0.5.1

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/npm/cli.mjs CHANGED
@@ -1,39 +1,45 @@
1
1
  #!/usr/bin/env node
2
2
  import fs from 'node:fs';
3
3
  import path from 'node:path';
4
- import { root, pkg, fail } from './runtime.mjs';
5
- import { source, resolveTarget, status, install, inventory, skillMetadata } from './skills.mjs';
6
- import { checkUpdate, installUpdate, globalPrefix } from './update.mjs';
7
- import { mediaDependency } from './media-dependency.mjs';
8
- import { comparisonRow } from './canvas-layout.mjs';
9
- import { parse, manifest } from './arguments.mjs';
10
- const started=performance.now();
11
- const out=value=>console.log(JSON.stringify(value,null,2));
12
- try {
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'));
27
- const problems=Object.entries(expected).filter(([name,hash])=>files[name]!==hash).map(([name])=>name);
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']}};
30
- if(!media.ok){result.code=media.code;result.action='pause';result.installPrompt=media.installPrompt;}
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}});}
4
+ import {spawnSync} from 'node:child_process';
5
+ let lifecycle;try{lifecycle=await import('../lifecycle/engine.mjs');}catch{console.log(JSON.stringify({ok:false,code:'LIFECYCLE_DEPENDENCY_MISSING',message:'Install the owning npm package with its required dependencies before continuing.'}));process.exit(1);}
6
+ const {dispatch,automatic,resolveTarget,status,root,pkg,config,installationLifecycle}=lifecycle;
7
+ const args=process.argv.slice(2);
8
+ if(!await dispatch(args)) {
9
+ if(args[0]==='version'||args[0]==='--version'){if(args.slice(1).some(x=>x!=='--json')||args.filter(x=>x==='--json').length>1){console.log(JSON.stringify({ok:false,code:'INVALID_ARGUMENT',message:'version accepts only one --json flag.'}));process.exitCode=1;}else console.log(JSON.stringify({ok:true,name:pkg.name,version:pkg.version,entry:process.argv[1]}));}
10
+ else {
11
+ let target;
12
+ try {
13
+ const declaration=JSON.parse(fs.readFileSync(path.join(root,'capabilities.json'),'utf8'));
14
+ const doctorRoot=args[0]==='doctor'&&declaration.commandContracts?.doctor?.options?.['--root'];
15
+ const binding={},clean=[];
16
+ for(let i=0;i<args.length;i++){
17
+ const key=args[i];if(!['--agent','--skill-path',...(doctorRoot?['--root']:[])].includes(key)){clean.push(key);continue;}
18
+ const field=key==='--agent'?'agent':key==='--root'?'root':'skill-path';if(field in binding||!args[i+1]||args[i+1].startsWith('--'))throw Object.assign(Error('Duplicate or missing target binding'),{code:'INVALID_ARGUMENT'});binding[field]=args[++i];
19
+ }
20
+ if(Object.keys(binding).length)target=resolveTarget(binding);
21
+ args.splice(0,args.length,...clean);process.argv.splice(2,process.argv.length-2,...clean);
22
+
23
+ const marker=path.join(path.dirname(root),'.agent-package.json');
24
+ if(!target&&path.basename(root)==='.runtime'&&fs.existsSync(marker)&&JSON.parse(fs.readFileSync(marker)).package===pkg.name)target=resolveTarget({path:path.dirname(root)});
25
+ else if(!target&&process.env[config.env+'_SKILL_PATH'])target=resolveTarget();
26
+ }catch(e){console.error(JSON.stringify({ok:false,code:e.code,message:e.message}));process.exit(1);}
27
+ const ordinary=!args.includes('--help')&&!args.includes('-h')&&!['task','help','--help','-h','_worker','_auth-worker'].includes(args[0])&&args.length;
28
+ if(ordinary&&!args.includes('--no-auto-update')){
29
+ const receipt=await automatic(target);
30
+ if(!['disabled','cached','up-to-date','owner-managed'].includes(receipt.state))console.error(JSON.stringify({automaticUpdate:receipt}));
31
+ if(receipt.state==='updated'){
32
+ console.error(JSON.stringify({reloadSkill:true,entry:receipt.receipt.entry}));
33
+ const r=spawnSync(process.execPath,[receipt.receipt.entry,...args],{stdio:'inherit',env:{...process.env,[config.env+'_AUTO_UPDATE']:'0'},windowsHide:true});process.exit(r.status??1);
34
+ }
35
+ if(!receipt.ok){console.error(JSON.stringify(receipt));process.exit(1);}
36
+ }
37
+ if(args[0]==='doctor'&&target){
38
+ const installation=status(target),originalLog=console.log.bind(console);
39
+ console.log=(text,...rest)=>{let value;try{value=JSON.parse(text);}catch{return originalLog(text,...rest);}if(value&&typeof value==='object'){value.installation=installation;value.resolution=target;if(!installation.current){value.ok=false;value.code||='SKILL_RECONCILIATION_REQUIRED';process.exitCode=1;}}return originalLog(JSON.stringify(value,null,2));};
40
+ }
41
+ // Lifecycle and automatic maintenance are owned by the package dispatcher.
42
+ process.env[config.env+'_AUTO_UPDATE']='0';process.env[config.env+'_UPDATE_CHECK']='0';
43
+ await import('./business.mjs');
38
44
  }
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;}
45
+ }
@@ -1,8 +1,9 @@
1
1
  {
2
- "SKILL.md": "98df8d4271e525c687a1f0b3e877345bd42f3ca537515c0f84a9c0d58b17612b",
3
- "adapters/codex.json": "bea8d59e6e0dafae7439693b33356825023516a6f52be02a64c976d7ce47ce76",
4
- "adapters/sealseek.json": "04ef053762fd4cfc2309573ec87425afad14b2df85a1ea8ef0aa06d98fee1aee",
5
- "adapters/workbuddy.json": "cd0a1d8d5b9fcebc5a709b8c7523911f41973adb95f71af2c0f644473a43a6b4",
2
+ "SKILL.md": "501ce6f6dfe3e892c889e572df2ceb992bc68ba6dbfaab608b5e6558f67072c1",
3
+ "adapters/codex.json": "c8f0a3afc937725d561a9713fda9e32be309cb8394f971450b58731568421b62",
4
+ "adapters/generic.json": "0f1ec9e7b4a698449500af609644c2ef0737ea4a0eb0ccd56a013935a64df2f3",
5
+ "adapters/sealseek.json": "58cc420131ec37e793fe57900880f86cb30027e2f8cc4713b1a0568df4b78ab8",
6
+ "adapters/workbuddy.json": "b6f04afd14ccc95539c209f4bd8cf90be09240ff9ac95bcc5b1bd4f5b8b587ef",
6
7
  "agents/openai.yaml": "d8ebec24c4e3034f4b45aa052b9468ab35790ec7fd93febcfde512c746d2d1d1",
7
8
  "assets/approved/all-colors-user-finish.webp": "539c77de8ec0dd46a29793befecf813e97ce6ae66f7cbe69486846383b2ae936",
8
9
  "assets/approved/brand-kv-user-finish-20261012.png": "cb09198481e779444696864b265c689f467207bf7de9610f7adc2b850f0be7b4",
@@ -55,18 +56,19 @@
55
56
  "assets/rejected/brand-kv-c2-20261012.webp": "88ed2de0d950ea4a34519661481877ee0899743a6dfce203a2033c0dab6a73f7",
56
57
  "assets/rejected/overhead-rest-b.webp": "16e5e6fabdc665868ac244d556f3a8a93db826a34425fdee042e4f7a8ebf64c3",
57
58
  "assets/rejected/prone-pile-a.webp": "d07f38bbb69fc23b30dca4ed27faa3d7ae58e2e81840a1c3d46101911c28a7a2",
58
- "capabilities.json": "5d40595bf64402acf700cbaea63065d104547b12e59c275bca59cc9b4658de85",
59
+ "capabilities.json": "cd1fefac8edde8f00bc62f07d428b552b6a1130c7c67b8a89d5352338a4ee8cb",
59
60
  "references/assets.md": "98b1a60d70cbc9ceec3e0d11dadbc0dc96344ac6f15cd5289009dfbfd8d71d6e",
60
61
  "references/brand-layout.md": "74f2674b7c9987e15a9d2ca7bb18498378eecc2d869d37e9ca1e71bd228ee883",
61
62
  "references/canvas-comparison.md": "df85594c92de3e87daa85ee7cd9cc92df4be9049a5d42c32904542faf329a6c7",
62
63
  "references/cases.md": "9d0d2d3d210e367411d5a291fc78ef6c9c733afd79c9da76451c580fcbcd4d3e",
63
64
  "references/detail-final-20261016.md": "d9311413420db743466bbecfe98c31b9753eeead905472d69839afec9578c557",
64
65
  "references/kv-layout-case-20261012.md": "845b287cfc57912aabedc48e558ca661cf86bf136304ea841030205a806ef06f",
65
- "references/maintenance.md": "ccaa22cbe537885c7936d76b9091ef681491fd75d3791f6dbcf803d2337cee8e",
66
+ "references/maintenance.md": "f17e3fa7c74d630db5238fd366b7cd3864ba630a4dbd6e243f21e1337d082f80",
66
67
  "references/model-generation.json": "21daa2c3bf7d2000c7ddf52ab0b980cb7ee95d6c9d345602dc59ecbc128ec147",
67
68
  "references/model.md": "c4da688e22e2ada3f251fe0dc87effcaf5cb6ed6176f9d9c20a9661414bffab5",
68
69
  "references/page-patterns.md": "bdd6756e303c95e432d0239be27ec5af1faf75abf71594917f2e11467255a1b4",
69
70
  "references/photography-method.md": "c0e54598863f3b4a2d87f27d6f18afb75db22ae71ce2aead41f817f35258807e",
70
71
  "references/products.md": "642795ae16803669b169531240723bf72a388cb6351679a2787e67e181dca9cd",
71
- "references/source-page-three-variants.md": "02a265cf11c3ff3bb7796eb289529ce97f6f64f0350a15a7e3275cec24037720"
72
+ "references/source-page-three-variants.md": "02a265cf11c3ff3bb7796eb289529ce97f6f64f0350a15a7e3275cec24037720",
73
+ "scripts/run.mjs": "0b71e6de4ae7babfce792869dc538569cc2db1bd95f8690571c951c2873211b1"
72
74
  }
package/npm/skills.mjs CHANGED
@@ -1,104 +1,11 @@
1
1
  import fs from 'node:fs';
2
- import os from 'node:os';
3
2
  import path from 'node:path';
4
- import crypto from 'node:crypto';
5
- import { metadataPlan } from './metadata.mjs';
6
- import { stateRoot } from './update.mjs';
7
- import { root, pkg, fail } from './runtime.mjs';
8
-
9
- export const source = path.join(root, 'skills', 'cloud-hug-style-transfer');
10
- const marker = '.cloud-hug-style-transfer-managed.json';
11
- const metadata = 'agents/openai.yaml';
12
- function exists(file) { try { return fs.lstatSync(file); } catch (e) { if (e.code === 'ENOENT') return null; throw e; } }
13
- export function inventory(dir) {
14
- const result = {};
15
- function walk(at, prefix = '') {
16
- for (const entry of fs.readdirSync(at, { withFileTypes: true })) {
17
- if (entry.name === marker) continue;
18
- const relative = prefix + entry.name;
19
- if (entry.isSymbolicLink()) throw fail('SKILL_UNSAFE_TARGET', 'Skill files must not contain symlinks.');
20
- if (entry.isDirectory()) walk(path.join(at, entry.name), relative + '/');
21
- else result[relative] = crypto.createHash('sha256').update(fs.readFileSync(path.join(at, entry.name))).digest('hex');
22
- }
23
- }
24
- walk(dir);
25
- return result;
26
- }
27
- export function resolveTarget(agent='codex', targetRoot) {
28
- if (!['codex', 'sealseek', 'workbuddy'].includes(agent)) throw fail('INVALID_AGENT', 'Choose --agent codex, sealseek or workbuddy.');
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
- }
3
+ import * as lifecycle from '../lifecycle/engine.mjs';
4
+ import {metadataPlan} from './metadata.mjs';
5
+ export const source=lifecycle.source;
6
+ export const inventory=dir=>lifecycle.inventory(dir,{skip:['.agent-package.json','.runtime','.cloud-hug-style-transfer-managed.json']});
7
+ export const resolveTarget=(agent='generic',targetRoot)=>lifecycle.resolveTarget({agent,root:targetRoot});
35
8
  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'));
40
- }
41
- export function status(target) {
42
- const st = exists(target);
43
- if (!st) return { installed: false, managed: false, current: false, target };
44
- if (st.isSymbolicLink() || !st.isDirectory()) return { installed: true, managed: false, current: false, target };
45
- let record;
46
- try { record = JSON.parse(fs.readFileSync(path.join(target, marker), 'utf8')); } catch { return { installed: true, managed: false, current: false, target }; }
47
- if (record.package !== pkg.name || !record.files || typeof record.files !== 'object') return { installed: true, managed: false, current: false, target };
48
- if (Object.keys(record.files).some(file => !file || path.isAbsolute(file) || file.includes('\\') || file.split('/').some(part => ['.', '..', ''].includes(part)))) throw fail('SKILL_UNSAFE_TARGET', 'Invalid managed-file path in Skill ownership record.');
49
- const files = inventory(target);
50
- const edited = Object.entries(record.files).some(([file, hash]) => file !== metadata && files[file] !== hash);
51
- const expected = inventory(source);
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 };
55
- }
56
- export function install(target) {
57
- const started=performance.now();
58
- let state = status(target);
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.');
60
- if (state.edited) throw fail('SKILL_EDITED', 'Managed Skill files contain local edits; preserve and reconcile those edits before updating.');
61
- const registry = path.join(stateRoot(), 'skill-targets');
62
- fs.mkdirSync(registry, { recursive: true });
63
- const registration = path.join(registry, crypto.createHash('sha256').update(target).digest('hex') + '.json');
64
- if (!exists(registration)) fs.writeFileSync(registration, JSON.stringify({ target }), { flag: 'wx', mode: 0o600 });
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} };
67
- const expected = inventory(source);
68
- for (const file of Object.keys(expected)) {
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.');
70
- }
71
- fs.mkdirSync(path.dirname(target), { recursive: true });
72
- const lock = target + '.install-lock';
73
- let lockfd;
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; }
75
- let backup;
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;
82
- if (state.installed) {
83
- backup = path.join(stateRoot(), 'skill-backups', crypto.randomUUID());
84
- fs.mkdirSync(path.dirname(backup), { recursive: true });
85
- fs.cpSync(target, backup, { recursive: true, errorOnExist: true, force: false });
86
- } else fs.mkdirSync(target);
87
- // In-place updates support hosts holding a directory handle open. Backup is recoverable.
88
- for (const file of Object.keys(expected)) {
89
- if (file === metadata && exists(path.join(target, file))) { if(ui.changed)fs.writeFileSync(path.join(target,file),ui.text); continue; }
90
- fs.mkdirSync(path.dirname(path.join(target, file)), { recursive: true });
91
- fs.copyFileSync(path.join(source, file), path.join(target, file));
92
- }
93
- for (const file of Object.keys(state.record?.files || {})) {
94
- if (file !== metadata && !(file in expected)) fs.unlinkSync(path.join(target, file));
95
- }
96
- const actual = inventory(target);
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.');
99
- fs.writeFileSync(path.join(target, marker), JSON.stringify({ package: pkg.name, version: pkg.version, files: expected }, null, 2));
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 };
101
- } catch (e) {
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});
103
- } finally { fs.closeSync(lockfd); fs.unlinkSync(lock); }
104
- }
9
+ export const status=target=>lifecycle.status(lifecycle.resolveTarget({path:target}));
10
+ export const install=target=>lifecycle.install(lifecycle.resolveTarget({path:target}));
11
+ export function skillMetadata(target){const p=path.join(target,'agents/openai.yaml');return fs.existsSync(p)?metadataPlan(fs.readFileSync(p,'utf8')):{valid:false,missing:true};}
package/npm/update.mjs CHANGED
@@ -1,99 +1,6 @@
1
- import fs from 'node:fs';
2
- import os from 'node:os';
3
- import path from 'node:path';
4
- import crypto from 'node:crypto';
5
- import { spawnSync } from 'node:child_process';
6
- import { packReceipt } from './pack.mjs';
7
- import { source, resolveTarget, status } from './skills.mjs';
8
- import { root, pkg, fail } from './runtime.mjs';
9
-
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'));
11
- export function newer(a, b) {
12
- if (!/^\d+\.\d+\.\d+$/.test(a)) return false;
13
- const x=a.split('.').map(Number), y=b.split('.').map(Number);
14
- for(let i=0;i<3;i++) { if(x[i]!==y[i]) return x[i]>y[i]; }
15
- return false;
16
- }
17
- export function globalPrefix(location=root, platform=process.platform) {
18
- const modules=path.dirname(path.dirname(location));
19
- if(path.basename(modules)!=='node_modules' || fs.existsSync(path.join(location,'.git'))) return null;
20
- if(platform==='win32') return path.dirname(modules);
21
- return path.basename(path.dirname(modules))==='lib' ? path.dirname(path.dirname(modules)) : null;
22
- }
23
- export async function checkUpdate(registry=fetch) {
24
- try {
25
- const r=await registry(`https://registry.npmjs.org/${encodeURIComponent(pkg.name)}/latest`,{signal:AbortSignal.timeout(8000)});
26
- if(!r.ok) throw Error('Registry unavailable');
27
- const data=await r.json();
28
- if(data.name!==pkg.name || !/^\d+\.\d+\.\d+$/.test(data.version)) throw Error('Invalid stable package');
29
- return {ok:true,current:pkg.version,available:data.version,updateAvailable:newer(data.version,pkg.version),tag:'latest'};
30
- } catch { return {ok:false,code:'REGISTRY_UNAVAILABLE',current:pkg.version,updateAvailable:false,offline:'keep-current'}; }
31
- }
32
- function npm(args) {
33
- let cli=process.env.npm_execpath;
34
- if(!cli?.endsWith('npm-cli.js')) {
35
- const found=spawnSync(process.platform==='win32'?'where':'which',[process.platform==='win32'?'npm.cmd':'npm'],{encoding:'utf8',timeout:10000});
36
- const launcher=found.stdout?.trim().split(/\r?\n/)[0];
37
- cli=launcher && (process.platform==='win32' ? path.join(path.dirname(launcher),'node_modules','npm','bin','npm-cli.js') : fs.realpathSync(launcher));
38
- }
39
- if(!cli || !fs.existsSync(cli)) throw fail('NPM_UNAVAILABLE','npm is required for updates.');
40
- const r=spawnSync(process.execPath,[cli,...args],{encoding:'utf8',timeout:180000});
41
- if(r.status!==0) throw fail('UPDATE_FAILED','npm update failed; check npm connectivity and installation permissions.');
42
- return r.stdout;
43
- }
44
- export function installUpdate(check, services={}) {
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});
48
- const lock=path.join(state,'update.lock');
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;
59
- try {
60
- const live=JSON.parse(fs.readFileSync(path.join(root,'package.json'),'utf8'));
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);
71
- }
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.');
81
- mutated=true;
82
- run(['install','--global','--prefix',prefix,'--prefer-online','--ignore-scripts','--no-audit','--no-fund',`${pkg.name}@${check.available}`]);
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);}
99
- }
1
+ import * as lifecycle from '../lifecycle/engine.mjs';
2
+ export const stateRoot=()=>process.env.CLOUD_HUG_STATE_DIR||lifecycle.root;
3
+ export const globalPrefix=()=>null;
4
+ export const newer=lifecycle.newer;
5
+ export const checkUpdate=()=>Promise.resolve(lifecycle.checkUpdate());
6
+ export const installUpdate=(check,services={})=>{if(!services.resolution)throw lifecycle.fail('TARGET_PATH_REQUIRED','Resolve the selected Skill destination.');return lifecycle.update(services.resolution,{yes:true,version:check.available});};
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@petercjl/cloud-hug-style-transfer",
3
- "version": "0.4.0",
4
- "description": "抱抱云朵社品牌风格转换 Skill,支持 Codex、SealSeek 与 WorkBuddy",
3
+ "version": "0.5.1",
4
+ "description": "抱抱云朵社品牌风格转换 Skill,面向具备所需能力的任意 Agent,提供独立安装与更新。",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "cloud-hug-style-transfer": "npm/cli.mjs"
@@ -11,15 +11,24 @@
11
11
  "skills/",
12
12
  "capabilities.json",
13
13
  "README.md",
14
- "LICENSE"
14
+ "LICENSE",
15
+ "lifecycle",
16
+ "INSTALL.md",
17
+ "UPDATE.md",
18
+ "release-integrity.json"
15
19
  ],
16
20
  "engines": {
17
21
  "node": ">=22"
18
22
  },
19
23
  "scripts": {
20
- "test": "node --test test/*.test.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
- "prepack": "npm run check && npm test"
24
+ "test": "node --test --test-concurrency=2 test/*.test.mjs",
25
+ "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 && node --check npm/automatic-update.mjs",
26
+ "prepack": "node lifecycle/validate-release.mjs && npm run check && npm test",
27
+ "validate:release": "node lifecycle/validate-release.mjs",
28
+ "postinstall": "node lifecycle/notice.mjs",
29
+ "version": "node lifecycle/version.mjs",
30
+ "verify:packed": "node scripts/verify-packed.mjs",
31
+ "verify:historical": "node scripts/verify-historical.mjs"
23
32
  },
24
33
  "publishConfig": {
25
34
  "access": "public"
@@ -31,5 +40,12 @@
31
40
  "license": "UNLICENSED",
32
41
  "dependencies": {
33
42
  "yaml": "^2.9.1"
43
+ },
44
+ "skillLifecycle": {
45
+ "skill": "cloud-hug-style-transfer",
46
+ "entry": "npm/cli.mjs",
47
+ "env": "CLOUD_HUG",
48
+ "legacyMarker": ".cloud-hug-style-transfer-managed.json",
49
+ "contract": 2
34
50
  }
35
51
  }
@@ -0,0 +1,100 @@
1
+ {
2
+ "package": "@petercjl/cloud-hug-style-transfer",
3
+ "version": "0.5.1",
4
+ "files": {
5
+ "package.json": "d5b1f4154ea4707ef49b01c4b7c45707290b0b8601c7a5bf81a2f8aa162ef323",
6
+ "npm/arguments.mjs": "cc49d94f4f706f21fce0f23d90e33964d999f20dbb5862c20c0fed4640d7e72c",
7
+ "npm/automatic-update.mjs": "081d68bbc1ff7052a9e8aafc88dc67a1942915210039939338df19528672761c",
8
+ "npm/business.mjs": "5416ebb725f0a782513e8bcb34bced162187d599d94f8d6f9ca019f7a3f0cd62",
9
+ "npm/canvas-layout.mjs": "857165f4f02b68b4fd2e48d5e0d954738212818b792499b1a6369e4178d11edf",
10
+ "npm/cli.mjs": "e7a8907db55c1edaa8160d75f5e3712675b940ba97710f39b15fdc3e611c65f5",
11
+ "npm/integrity.json": "e31d47750d3ab27db9f68ae465d3aded0cafc798cffc2197ebeef81de029facc",
12
+ "npm/media-dependency.mjs": "f427dbe1c5d2cb084d1fafd2300f84cf4b3cb6f4516c767cbc9ea321c551a1a9",
13
+ "npm/metadata.mjs": "fa3a41bc9a81330e7e409aa7b0db29273a87624f616ed3d187277441ffe981ab",
14
+ "npm/pack.mjs": "b93bc128a23ac539666b9c62e853e0b3256a4739a3fb0f462a7069d3b04eeb90",
15
+ "npm/runtime.mjs": "2e01cc09e496db5e09e3726af845fac9bdcff7222f0750befc218616f0192913",
16
+ "npm/skills.mjs": "cd93e26cf286b7e4dfb3256fa710ec4f194343f9d2beae6646a6d657981022d2",
17
+ "npm/update.mjs": "8449f9ea2639a58b224ec2544e5b608cd64ea495289af8f81f76e9698339299e",
18
+ "skills/cloud-hug-style-transfer/SKILL.md": "501ce6f6dfe3e892c889e572df2ceb992bc68ba6dbfaab608b5e6558f67072c1",
19
+ "skills/cloud-hug-style-transfer/adapters/codex.json": "c8f0a3afc937725d561a9713fda9e32be309cb8394f971450b58731568421b62",
20
+ "skills/cloud-hug-style-transfer/adapters/generic.json": "0f1ec9e7b4a698449500af609644c2ef0737ea4a0eb0ccd56a013935a64df2f3",
21
+ "skills/cloud-hug-style-transfer/adapters/sealseek.json": "58cc420131ec37e793fe57900880f86cb30027e2f8cc4713b1a0568df4b78ab8",
22
+ "skills/cloud-hug-style-transfer/adapters/workbuddy.json": "b6f04afd14ccc95539c209f4bd8cf90be09240ff9ac95bcc5b1bd4f5b8b587ef",
23
+ "skills/cloud-hug-style-transfer/agents/openai.yaml": "d8ebec24c4e3034f4b45aa052b9468ab35790ec7fd93febcfde512c746d2d1d1",
24
+ "skills/cloud-hug-style-transfer/assets/approved/all-colors-user-finish.webp": "539c77de8ec0dd46a29793befecf813e97ce6ae66f7cbe69486846383b2ae936",
25
+ "skills/cloud-hug-style-transfer/assets/approved/brand-kv-user-finish-20261012.png": "cb09198481e779444696864b265c689f467207bf7de9610f7adc2b850f0be7b4",
26
+ "skills/cloud-hug-style-transfer/assets/approved/detail-final-20261016/01.jpg": "ecb481a422b3eadb0050b8c1080a1781e3fbd50ce4479f92e9f4a8beffd91187",
27
+ "skills/cloud-hug-style-transfer/assets/approved/detail-final-20261016/02.jpg": "676fdc94d3f247f370942f0d1cb1497e59f816b4aba77d551529b22a7a4ca49d",
28
+ "skills/cloud-hug-style-transfer/assets/approved/detail-final-20261016/03.jpg": "ec5b4f6fb3e86653ff1fff608bce322bc35f8447dfc823038fc3b245570c0461",
29
+ "skills/cloud-hug-style-transfer/assets/approved/detail-final-20261016/04.jpg": "0750a06d7d4c21077955e1ba991a5477efc33b0370444fc30ce885c93fe17355",
30
+ "skills/cloud-hug-style-transfer/assets/approved/detail-final-20261016/05.jpg": "75223e46c9ddb288498d64cbc4e8f61e00ed01733b3e5783805aa31d15c2ebd7",
31
+ "skills/cloud-hug-style-transfer/assets/approved/detail-final-20261016/06.jpg": "410be00a93f5be9e970554b96f950fb5cf6699e3244a2e572233e7e7bfcd8a33",
32
+ "skills/cloud-hug-style-transfer/assets/approved/detail-final-20261016/07.jpg": "96c2b12650a6cd326631e86f63e522c50afb84162a5d69d39fb3da67223de68a",
33
+ "skills/cloud-hug-style-transfer/assets/approved/detail-final-20261016/08.jpg": "f20f9a264fc81ae2b7c6e1764b8a3167d434224bed269cd96f826dcd2fd13875",
34
+ "skills/cloud-hug-style-transfer/assets/approved/detail-final-20261016/09.jpg": "dae56031cc673023ce882f6c9a678d43e31c18e9e7d0ca046248c3ca972cad19",
35
+ "skills/cloud-hug-style-transfer/assets/approved/detail-final-20261016/10.jpg": "c5ad7bfaf54fb0bd1d74e1833f6c7c1bc42c15f6449fadda0fe8daff2334121a",
36
+ "skills/cloud-hug-style-transfer/assets/approved/detail-final-20261016/11.jpg": "a0398cca68b2d76907e2c4656c506a4df04c9a38c7f91b160c719bf077ca016a",
37
+ "skills/cloud-hug-style-transfer/assets/approved/detail-final-20261016/12.jpg": "48e561a28548d4fbd712b1341dd76e3c668d376e13306b65a1ef32ac71ad7705",
38
+ "skills/cloud-hug-style-transfer/assets/approved/detail-final-20261016/13.jpg": "0ce9293acd81100f47cb9fc4c0064747ca911cae7c6a390da8c8c771d2df5a07",
39
+ "skills/cloud-hug-style-transfer/assets/approved/detail-final-20261016/14.jpg": "5f2c9dbf350e766c8064a4feaeef430611c02220f10648a099ed34b0b416bdc9",
40
+ "skills/cloud-hug-style-transfer/assets/approved/detail-final-20261016/15.jpg": "78c623e2c5eadfdd34aaaa7503fa6d975e1f1307016efe832b0fd9d2fd04fb8c",
41
+ "skills/cloud-hug-style-transfer/assets/approved/detail-final-20261016/16.jpg": "576fe80c894e221acdd7806a7e5892b4ea3922ca62b828ffecd4109c25549137",
42
+ "skills/cloud-hug-style-transfer/assets/approved/detail-final-20261016/17.jpg": "4cc72bd8cac12be0e8b54659daa3c2f44e8bd8e6953c127ca4adaf669e32e69e",
43
+ "skills/cloud-hug-style-transfer/assets/approved/detail-final-20261016/18.jpg": "88300f31dd4f1458c1b2fe927570c303a5e80a9c89abbd839d49e5fc808f3930",
44
+ "skills/cloud-hug-style-transfer/assets/approved/detail-final-20261016/19.jpg": "588a474405e3672e4780252c7c1cc25f558974908628b970026d42575a9d9851",
45
+ "skills/cloud-hug-style-transfer/assets/approved/detail-final-20261016/sources.json": "38acec5807cfec104ada2cc93a0a1771dae78960cd4402e9550f9aad77e7fd86",
46
+ "skills/cloud-hug-style-transfer/assets/approved/dog-detail.webp": "e9e73ae4cf35071eea7b1ce161ab7e0a5d7f4a4b8bbeb83be646e1bfec555aa0",
47
+ "skills/cloud-hug-style-transfer/assets/approved/hippo-detail.webp": "5f3fc742492747166666704adc1744a6859774a95d3d062ee3d17e632f3c7ee5",
48
+ "skills/cloud-hug-style-transfer/assets/approved/overhead-breathing-user-finish.png": "f65546328c773a5e2837b896237d9b3adcb175c3b6e565b28e7fa2353008dd3f",
49
+ "skills/cloud-hug-style-transfer/assets/approved/quiet-prone-user-finish.webp": "e01c02a1804a50972eb8ec2438268b89697c4903d3624246d22f1ef8e1698dbf",
50
+ "skills/cloud-hug-style-transfer/assets/approved/rabbit-detail.webp": "787c296639b0b4922d8aa0668f3d08760ea786f6dad4c3ca20fa5943d2456fe8",
51
+ "skills/cloud-hug-style-transfer/assets/brand/layout-reference.jpg": "4a100fcb461bb111a671f7051302f9be2f918bca6b3c73eeb2e9ee7f52f5eaba",
52
+ "skills/cloud-hug-style-transfer/assets/brand/logo-blue.png": "70010f32676c9ed93268efac3dcd5f87b9caf3b57d52932eb2a5d4f7a8a268d9",
53
+ "skills/cloud-hug-style-transfer/assets/brand/main-kv-dog-rest.webp": "6a237f78ac8cc839a6a7786742bb38921f6dd843313893444d4cfcf8ed257c67",
54
+ "skills/cloud-hug-style-transfer/assets/brand/main-kv-lounge.webp": "e6f55f9671c2aec17582b742b7ad9575d8e7b39aa8b2d8b6691caf0da86f0405",
55
+ "skills/cloud-hug-style-transfer/assets/brand/main-kv-seated-hug.webp": "cc7c52883e3732466079b9625110cce09ac7072337587fbb0213f9c31ff7f44b",
56
+ "skills/cloud-hug-style-transfer/assets/brand/main-kv-sleep.webp": "57425f54c6aa9e9d0e73fa1eb9fc2b64b09ec6f579facbb6d89178c58528953c",
57
+ "skills/cloud-hug-style-transfer/assets/icon.svg": "49315dda7125ec5fc77ef5f2b96126d8b2121c6e72944b4702972e90f321d3ee",
58
+ "skills/cloud-hug-style-transfer/assets/model/character-sheet-approved-20261019.png": "55300aa20053612fe132bf0899ba0d3ffd280a197782aeba72fd097df29f51f3",
59
+ "skills/cloud-hug-style-transfer/assets/products/bear.jpg": "6b182d98bf778f45bd2a498c5e428ac5698a4bfd8425c5ea0c04fbda465456e5",
60
+ "skills/cloud-hug-style-transfer/assets/products/dog.jpg": "14a513feb9216b04a62e0d78d9b69ca463750ff5e957725512a776de5d7f6d87",
61
+ "skills/cloud-hug-style-transfer/assets/products/hippo.jpg": "67da5fdaa60274d08cd545ac0c9c891c3cd9761e74dc39c75219b1c676a634af",
62
+ "skills/cloud-hug-style-transfer/assets/products/rabbit.jpg": "39f250512a465465190e01c25ea3e8c5a8759c12bdd82823d9efbdf11720e332",
63
+ "skills/cloud-hug-style-transfer/assets/products/six-variants.webp": "a15e1a38bcdcef07c4c00e4978908e8a9054bd91e2c410abea1cbd93b6106763",
64
+ "skills/cloud-hug-style-transfer/assets/references/kv-layout-source-20261012.webp": "ad98d1b3668080d4cca679eb5a8fd8119d90be38e04b5b1a79f29f33c406af0d",
65
+ "skills/cloud-hug-style-transfer/assets/references/kv-old-long-20261012.webp": "ba0402fb099bb5561d5351872bb4e63bcee159228016fc28b6c95cfea919608d",
66
+ "skills/cloud-hug-style-transfer/assets/references/kv-photo-source-20261012.webp": "084d267802a0acf6cd54201215ea2472ffe54f11e37d803a38dbe5e5271771c2",
67
+ "skills/cloud-hug-style-transfer/assets/references/overhead-cushion-source.webp": "85f7d9636e5c7a4310690027f5dde709cfafbe3abc44804094338faf62bc950d",
68
+ "skills/cloud-hug-style-transfer/assets/references/prone-pile-source.webp": "4e6537e322fa99e9c23599547bb60c97afc09ef61133c3bb03cd6dab5e8d1588",
69
+ "skills/cloud-hug-style-transfer/assets/rejected/all-colors-b.webp": "d74a8dc41d9de0f4b024f6ae8b2a02f7fdbb2c9f07d4841c47181002760266aa",
70
+ "skills/cloud-hug-style-transfer/assets/rejected/brand-kv-a2-20261012.webp": "276ec445939643559708f04c63292ffec384744ea4c7b517d6e1a3abd52397e9",
71
+ "skills/cloud-hug-style-transfer/assets/rejected/brand-kv-b2-20261012.webp": "80ec90d0b5500d9b661533ad8c59af2c24c89a76f6fc301993462f48a37a7def",
72
+ "skills/cloud-hug-style-transfer/assets/rejected/brand-kv-c2-20261012.webp": "88ed2de0d950ea4a34519661481877ee0899743a6dfce203a2033c0dab6a73f7",
73
+ "skills/cloud-hug-style-transfer/assets/rejected/overhead-rest-b.webp": "16e5e6fabdc665868ac244d556f3a8a93db826a34425fdee042e4f7a8ebf64c3",
74
+ "skills/cloud-hug-style-transfer/assets/rejected/prone-pile-a.webp": "d07f38bbb69fc23b30dca4ed27faa3d7ae58e2e81840a1c3d46101911c28a7a2",
75
+ "skills/cloud-hug-style-transfer/capabilities.json": "cd1fefac8edde8f00bc62f07d428b552b6a1130c7c67b8a89d5352338a4ee8cb",
76
+ "skills/cloud-hug-style-transfer/references/assets.md": "98b1a60d70cbc9ceec3e0d11dadbc0dc96344ac6f15cd5289009dfbfd8d71d6e",
77
+ "skills/cloud-hug-style-transfer/references/brand-layout.md": "74f2674b7c9987e15a9d2ca7bb18498378eecc2d869d37e9ca1e71bd228ee883",
78
+ "skills/cloud-hug-style-transfer/references/canvas-comparison.md": "df85594c92de3e87daa85ee7cd9cc92df4be9049a5d42c32904542faf329a6c7",
79
+ "skills/cloud-hug-style-transfer/references/cases.md": "9d0d2d3d210e367411d5a291fc78ef6c9c733afd79c9da76451c580fcbcd4d3e",
80
+ "skills/cloud-hug-style-transfer/references/detail-final-20261016.md": "d9311413420db743466bbecfe98c31b9753eeead905472d69839afec9578c557",
81
+ "skills/cloud-hug-style-transfer/references/kv-layout-case-20261012.md": "845b287cfc57912aabedc48e558ca661cf86bf136304ea841030205a806ef06f",
82
+ "skills/cloud-hug-style-transfer/references/maintenance.md": "f17e3fa7c74d630db5238fd366b7cd3864ba630a4dbd6e243f21e1337d082f80",
83
+ "skills/cloud-hug-style-transfer/references/model-generation.json": "21daa2c3bf7d2000c7ddf52ab0b980cb7ee95d6c9d345602dc59ecbc128ec147",
84
+ "skills/cloud-hug-style-transfer/references/model.md": "c4da688e22e2ada3f251fe0dc87effcaf5cb6ed6176f9d9c20a9661414bffab5",
85
+ "skills/cloud-hug-style-transfer/references/page-patterns.md": "bdd6756e303c95e432d0239be27ec5af1faf75abf71594917f2e11467255a1b4",
86
+ "skills/cloud-hug-style-transfer/references/photography-method.md": "c0e54598863f3b4a2d87f27d6f18afb75db22ae71ce2aead41f817f35258807e",
87
+ "skills/cloud-hug-style-transfer/references/products.md": "642795ae16803669b169531240723bf72a388cb6351679a2787e67e181dca9cd",
88
+ "skills/cloud-hug-style-transfer/references/source-page-three-variants.md": "02a265cf11c3ff3bb7796eb289529ce97f6f64f0350a15a7e3275cec24037720",
89
+ "skills/cloud-hug-style-transfer/scripts/run.mjs": "0b71e6de4ae7babfce792869dc538569cc2db1bd95f8690571c951c2873211b1",
90
+ "capabilities.json": "c10b594c9ef708755391b016152475a8d466a9f6094defb252347c8a2ac9817b",
91
+ "README.md": "4de323933538c1f761a034e93c9f638c3b19680917c1b3d99375033c4ba07bee",
92
+ "LICENSE": "1bcfea195910091f440b9b09399b5a88a6112a1b0013c3ae5784e2067d986acf",
93
+ "lifecycle/engine.mjs": "67ee4a2727162930205b2cee172de7df5821a599a84d510ecda253401310a523",
94
+ "lifecycle/notice.mjs": "2fde2937acb6fa170e1e575b2d65b8a1d7db07794a27ed0abb5571a529132271",
95
+ "lifecycle/validate-release.mjs": "6c22ff444122d2dbbcf6ae14ea8578d12d74400491b832045e17228599c73b64",
96
+ "lifecycle/version.mjs": "8f18e243f1af7aa4eef5713054dc187633386076c7d556574ce9727d1c519521",
97
+ "INSTALL.md": "6b045ff0fc135bb0f1c71760b26c35cbe49d83563f3779d141a86e705159906e",
98
+ "UPDATE.md": "d9886035f501dcfc0e0b8d0a5a04d361eabfdc4dbd493ffa49add6610f411345"
99
+ }
100
+ }
@@ -1,10 +1,22 @@
1
1
  ---
2
2
  name: cloud-hug-style-transfer
3
3
  description: 独立把旧详情页、产品摄影、主KV或SKU转换为抱抱云朵社的品牌视觉与同一模特。保留当次商品、有效文案参数及页面用途,产品款式与材料随新资料变化。内置完整19页定稿、LOGO、人物和摄影排版方法;生图必需 @petercjl/sealseek-media-cli 及其配套 sealseek-media Skill,未检测到即暂停;品牌资料无需私人素材库。用于“抱抱云朵社风格转换”、旧页品牌化、同模特延展与图文设计。
4
+ metadata:
5
+ package: "@petercjl/cloud-hug-style-transfer"
6
+ version: 0.5.1
4
7
  ---
5
8
 
6
9
  # 抱抱云朵社风格转换
7
10
 
11
+ ## Package installation and local execution
12
+
13
+ The owning npm package is the canonical source. Installation instructions are in its INSTALL.md and UPDATE.md before Skill loading. Resolve the current Agent's supported Skill directory and use explicit `--path` with package-managed install/status/update. Named Agent identities describe conventions, not eligibility or directory defaults.
14
+
15
+ After managed installation, invoke this Skill's `scripts/run.mjs` with the current Node.js runtime for every owning-package CLI command below. The launcher uses the target-owned `.runtime` and bundled dependencies. Resolve this launcher relative to this Skill's actual directory; do not fall back to a shared global package when the installed runtime is missing. External service dependencies are declared separately and resolve their own canonical Skill through their documented CLI contract.
16
+
17
+ Maintenance completes CLI/runtime and Skill verification, followed by host-native reload and discovery. CLI receipts leave host discovery pending. Automatic checks notify by default; installation requires separate standing authorization and a compatible stable version. Use update operation/resume for partial or unknown outcomes, preserving the original transaction and backup. Only the selected current Agent is synchronized.
18
+
19
+
8
20
  使用中文展示名 **抱抱云朵社风格转换**。用本目录内的方法和素材独立完成品牌转换,以当前使用者的明确要求为准;生成能力由必需的 `@petercjl/sealseek-media-cli` 及其规范配套 `sealseek-media` Skill 提供,品牌资料不依赖创建者的历史会话或私人文件权限。
9
21
 
10
22
  ## 运行合同与平台入口
@@ -17,7 +29,9 @@ description: 独立把旧详情页、产品摄影、主KV或SKU转换为抱抱
17
29
 
18
30
  ### 入口:必需依赖检查
19
31
 
20
- **每次业务任务先检查依赖,通过后才进入第 1 节;规划任务也遵守此入口。** 执行 `cloud-hug-style-transfer doctor --json`,核对 `dependencies.media.ok`。检查支持当前 npm 安装树、PATH 安装及显式配置的 `CLOUD_HUG_MEDIA_ROOT`;返回的 `dependencies.media.invocation` 是经过包身份核验的 CLI 调用入口,使用宿主当前 Node 运行时,可用于 Agent 管理的运行时或套件组件。
32
+ 当前宿主已发现 `sealseek-media` 时,先从该 Skill 的实际目录解析其本地启动入口与规范来源,将其已核验的独立运行包根目录作为 `CLOUD_HUG_MEDIA_ROOT` 传给本应用的诊断与调用。未提供该绑定时,使用依赖检查器声明的发现合同。该绑定只选择当前宿主的依赖安装。
33
+
34
+ **每次业务任务先检查依赖,通过后才进入第 1 节;规划任务也遵守此入口。** 执行 `cloud-hug-style-transfer doctor --json`;此入口按当前策略自动检测更新,读取 `automaticUpdate`。若其 `reloadSkill` 或 `changed` 为 true,先通过 `skill source --json` 重新加载当前规范 Skill 再继续;CLI 在包替换后会自动以新入口重跑本次检查。核对 `dependencies.media.ok`。检查支持当前 npm 安装树、PATH 安装及显式配置的 `CLOUD_HUG_MEDIA_ROOT`;返回的 `dependencies.media.invocation` 是经过包身份核验的 CLI 调用入口,使用宿主当前 Node 运行时,可用于 Agent 管理的运行时或套件组件。
21
35
 
22
36
  未检测到 `@petercjl/sealseek-media-cli` 时返回 `DEPENDENCY_MISSING` 并**暂停整个任务**,保留输入和进度,给出最简安装提示词:“请安装 npm 包 @petercjl/sealseek-media-cli。”等待安装并重新检查通过后,从本入口恢复。版本低于 0.6.1、CLI 无法执行、规范 Skill 缺失或合同不兼容同样暂停,按诊断修复后复查。不得以宿主内置生图、其他提供商或继续规划代替依赖通过;本入口不自动安装软件或提交生成。
23
37
 
@@ -69,5 +69,6 @@
69
69
  "windows": "implemented"
70
70
  },
71
71
  "notes": "Image generation uses the same required sealseek-media-cli on every host. Native viewing and command execution still require host verification. Missing media dependency pauses all tasks.",
72
- "host_generation_tested": false
72
+ "host_generation_tested": false,
73
+ "local_execution": "Use this installed Skill’s scripts/run.mjs for owning-package commands; resolve external media through its independently managed canonical contract."
73
74
  }