@petercjl/competitor-visual-canvas 0.1.1 → 0.1.7

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/INSTALL.md ADDED
@@ -0,0 +1,7 @@
1
+ # Install for the current Agent
2
+
3
+ User prompt: “请安装 @petercjl/competitor-visual-canvas,并配置当前 Agent 使用。”
4
+
5
+ The executing Agent installs the npm package, resolves its own exact Skill directory and registration mechanism, reads `skill source --json`, then runs `skill install --agent CURRENT --path ABSOLUTE_SKILL_DIRECTORY --json`. Node 22+ is required. Installation copies canonical resources and an independent runtime, preserves host metadata, and refuses user-owned targets. Verify CLI version, managed/current status and SHA256 verification, then load the Skill through native host discovery. npm success with Skill or registration pending is incomplete. Scripts-disabled installation uses this same handoff.
6
+
7
+ Service capabilities are separate installations: tbcli for collection, boardmixcli videoContract v1 (0.1.6+) for Boardmix, or sealseek-media for Infinite Canvas. Boardmix videos require ffprobe. Login occurs in the selected service; package installation grants no service access.
package/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # Competitor visual canvas
2
2
 
3
- Application package for collecting Taobao/Tmall visual references into SealSeek Infinite Canvas. The application owns the collection workflow and layout. `@petercjl/tbcli` owns product collection; `@petercjl/sealseek-media-cli` owns service authentication and generic canvas operations.
3
+ Application package for collecting Taobao/Tmall visual references into Infinite Canvas or explicitly selected Boardmix. The application owns the collection workflow and layout. `@petercjl/tbcli` owns product collection; `@petercjl/sealseek-media-cli` owns service authentication and generic canvas operations.
4
4
 
5
- Requires Node.js 22+, `tbcli item media`, and SealSeek `canvas batch` (including text-batch) / `media inspect` capabilities. Service credentials stay with the dependency packages. The public npm package supports Codex, SealSeek and WorkBuddy adapters. macOS Codex business runs are verified; other host runtime evidence is separate from portable package tests.
5
+ Requires Node.js 22+, `tbcli item media`, and SealSeek `canvas batch` (including text-batch) / `media inspect` capabilities. Service credentials stay with the dependency packages. Any Agent with the required execution capabilities can use the generic adapter. macOS Codex business runs are verified; other host runtime evidence is separate from portable package tests.
6
6
 
7
7
  ```sh
8
8
  competitor-visual-canvas doctor --json
@@ -48,8 +48,22 @@ Agent prompt: “用竞品视觉素材画板工具,找到画板‘我的竞品
48
48
 
49
49
  ## Installation and updates
50
50
 
51
- Install `@petercjl/competitor-visual-canvas` globally, then use `competitor-visual-canvas skill install --agent codex|sealseek|workbuddy --json` for the current Agent. Its npm dependencies provide compatible tbcli and sealseek-media CLIs; service authorization remains separate. SealSeek resolves the active default workspace or a configured SEALSEEK_SKILLS_DIR; ambiguous roots require an explicit --path.
51
+ 向当前使用的 Agent 发送:“请安装 @petercjl/competitor-visual-canvas,并配置当前 Agent 使用。”
52
52
 
53
- Global installations check stable latest on business invocation once per day, download/install a newer version, refresh already managed Skills with backups and run the original command once. Local edits stop automatic synchronization. Offline checks keep the current version; interrupted updates retain package backups in private state. `update auto status|on|off` controls the policy, and `update install --yes` forces a check. Suite-local installations stay managed by taobao-ai-ops; Git development stays Git-owned. Custom Skill paths need explicit skill synchronization.
53
+ 更新提示词:“请更新 @petercjl/competitor-visual-canvas,并同步当前 Agent 的 Skill。”
54
+
55
+ The executing Agent follows [INSTALL.md](INSTALL.md) or [UPDATE.md](UPDATE.md), resolves its exact Skill directory, preserves edits, synchronizes only that target and verifies the CLI, independent runtime, receipt hashes and native discovery. Ordinary invocations notify about stable updates daily; automatic installation requires explicit opt-in and a selected target. Service dependencies and login remain separate. Git checkouts stay Git-owned.
54
56
 
55
57
  Application run directories and credential profiles stay outside npm. Continue a canvas from its newest completed run; backup and unknown-write recovery use that existing canvas rather than creating another.
58
+
59
+ ## Boardmix 素材归档
60
+
61
+ 默认使用无限画板。用户明确指定 Boardmix 时,应用改用 boardmixcli 归档主图、主图视频、SKU 图和详情图;视频使用原生 MP4 对象,支持为已有图片画板补充视频。
62
+
63
+ > 使用 competitor-visual-canvas 收集这些竞品的图片素材到 Boardmix:提供商品链接或 ID。
64
+
65
+ Boardmix 分支要求当前 boardmixcli 具有 frame.create、text.create 和 image.download 能力,通过 boardmixcli 准备 Chrome 登录与每个编辑器的授权连接。目标、来源、布局和 GUID 回执保存于应用运行目录;同一运行可恢复。macOS 已验证浏览器接入;追加使用最新已完成运行目录,通过 append --base-run 复用原文件并保持已有图元坐标。按 Boardmix 名称查找仍未支持。
66
+
67
+ Boardmix writes discover batch contract v1 automatically: up to 20 images per import, batch placement/readback, and receipt-based resume. Layout decisions remain in this application; older capability packages retain the serial path.
68
+
69
+ For an authorized Chrome CDP session, Boardmix create/canvas accept `--cdp-endpoint URL` to open and connect the exact file through boardmixcli without visible DevTools. Existing run identity and receipts are retained on connection failure.
package/UPDATE.md ADDED
@@ -0,0 +1,7 @@
1
+ # Update the current Agent
2
+
3
+ User prompt: “请更新 @petercjl/competitor-visual-canvas,并同步当前 Agent 的 Skill。”
4
+
5
+ Resolve the current Agent and exact Skill directory before package replacement. Use `update install --agent CURRENT --path ABSOLUTE_SKILL_DIRECTORY --yes --json`, or install an exact approved npm version and run its `skill update` with the same selected target. Preserve edits and inspect backup/recovery output. Same-version maintenance reconciles stale resources. Verify CLI, Skill runtime and receipt versions, managed/current SHA256 status, and native discovery. Other Agent targets are unchanged. A source checkout updates through Git.
6
+
7
+ Ordinary invocations detect stable updates daily with bounded network time and offline backoff. Automatic installation is opt-in via COMPETITOR_CANVAS_AUTO_INSTALL=1 with explicit COMPETITOR_CANVAS_AGENT and COMPETITOR_CANVAS_SKILL_PATH. `update auto off` disables checks. Unknown or partial outcomes require inspecting the existing package and selected Skill before retrying.
@@ -5,20 +5,26 @@ import {performUpdate,latestVersion,updateStatus,setAutomatic} from '../src/upda
5
5
  import {collect,planRun,publishCanvas,invoke,read,fail,configureTool,appendRun} from '../src/workflow.mjs';
6
6
  import {reflowRun} from '../src/reflow.mjs';
7
7
  import {findCanvases,appendToCanvas} from '../src/canvas-target.mjs';
8
+ import {createBoardmix,writeBoardmix,recoverBoardmix,requireBoardmix,addBoardmixVideos} from '../src/boardmix.mjs';
8
9
  import {ROOT,META,skill} from '../src/lifecycle.mjs';
9
10
  const argv=process.argv.slice(2),command=argv.shift(),options={},args=[];
10
- function parse(){for(let i=0;i<argv.length;i++){const k=argv[i];if(k==='--json')continue;if(['--submit','--yes'].includes(k)){options[k.slice(2)]=true;continue;}if(k.startsWith('--')){const key=k.slice(2),value=argv[++i];if(!value||value.startsWith('--'))fail('INVALID_INPUT','Missing '+k);if(!['input','raw','run','title','agent','canvas','tool','entry','base-run','path'].includes(key))fail('INVALID_INPUT','Unknown '+k);(options[key]??=[]).push(value);}else args.push(k);}}
11
+ function parse(){for(let i=0;i<argv.length;i++){const k=argv[i];if(k==='--json')continue;if(['--submit','--yes','--verified'].includes(k)){options[k.slice(2)]=true;continue;}if(k.startsWith('--')){const key=k.slice(2),value=argv[++i];if(!value||value.startsWith('--'))fail('INVALID_INPUT','Missing '+k);if(!['input','raw','run','title','agent','canvas','tool','entry','base-run','path','target','session','file-key','cdp-endpoint','session-id','local-id'].includes(key))fail('INVALID_INPUT','Unknown '+k);(options[key]??=[]).push(value);}else args.push(k);}}
11
12
  const one=k=>options[k]?.at(-1);
12
13
  const help=`competitor-visual-canvas ${META.version}
13
14
  collect --input ID_OR_URL [--input MORE] --run NEW_DIR [--raw SAVED_COLLECTION.json ...] --json
15
+ collect --target boardmix --input ID_OR_URL --run NEW_DIR --json
16
+ boardmix videos --base-run COMPLETED_DIR --run NEW_DIR [--raw COLLECTION ...] --json
17
+ boardmix create --run DIR --session FILE --file-key SOURCE_KEY [--cdp-endpoint URL] --submit --json
18
+ boardmix recover --run DIR --session FILE --file-key KEY --session-id N --local-id N [--verified] --submit --json
19
+ canvas --run DIR --session FILE --file-key KEY [--cdp-endpoint URL] [--submit] --json (dispatches saved target)
14
20
  plan --run DIR [--title TEXT] [--base-run COMPLETED_DIR] --json
15
21
  find --title EXACT_TITLE --json (read-only exact-name lookup)
16
22
  append (--base-run COMPLETED_DIR | --title EXACT_TITLE | --canvas ID) --run NEW_DIR --input ID_OR_URL [--input MORE] [--raw FILE ...] --json
17
23
  reflow --run DIR [--submit] --json (migrate a legacy canvas to horizontal regions)
18
24
  canvas --run DIR [--submit] --json
19
25
  recover --run DIR --canvas ID --submit --json (bind verified existing canvas after uncertain creation)
20
- tool run tbcli|sealseek-media ARGS...
21
- configure --tool tbcli|sealseek-media --entry CLI_PATH --submit --json
26
+ tool run tbcli|sealseek-media|boardmixcli ARGS...
27
+ configure --tool tbcli|sealseek-media|boardmixcli --entry CLI_PATH --submit --json
22
28
  version | capabilities --json | doctor --json
23
29
  skill source|status|install|update [--agent codex|sealseek|workbuddy] [--path DIR] --json
24
30
  update check|install --yes --json
@@ -28,30 +34,37 @@ Global npm installations check stable updates daily during use and synchronize m
28
34
  Source development and suite-managed installations use their owner update path.`;
29
35
  async function main(){
30
36
  if(!command||['--help','help'].includes(command))return {help};
31
- if(command==='tool'&&argv[0]==='run'){const tool=argv[1];if(!['tbcli','sealseek-media'].includes(tool))fail('INVALID_INPUT','Unknown dependency.');return invoke(tool,argv.slice(2));}
32
- parse();
37
+ if(command==='skill'&&argv.includes('--help')){const caps=await read(path.join(ROOT,'capabilities.json'));const contract=caps.commandContracts['skill '+argv[0]];if(!contract)fail('INVALID_INPUT','Unknown Skill operation.');return contract;}
38
+ if(command==='tool'&&argv[0]==='run'){const tool=argv[1];if(!['tbcli','sealseek-media','boardmixcli'].includes(tool))fail('INVALID_INPUT','Unknown dependency.');return invoke(tool,argv.slice(2));}
39
+ parse();if(one('target')&&!['infinite-canvas','boardmix'].includes(one('target')))fail('INVALID_TARGET','Choose infinite-canvas or boardmix.');
33
40
  if(command==='configure'){if(!options.submit)fail('SUBMIT_REQUIRED','Configuring dependency entry requires --submit.');return configureTool(one('tool'),one('entry'));}
34
41
  if(command==='version')return {version:META.version};
35
42
  if(command==='skill')return skill(args[0],one('agent'),one('path'));
36
- if(command==='capabilities')return {...await read(path.join(ROOT,'skills','competitor-visual-canvas','capabilities.json')),execution:{frame_grouping:'four-per-product',inputs:'Taobao IDs or Taobao/Tmall detail URLs',archive:'canvas',supported_platform:process.platform==='darwin'?'macos':'unverified'}};
43
+ if(command==='capabilities')return {...await read(path.join(ROOT,'skills','competitor-visual-canvas','capabilities.json')),execution:{frame_grouping:'four-per-product',inputs:'Taobao IDs or Taobao/Tmall detail URLs',archive:'canvas',targets:['infinite-canvas','boardmix'],default_target:'infinite-canvas',supported_platform:process.platform==='darwin'?'macos':'unverified'}};
44
+ if(command==='doctor'&&one('target')==='boardmix'){await requireBoardmix();const source=await invoke('tbcli',['skill','source','--json']);return {ok:!!source,target:'boardmix',service_access:'not-checked'};}
37
45
  if(command==='doctor'){const checks=[];for(const tool of ['tbcli','sealseek-media'])try{const source=await invoke(tool,['skill','source','--json']),capabilities=await invoke(tool,['capabilities','--json']);const s=source.source??source.data?.source;const valid=tool==='tbcli'?JSON.stringify(capabilities).includes('item media'):['frame-batch','text-batch','media-inspect','source-metadata'].every(f=>capabilities.manifest?.canvas_contract?.features?.includes(f));checks.push({tool,source:s,ok:!!s&&valid});}catch(e){checks.push({tool,ok:false,code:e.code??'CLI_UNAVAILABLE'});}return {ok:checks.every(c=>c.ok),checks,node:process.version,service_access:'not-checked'};}
38
46
  if(command==='update'){
39
47
  if(args[0]==='check'){const latest=await latestVersion();return {current:META.version,latest,updateAvailable:latest!==META.version};}
40
48
  if(args[0]==='auto'){if(args[1]==='status')return updateStatus();if(['on','off'].includes(args[1]))return setAutomatic(args[1]==='on');}
41
- if(args[0]==='install'){if(!options.yes)fail('AUTHORIZATION_REQUIRED','Use --yes for package update.');return performUpdate({automatic:false});}
49
+ if(args[0]==='install'){if(!options.yes)fail('AUTHORIZATION_REQUIRED','Use --yes for package update.');if(!one('agent')||!one('path'))fail('TARGET_UNRESOLVED','Provide the current Agent and explicit --path.');const {status}=await import('../src/skills.mjs');return performUpdate({automatic:false,targets:async()=>{const s=await status(one('agent'),one('path'));if(s.edited)fail('LOCAL_EDITS','Selected Skill has local edits.');if(s.installed&&!s.managed)fail('UNMANAGED_TARGET','Selected Skill is user-owned.');return [{agent:one('agent'),path:s.destination}];}});}
42
50
  fail('INVALID_INPUT','Use update check/install or auto status/on/off.');
43
51
  }
44
- if(command==='find')return findCanvases(one('title'));
52
+ if(command==='find'){if(one('target')==='boardmix')fail('FEATURE_UNSUPPORTED','Use an explicit Boardmix file key or its saved run.');return findCanvases(one('title'));}
45
53
  const run=one('run');if(!run)fail('INVALID_INPUT','Provide --run DIR.');
46
- if(command==='collect'){const result=await collect(path.resolve(run),options.input||[],options.raw||[]);return {run_id:result.run_id,run:path.resolve(run),products:result.products.map(p=>({id:p.id,title:p.title,counts:Object.fromEntries(Object.entries(p.assets).map(([k,v])=>[k,v.length]))}))};}
47
- if(command==='plan')return planRun(path.resolve(run),{title:one('title'),baseRun:one('base-run')?path.resolve(one('base-run')):undefined});
54
+ if(command==='collect'){const result=await collect(path.resolve(run),options.input||[],options.raw||[],one('target')||'infinite-canvas');return {run_id:result.run_id,target:result.target,run:path.resolve(run),products:result.products.map(p=>({id:p.id,title:p.title,counts:Object.fromEntries(Object.entries(p.assets).map(([k,v])=>[k,v.length]))}))};}
55
+ if(command==='plan')return planRun(path.resolve(run),{target:one('target'),title:one('title'),baseRun:one('base-run')?path.resolve(one('base-run')):undefined});
56
+ const boardmixOptions={cdpEndpoint:one('cdp-endpoint'),session:one('session'),fileKey:one('file-key'),submit:!!options.submit,verified:!!options.verified,sessionID:one('session-id')===undefined?undefined:Number(one('session-id')),localID:one('local-id')===undefined?undefined:Number(one('local-id'))};
57
+ if(command==='boardmix'){if(one('target')&&one('target')!=='boardmix')fail('TARGET_CONFLICT','Boardmix command conflicts with the explicit target.');if(args[0]==='videos')return addBoardmixVideos(path.resolve(run),one('base-run')?path.resolve(one('base-run')):undefined,options.raw||[]);if(args[0]==='create'){if(!options.submit)fail('SUBMIT_REQUIRED','Use --submit to create the target file.');return createBoardmix(path.resolve(run),boardmixOptions);}if(args[0]==='recover'){if(!options.submit)fail('SUBMIT_REQUIRED','Use --submit for recovery.');return recoverBoardmix(path.resolve(run),boardmixOptions);}fail('INVALID_INPUT','Use boardmix create/recover.');}
48
58
  if(command==='append'){
59
+ if(one('target')==='boardmix'&&!one('base-run'))fail('FEATURE_UNSUPPORTED','Boardmix append requires --base-run from the latest completed run.');
60
+ if(one('base-run')&&one('target')&&one('target')!==((await read(path.join(one('base-run'),'layout.plan.json'))).target||'infinite-canvas'))fail('TARGET_CONFLICT','Requested target differs from base run.');
49
61
  if(one('base-run')){if(one('title')||one('canvas'))fail('INVALID_INPUT','Use a base run or a canvas selector.');return appendRun(path.resolve(run),path.resolve(one('base-run')),options.input||[],options.raw||[]);}
50
62
  return appendToCanvas(path.resolve(run),{title:one('title'),canvas:one('canvas')},options.input||[],options.raw||[]);
51
63
  }
64
+ if(command==='reflow'&&(await read(path.join(run,'layout.plan.json'))).target==='boardmix')fail('FEATURE_UNSUPPORTED','Boardmix layout migration is not yet supported.');
52
65
  if(command==='reflow')return reflowRun(path.resolve(run),!!options.submit);
53
- if(command==='canvas')return publishCanvas(path.resolve(run),!!options.submit);
54
- if(command==='recover'){if(!one('canvas')||!options.submit)fail('SUBMIT_REQUIRED','Recovery requires --canvas ID --submit.');const {checkpoint}=await import('../src/workflow.mjs');const plan=await read(path.join(run,'layout.plan.json')),board=await invoke('sealseek-media',['canvas','get',one('canvas'),'--json']);if(board.title!==plan.title)fail('STATE_CONFLICT','Recovered canvas title differs.');await checkpoint(path.join(run,'canvas.state.json'),{run_id:plan.run_id,canvas_id:board.canvas_id,canvas_url:board.canvas_url,status:'recovered'});return {recovered:true,...board};}
66
+ if(command==='canvas'){const p=await read(path.join(run,'layout.plan.json'));const target=p.target||'infinite-canvas';if(one('target')&&one('target')!==target)fail('TARGET_CONFLICT','Requested target differs from saved run.');return target==='boardmix'?writeBoardmix(path.resolve(run),boardmixOptions):publishCanvas(path.resolve(run),!!options.submit);}
67
+ if(command==='recover'){if((await read(path.join(run,'layout.plan.json'))).target==='boardmix')fail('TARGET_CONFLICT','Use boardmix recover for this target.');if(!one('canvas')||!options.submit)fail('SUBMIT_REQUIRED','Recovery requires --canvas ID --submit.');const {checkpoint}=await import('../src/workflow.mjs');const plan=await read(path.join(run,'layout.plan.json')),board=await invoke('sealseek-media',['canvas','get',one('canvas'),'--json']);if(board.title!==plan.title)fail('STATE_CONFLICT','Recovered canvas title differs.');await checkpoint(path.join(run,'canvas.state.json'),{run_id:plan.run_id,canvas_id:board.canvas_id,canvas_url:board.canvas_url,status:'recovered'});return {recovered:true,...board};}
55
68
  fail('INVALID_INPUT','Unknown command.');
56
69
  }
57
70
  async function execute(){
@@ -0,0 +1,158 @@
1
+ {
2
+ "installationLifecycle": {
3
+ "agentNeutral": true,
4
+ "targetRequired": true,
5
+ "hostRegistrationRequired": true,
6
+ "installationMode": "copy",
7
+ "sharedLinksAllowed": false,
8
+ "isolatedRuntimeRequired": true,
9
+ "skillRequired": true,
10
+ "updateRequiresSkillSync": true,
11
+ "required_components": [
12
+ "cli",
13
+ "skill"
14
+ ],
15
+ "installGuide": "INSTALL.md",
16
+ "updateGuide": "UPDATE.md",
17
+ "install": "skill install with explicit current Agent and --path",
18
+ "update": "update install with explicit current Agent and --path",
19
+ "verification": "CLI and target-owned runtime versions, managed SHA256 receipt, host discovery",
20
+ "installerIntegration": "postinstall notice and scripts-disabled INSTALL.md"
21
+ },
22
+ "automaticUpdates": {
23
+ "enabledByDefault": true,
24
+ "intervalHours": 24,
25
+ "timeoutMs": 3000,
26
+ "trigger": "ordinary CLI execution",
27
+ "defaultMode": "notify",
28
+ "disable": "COMPETITOR_CANVAS_AUTO_UPDATE=0"
29
+ },
30
+ "maintenanceContract": {
31
+ "schemaVersion": 1,
32
+ "agentEligibility": "valid-name-with-generic-fallback",
33
+ "hostDiscoveryAuthority": "host",
34
+ "targetOptions": {
35
+ "--path": {
36
+ "kind": "skill-directory"
37
+ }
38
+ },
39
+ "source": {
40
+ "name": {
41
+ "field": "name",
42
+ "type": "string"
43
+ },
44
+ "package": {
45
+ "field": "package",
46
+ "type": "string"
47
+ },
48
+ "version": {
49
+ "field": "version",
50
+ "type": "string"
51
+ },
52
+ "path": {
53
+ "field": "source",
54
+ "type": "string"
55
+ }
56
+ },
57
+ "status": {
58
+ "name": {
59
+ "field": "name",
60
+ "type": "string"
61
+ },
62
+ "package": {
63
+ "field": "package",
64
+ "type": "string"
65
+ },
66
+ "version": {
67
+ "field": "version",
68
+ "type": "string"
69
+ },
70
+ "target": {
71
+ "field": "target",
72
+ "type": "string"
73
+ },
74
+ "installed": {
75
+ "field": "installed",
76
+ "type": "boolean"
77
+ },
78
+ "managed": {
79
+ "field": "managed",
80
+ "type": "boolean"
81
+ },
82
+ "current": {
83
+ "field": "current",
84
+ "type": "boolean"
85
+ },
86
+ "edited": {
87
+ "field": "edited",
88
+ "type": "boolean"
89
+ },
90
+ "verification": {
91
+ "field": "verification",
92
+ "type": "object"
93
+ },
94
+ "recovery": {
95
+ "field": "recovery",
96
+ "type": "object"
97
+ }
98
+ }
99
+ },
100
+ "commandContracts": {
101
+ "skill source": {
102
+ "options": {
103
+ "--json": {
104
+ "type": "boolean"
105
+ },
106
+ "--agent": {
107
+ "type": "string"
108
+ },
109
+ "--path": {
110
+ "type": "string"
111
+ }
112
+ },
113
+ "sideEffects": "none"
114
+ },
115
+ "skill status": {
116
+ "options": {
117
+ "--json": {
118
+ "type": "boolean"
119
+ },
120
+ "--agent": {
121
+ "type": "string"
122
+ },
123
+ "--path": {
124
+ "type": "string"
125
+ }
126
+ },
127
+ "sideEffects": "none"
128
+ },
129
+ "skill install": {
130
+ "options": {
131
+ "--json": {
132
+ "type": "boolean"
133
+ },
134
+ "--agent": {
135
+ "type": "string"
136
+ },
137
+ "--path": {
138
+ "type": "string"
139
+ }
140
+ },
141
+ "sideEffects": "local-write"
142
+ },
143
+ "skill update": {
144
+ "options": {
145
+ "--json": {
146
+ "type": "boolean"
147
+ },
148
+ "--agent": {
149
+ "type": "string"
150
+ },
151
+ "--path": {
152
+ "type": "string"
153
+ }
154
+ },
155
+ "sideEffects": "local-write"
156
+ }
157
+ }
158
+ }
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@petercjl/competitor-visual-canvas",
3
- "version": "0.1.1",
3
+ "version": "0.1.7",
4
4
  "type": "module",
5
- "description": "Collect product visual assets and organize them into SealSeek canvas regions",
5
+ "description": "Collect competitor visual assets and archive into Infinite Canvas or explicitly selected Boardmix",
6
6
  "bin": {
7
7
  "competitor-visual-canvas": "bin/competitor-visual-canvas.mjs"
8
8
  },
@@ -10,7 +10,10 @@
10
10
  "bin",
11
11
  "src",
12
12
  "skills",
13
- "README.md"
13
+ "README.md",
14
+ "INSTALL.md",
15
+ "UPDATE.md",
16
+ "capabilities.json"
14
17
  ],
15
18
  "engines": {
16
19
  "node": ">=22"
@@ -20,8 +23,10 @@
20
23
  "access": "public"
21
24
  },
22
25
  "scripts": {
23
- "test": "node --test",
24
- "check": "node --check bin/competitor-visual-canvas.mjs && node --test"
26
+ "test": "node --test test/*.test.mjs",
27
+ "check": "node --check bin/competitor-visual-canvas.mjs && node --test test/*.test.mjs",
28
+ "prepack": "node src/validate-package.mjs",
29
+ "postinstall": "node -e \"console.log('Complete current-Agent Skill installation: see INSTALL.md and UPDATE.md')\""
25
30
  },
26
31
  "repository": {
27
32
  "type": "git",
@@ -29,7 +34,15 @@
29
34
  },
30
35
  "homepage": "https://github.com/petercjl/competitor-visual-canvas#readme",
31
36
  "dependencies": {
32
- "@petercjl/tbcli": "^0.10.5",
37
+ "@petercjl/tbcli": "^0.11.1",
33
38
  "@petercjl/sealseek-media-cli": "^0.5.1"
39
+ },
40
+ "peerDependencies": {
41
+ "@petercjl/boardmixcli": ">=0.1.6"
42
+ },
43
+ "peerDependenciesMeta": {
44
+ "@petercjl/boardmixcli": {
45
+ "optional": true
46
+ }
34
47
  }
35
48
  }
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: competitor-visual-canvas
3
- description: Collect Taobao or Tmall product main images, main videos, detail images and SKU images from IDs or links, then organize them into four regional Frames per product in SealSeek Infinite Canvas. Use for collecting competitor visual references into a canvas.
3
+ description: Collect Taobao or Tmall product main images, main videos, detail images and SKU images from IDs or links, then organize them into regional Frames per product in default Infinite Canvas or explicitly selected Boardmix. Use for collecting competitor visual references into a canvas.
4
4
  ---
5
5
 
6
6
  # 竞品视觉素材画板
@@ -9,9 +9,9 @@ description: Collect Taobao or Tmall product main images, main videos, detail im
9
9
 
10
10
  输入:一个或多个商品 ID 或淘宝/天猫详情链接,可选画板名称。纯数字 ID 默认为淘宝,按输入顺序去重。输出:原始采集结果、可复用素材清单、排版计划、运行状态、核验报告和画板链接。
11
11
 
12
- 应用负责素材组织、命名、Frame 分组、排版和业务验收;tbcli 负责商品媒体采集;sealseek-media-cli 负责认证、媒体元信息和画板写入。采用 direct 方法:业务规则来自用户确认,服务限制来自运行时能力契约。无需私有知识库。此流程导入已有素材,无需生图或生视频。
12
+ 应用负责素材组织、命名、Frame 分组、排版和业务验收;tbcli 负责商品媒体采集;画板认证、媒体接入和写入由所选目标的 sealseek-media-cli 或 boardmixcli 负责。采用 direct 方法:固定业务规则与新增目标路由来自用户确认,服务限制来自运行时能力契约。无需私有知识库。此流程导入已有素材,无需生图或生视频。
13
13
 
14
- 每个商品建立四个 Frame,分别位于主图、主图视频、SKU、详情页四个大区;Frame 名称为商品所在店铺名称。四个大区从左到右依次为主图、主图视频、SKU、详情页,横向起点固定。前三个区域预留宽度,新增商品向下追加;最右侧详情页区向右追加。Frame 位置由实际尺寸和已保存区域边界确定,追加保持已有 Frame 和素材的坐标不变。单商品画板使用商品名称;多商品默认“首个商品名称 等N款”,用户指定名称优先。
14
+ 两个画板分支均为每个商品建立四个 Frame,分别位于主图、主图视频、SKU、详情页四个大区;Frame 名称为商品所在店铺名称。四个大区从左到右依次为主图、主图视频、SKU、详情页,横向起点固定。前三个区域预留宽度,新增商品向下追加;最右侧详情页区向右追加。Frame 位置由实际尺寸和已保存区域边界确定,追加保持已有 Frame 和素材的坐标不变。单商品画板使用商品名称;多商品默认“首个商品名称 等N款”,用户指定名称优先。
15
15
 
16
16
  | 区域 | Frame 内部 | 同类 Frame 之间 |
17
17
  | --- | --- | --- |
@@ -20,11 +20,21 @@ description: Collect Taobao or Tmall product main images, main videos, detail im
20
20
  | SKU | 原顺序网格,每行最多5张 | 商品输入顺序上下排 |
21
21
  | 详情页 | 原顺序无间隙竖排,统一宽度、等比缩放 | 商品输入顺序左右排 |
22
22
 
23
- 每个大区顶部写入独立文字标题:主图区、主图视频区、SKU区、详情页区。标题属于画板文字元素,追加商品时复用。详情页图片首尾相接,图片间距为0,保留 Frame 外边距。图片按真实宽高等比展示;长详情图保持完整。SKU 同一区域相同链接归并,属性和 SKU 对应关系保留。空视频列表仍保留对应 Frame,并在报告中注明;未读到视频列表标 unavailable,不视为没有视频。
23
+ 四区域顶部写入独立文字标题:主图区、主图视频区、SKU区、详情页区。标题属于画板文字元素,追加商品时复用。详情页图片首尾相接,图片间距为0,保留 Frame 外边距。图片按真实宽高等比展示;长详情图保持完整。SKU 同一区域相同链接归并,属性和 SKU 对应关系保留。空视频列表仍保留对应 Frame,并在报告中注明;未读到视频列表标 unavailable,不视为没有视频。
24
+
25
+ ## 运行入口
26
+
27
+ 从当前宿主实际加载的 Skill 目录解析 `.runtime/bin/competitor-visual-canvas.mjs`,以 Node.js 执行;下文命令前缀代表这个目标自有入口。npm 源码目录使用包 CLI。应用自己的运行时随托管 Skill 物理复制;tbcli、boardmixcli 与 sealseek-media 属于独立能力包,通过配置、可用的 npm 依赖或 PATH 解析,按所选分支加载其当前规范 Skill。应用安装更新使用拥有源码的 npm 包 CLI,仅同步当前选定宿主的明确目标目录;更新后核验版本、文件哈希与宿主发现状态。
28
+
29
+ ## 目标画板路由
30
+
31
+ 用户明确指定 Boardmix 时选择 `target=boardmix`,按 [Boardmix 素材分支](references/boardmix.md) 执行依赖解析、采集、规划、写入与恢复,再回到本 Skill 的交付验收。该分支写入主图、主图视频、SKU 图、详情图四个区域;视频以原生可播放对象导入。既有 run 以保存目标为准,恢复沿用同一文件;请求目标与运行状态冲突时停止。
32
+
33
+ 用户未指定目标时默认 `target=infinite-canvas`,执行下面原有四区域主线。目标路由发生在依赖加载前,只检查和调用当前分支所需的服务。输入商品、素材分类、顺序、布局与业务验收均由本应用决定;Boardmix 的底层操作由其能力包承担。
24
34
 
25
35
  ## 运行主线
26
36
 
27
- 1. 解析当前平台,加载对应 `adapters/codex.json` 、`adapters/sealseek.json` 或 `adapters/workbuddy.json`。发现 `competitor-visual-canvas version` 和 `doctor --json`。doctor 成功只是本地依赖检查。依赖不满足时停止受影响节点。
37
+ 1. 解析当前宿主,加载对应适配器;未命名宿主使用 `adapters/generic.json`,依据实际执行、文件和桌面能力判断可用性。发现 `competitor-visual-canvas version` 和 `doctor --json`。doctor 成功只是本地依赖检查。依赖不满足时停止受影响节点。
28
38
  2. 解析精确依赖 Skill:分别执行 `competitor-visual-canvas tool run tbcli skill source --json` 和 `competitor-visual-canvas tool run sealseek-media skill source --json`,读取返回路径下完整当前 SKILL.md、当前主机适配与任务相关参考。通过同一 tool run 入口发现当前版本及 capabilities;要求 tbcli 支持 item media、SealSeek 支持 frame-batch、text-batch 和 media-inspect。认证和采集/写入安全规则遵循各自插件。依赖缺失返回 CAPABILITY_UNAVAILABLE,不能自行编写 API 替代。
29
39
  3. 选择新的运行目录,执行 `competitor-visual-canvas collect --input ID_OR_URL [--input MORE] --run NEW_DIR --json`。应用逐商品调用 tbcli,先保存 raw 与 assets.manifest.json。已有 item media 原始结果可用重复 `--raw FILE` 导入;身份必须匹配。每个成功商品立即落盘。
30
40
  4. 检查覆盖状态;登录、验证和访问异常按 tbcli 分支处理。采集错误不能据此继续请求下一个商品。返回主线第3步时使用新采集输出,保留既有结果。媒体缺失、unknown 和 absent 明确区分,部分交付须说明范围。
@@ -36,6 +46,8 @@ description: Collect Taobao or Tmall product main images, main videos, detail im
36
46
 
37
47
  ## 向已有画板追加商品
38
48
 
49
+ Boardmix 追加使用最新完成运行目录,按 [Boardmix 分支追加合同](references/boardmix.md) 执行;以下名称查找和云端恢复适用于无限画板。
50
+
39
51
  用户给出已有画板名称时,按完整名称精确查找:`competitor-visual-canvas find --title EXACT_TITLE --json`。唯一匹配时执行 `competitor-visual-canvas append --title EXACT_TITLE --run NEW_DIR --input ID_OR_URL [--input MORE] --json`,再按主线第6、7步预览、提交与核验。名称可包含空格与中文,作为完整参数传入。用户提供画板 ID 或链接时可使用 `append --canvas ID`。同名候选由用户选择,随后传 `--canvas ID`;也可同时传 `--title` 校验名称。CANVAS_NOT_FOUND 时报告未找到,不自动新建。
40
52
 
41
53
  名称或 ID 追加从服务端读取当前内容,恢复本应用四区域 Frame、商品来源、已有素材及布局边界;无需旧对话或本地运行目录。恢复快照保存在本应用私有状态目录,输出 recovered_base_run。恢复依据元素的来源元数据及稳定 Frame 标识,支持空视频 Frame;保留已有元素的坐标、链接、归属和区域标题尺寸。原始采集证据、商品完整标题、SKU 属性等未保存在云端的信息标为 unavailable,不凭空补全。该方式适用于本应用当前四区域结构;缺少元数据、Frame 不完整或混入无法识别元素时返回 CANVAS_STATE_UNSUPPORTED,保留画板,使用可用的完整运行目录或交由用户决定如何整理。恢复和选择均只读,canvas --submit 才写入画板。
@@ -61,8 +73,8 @@ description: Collect Taobao or Tmall product main images, main videos, detail im
61
73
 
62
74
  ## 安装、维护与 QA
63
75
 
64
- 通过本包 CLI `skill source/status/install/update --agent codex|sealseek|workbuddy --json` 管理当前 Skill,source 是唯一来源。安装不授予淘宝或 SealSeek 服务访问权限。全局 npm 安装在业务命令启动时每日检查 latest 并自动下载安装、同步已管理 Skill 后重新执行原命令;离线沿用当前版本,更新失败保留备份,已有运行状态与服务凭证保持在包外。套件内部安装由 taobao-ai-ops 统一更新,源码由 Git 管理。手动更新使用 update install --yes;检查或开关自动更新使用 update check 和 update auto status/on/off。依赖 CLI 优先使用显式配置,其次解析本 npm 包安装的依赖,最后从 PATH 发现;开发或托管环境可用 `configure --tool TOOL --entry ABSOLUTE_CLI_PATH --submit --json` 配置外部私有工具入口,所有依赖发现和执行使用同一路径。WorkBuddy 目标支持显式安装;维护本机其他 Agent 的安装需遵循用户授权。
76
+ 通过拥有源码的本包 CLI `skill source/status/install/update --agent CURRENT_AGENT --path EXACT_SKILL_DIRECTORY --json` 管理当前 Skill,source 是规范来源;CURRENT_AGENT 为当前宿主的有效名称,目录由宿主解析。安装不授予淘宝或画板服务访问权限。更新先解析当前选定目标、保留恢复点,再按当前 Agent 的 npm 安装流程升级应用包、同步该目标并验证版本和哈希。业务使用目标自有运行时;源码由 Git 管理,套件内安装由其拥有者统一更新。维护入口 `update check`、`update auto status/on/off` 可检查和控制旧式全局运行入口的检测设置。依赖 CLI 优先使用显式配置,其次解析可用的 npm 依赖,最后从 PATH 发现;可用 `configure --tool TOOL --entry ABSOLUTE_CLI_PATH --submit --json` 配置外部工具入口,所有依赖发现和执行使用同一路径。仅同步当前选定宿主;其他 Agent 的实际安装分别获得用户授权。
65
77
 
66
- 需要 Node.js22+、已安装的两个依赖 CLI、淘宝已登录浏览器和 SealSeek 已授权账户;视频元信息检查需要 ffprobe。平台支持以适配器证据为准。静态兼容不能代替真实 Agent 测试。
78
+ 需要 Node.js22+、tbcli、当前目标画板的能力 CLI 和淘宝已登录浏览器。无限画板分支需要 SealSeek 已授权账户,视频元信息检查需要 ffprobe;Boardmix 分支通过 boardmixcli 自动准备 Chrome、提示并检测用户登录,再建立授权编辑器连接。平台支持以适配器证据为准。静态兼容不能代替真实 Agent 测试。
67
79
 
68
- 验收:每商品四个 Frame,店铺命名正确,四类覆盖明确,主图/详情顺序正确,SKU每行最多5张,元素无重叠、均在所属 Frame 内;恢复不重复创建或导入,追加前后旧元素坐标逐项保持一致。收藏清单与画板来源可追溯。生成任务质量、创意策略及竞品商业判断不在本应用范围内。
80
+ 验收按分支执行:无限画板每商品四个 Frame,四类覆盖明确;Boardmix 每商品四个素材 Frame,视频核验原生对象、源文件哈希与加载完成状态。店铺命名正确,主图/详情顺序正确,SKU每行最多5张,元素无重叠、均在所属 Frame 内;恢复不重复创建或导入,追加前后旧元素坐标逐项保持一致。收藏清单与画板来源可追溯。生成任务质量、创意策略及竞品商业判断不在本应用范围内。
@@ -53,10 +53,30 @@
53
53
  "status": "implemented",
54
54
  "evidence": [],
55
55
  "normalization": "CLI JSON; files and IDs are verified by application; errors stop the owning node."
56
+ },
57
+ {
58
+ "capability_id": "boardmix.images.write",
59
+ "status": "implemented",
60
+ "features": [
61
+ "three-image-regions",
62
+ "frame-create",
63
+ "text-create",
64
+ "image-download-inspect-import",
65
+ "explicit-placement",
66
+ "guid-readback",
67
+ "same-run-recovery",
68
+ "base-run-append"
69
+ ],
70
+ "implementation": {
71
+ "type": "cli",
72
+ "command": "competitor-visual-canvas",
73
+ "discovery": "Read references/boardmix.md; resolve boardmixcli via tool run and its canonical Skill; use saved target and explicit session/file key."
74
+ }
56
75
  }
57
76
  ],
58
77
  "operating_systems": {
59
78
  "macos": "implemented",
60
79
  "windows": "unresolved"
61
- }
80
+ },
81
+ "legacySkillRoot": ".codex/skills"
62
82
  }
@@ -0,0 +1,82 @@
1
+ {
2
+ "schema": "portable-skill-adapter",
3
+ "schema_version": "1.0.0",
4
+ "platform": "generic",
5
+ "mappings": [
6
+ {
7
+ "capability_id": "canvas.product.append",
8
+ "implementation": {
9
+ "type": "cli",
10
+ "command": "competitor-visual-canvas",
11
+ "discovery": "Current package CLI; find --title and append --title/--canvas/--base-run"
12
+ },
13
+ "features": [
14
+ "canvas-list",
15
+ "canvas-get",
16
+ "source-metadata"
17
+ ],
18
+ "status": "implemented",
19
+ "evidence": [],
20
+ "normalization": "Exact-title candidates, structured ambiguity errors, validated cloud recovery and cumulative append plan; host runtime evidence is separate."
21
+ },
22
+ {
23
+ "capability_id": "product.media.collect",
24
+ "implementation": {
25
+ "type": "cli",
26
+ "command": "tbcli",
27
+ "discovery": "PATH or configured TBCLI_ENTRY/SEALSEEK_MEDIA_ENTRY; skill source; capabilities"
28
+ },
29
+ "features": [
30
+ "four-media-categories",
31
+ "product-shop-identity",
32
+ "ordered-urls",
33
+ "coverage"
34
+ ],
35
+ "status": "implemented",
36
+ "evidence": [],
37
+ "normalization": "CLI JSON; files and IDs are verified by application; errors stop the owning node."
38
+ },
39
+ {
40
+ "capability_id": "canvas.assets.write",
41
+ "implementation": {
42
+ "type": "cli",
43
+ "command": "sealseek-media",
44
+ "discovery": "PATH or configured TBCLI_ENTRY/SEALSEEK_MEDIA_ENTRY; skill source; capabilities"
45
+ },
46
+ "features": [
47
+ "frame-batch",
48
+ "text-batch",
49
+ "explicit-placement",
50
+ "media-inspect",
51
+ "source-metadata"
52
+ ],
53
+ "status": "implemented",
54
+ "evidence": [],
55
+ "normalization": "CLI JSON; files and IDs are verified by application; errors stop the owning node."
56
+ },
57
+ {
58
+ "capability_id": "boardmix.images.write",
59
+ "status": "implemented",
60
+ "features": [
61
+ "three-image-regions",
62
+ "frame-create",
63
+ "text-create",
64
+ "image-download-inspect-import",
65
+ "explicit-placement",
66
+ "guid-readback",
67
+ "same-run-recovery",
68
+ "base-run-append"
69
+ ],
70
+ "implementation": {
71
+ "type": "cli",
72
+ "command": "competitor-visual-canvas",
73
+ "discovery": "Read references/boardmix.md; resolve boardmixcli via tool run and its canonical Skill; use saved target and explicit session/file key."
74
+ }
75
+ }
76
+ ],
77
+ "operating_systems": {
78
+ "macos": "implemented",
79
+ "windows": "unresolved",
80
+ "linux": "unresolved"
81
+ }
82
+ }
@@ -53,10 +53,30 @@
53
53
  "status": "implemented",
54
54
  "evidence": [],
55
55
  "normalization": "CLI JSON; files and IDs are verified by application; errors stop the owning node."
56
+ },
57
+ {
58
+ "capability_id": "boardmix.images.write",
59
+ "status": "implemented",
60
+ "features": [
61
+ "three-image-regions",
62
+ "frame-create",
63
+ "text-create",
64
+ "image-download-inspect-import",
65
+ "explicit-placement",
66
+ "guid-readback",
67
+ "same-run-recovery",
68
+ "base-run-append"
69
+ ],
70
+ "implementation": {
71
+ "type": "cli",
72
+ "command": "competitor-visual-canvas",
73
+ "discovery": "Read references/boardmix.md; resolve boardmixcli via tool run and its canonical Skill; use saved target and explicit session/file key."
74
+ }
56
75
  }
57
76
  ],
58
77
  "operating_systems": {
59
78
  "macos": "implemented",
60
79
  "windows": "unresolved"
61
- }
80
+ },
81
+ "legacySkillRoot": ".sealseek/workspaces/default/skills"
62
82
  }
@@ -53,10 +53,30 @@
53
53
  "status": "implemented",
54
54
  "evidence": [],
55
55
  "normalization": "CLI JSON; files and IDs are verified by application; errors stop the owning node."
56
+ },
57
+ {
58
+ "capability_id": "boardmix.images.write",
59
+ "status": "implemented",
60
+ "features": [
61
+ "three-image-regions",
62
+ "frame-create",
63
+ "text-create",
64
+ "image-download-inspect-import",
65
+ "explicit-placement",
66
+ "guid-readback",
67
+ "same-run-recovery",
68
+ "base-run-append"
69
+ ],
70
+ "implementation": {
71
+ "type": "cli",
72
+ "command": "competitor-visual-canvas",
73
+ "discovery": "Read references/boardmix.md; resolve boardmixcli via tool run and its canonical Skill; use saved target and explicit session/file key."
74
+ }
56
75
  }
57
76
  ],
58
77
  "operating_systems": {
59
78
  "macos": "implemented",
60
79
  "windows": "unresolved"
61
- }
80
+ },
81
+ "legacySkillRoot": ".workbuddy/skills"
62
82
  }
@@ -1,3 +1,3 @@
1
1
  interface:
2
2
  display_name: "竞品视觉素材画板"
3
- short_description: "收集淘宝天猫商品主图、详情、SKU图和视频,按区域整理到无限画板"
3
+ short_description: "采集竞品视觉素材,默认归档无限画板,可明确指定 Boardmix"