best-geo-test 2.0.0-beta.2 → 2.0.2

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.
@@ -235,7 +235,7 @@
235
235
  "maxLength": 255
236
236
  },
237
237
  "maxItems": 100,
238
- "description": "问题文本数组,不是换行字符串"
238
+ "description": "问题文本数组,不是换行字符串。每条里不能带换行,带了会被服务端拒绝——一条问题就是一个数组元素"
239
239
  },
240
240
  "tags": {
241
241
  "type": "array",
@@ -3657,7 +3657,7 @@
3657
3657
  "mode": "read",
3658
3658
  "guide": "publication",
3659
3659
  "requiresPlan": false,
3660
- "description": "单个媒体的实时状态与当前价格。**报价给用户前必须查这条**——列表是分页快照,遇上刚调过价就会和实际扣费对不上。",
3660
+ "description": "单个媒体的实时状态与当前价格。**报价给用户前必须查这条**——列表是分页快照,遇上刚调过价就会和实际扣费对不上。**单位注意**:这里的价格字段是 points,单位是算力(1 元 = 100 算力);mediaPlatforms.list 的 price 和 plan 摘要里的金额单位都是元。给用户报价时统一换算成元,例如 points=5000 就是 50 元。",
3661
3661
  "inputSchema": {
3662
3662
  "type": "object",
3663
3663
  "properties": {
@@ -3890,7 +3890,7 @@
3890
3890
  "mode": "write",
3891
3891
  "guide": "publication",
3892
3892
  "requiresPlan": true,
3893
- "description": "删发布任务。只删任务和它名下**还没发出去**的记录——已经发布成功的稿子留在平台上不受影响,要撤那些得去各平台自己删。一次只能删当前 GEO 项目的。",
3893
+ "description": "删发布任务。普通任务只删任务和它名下**还没发出去**的记录——已经发布成功的稿子留在平台上不受影响,要撤那些得去各平台自己删。**例外:外部导入的任务**(publicationTasks.list 里 typeLabel=外部导入)会连同名下已发布的记录一起删掉,收录统计也会跟着减少,计划摘要里会单独写出来,必须念给用户。一次只能删当前 GEO 项目的。",
3894
3894
  "inputSchema": {
3895
3895
  "type": "object",
3896
3896
  "properties": {
@@ -3938,6 +3938,39 @@
3938
3938
  "additionalProperties": false
3939
3939
  }
3940
3940
  },
3941
+ {
3942
+ "name": "publicationTasks.importLinks",
3943
+ "mode": "write",
3944
+ "guide": "publication",
3945
+ "requiresPlan": true,
3946
+ "description": "导入用户**已经在外面发出去**的文章链接,登记成一个「外部导入」发布任务,让这些链接参与收录匹配和统计。不扣费,也不会往任何平台发东西。articleId 和 title 必须且只能给一个:链接发的是系统里已有的文章就给 articleId;在外面写的给 title,会新建一篇只有标题的外部文章(之后不能再拿去发布或投稿)。计划里会逐条写明哪条能导、哪条跳过及原因(链接无效、网站暂不支持提取文章 ID、已经导入或发布过),念给用户再确认;一条都导不了时 plan 直接报错。",
3947
+ "inputSchema": {
3948
+ "type": "object",
3949
+ "properties": {
3950
+ "projectId": { "type": "integer", "minimum": 1, "description": "GEO 项目 id,来自 projects.list" },
3951
+ "urls": {
3952
+ "type": "array",
3953
+ "minItems": 1,
3954
+ "maxItems": 20,
3955
+ "items": { "type": "string", "minLength": 1 },
3956
+ "description": "外部文章链接,一次最多 20 条,用户给的原样传入"
3957
+ },
3958
+ "articleId": {
3959
+ "type": "integer",
3960
+ "minimum": 1,
3961
+ "description": "链接对应系统里已有的哪篇文章,来自 articles.list,必须属于当前 GEO 项目。和 title 二选一"
3962
+ },
3963
+ "title": {
3964
+ "type": "string",
3965
+ "minLength": 1,
3966
+ "maxLength": 255,
3967
+ "description": "外面写的文章标题,用来新建一篇外部文章。和 articleId 二选一"
3968
+ }
3969
+ },
3970
+ "required": ["projectId", "urls"],
3971
+ "additionalProperties": false
3972
+ }
3973
+ },
3941
3974
  {
3942
3975
  "name": "mediaPublications.create",
3943
3976
  "mode": "write",
@@ -3982,7 +4015,7 @@
3982
4015
  "name": "textToImages.models",
3983
4016
  "mode": "read",
3984
4017
  "guide": "material",
3985
- "description": "列出可用的 AI 出图档位。不同档位计费不同(返回里的 toolScore 是计费口径),建图之前先调这个看有哪些能用。",
4018
+ "description": "列出可用的 AI 出图档位。不同档位计费不同(返回里的 toolScore 是计费口径),建图之前先调这个看有哪些能用。maxInputImages 是这个档位最多能喂几张输入图(0 表示不支持参考图),答案卡选参考图前要用它算上限。",
3986
4019
  "inputSchema": { "type": "object", "properties": {}, "additionalProperties": false }
3987
4020
  },
3988
4021
  {
@@ -4486,7 +4519,7 @@
4486
4519
  "visualMode": {
4487
4520
  "type": "integer",
4488
4521
  "enum": [1, 2, 3],
4489
- "description": "视觉方式:1 AI 智能匹配(后端从可用模板里自动挑一套,不用再给 templateId 或 customStylePrompt)/ 2 指定模板(需一并给 templateId)/ 3 自定义风格(需一并给 customStylePrompt)"
4522
+ "description": "视觉方式:1 AI 智能匹配(后端从可用模板里自动挑一套,不用再给 templateId 或 customStylePrompt)/ 2 指定模板(需一并给 templateId)/ 3 自定义风格(需一并给 customStylePrompt)。1 和 2 要把模板图喂给模型,所选档位的 maxInputImages 为 0 时只能用 3"
4490
4523
  },
4491
4524
  "templateId": {
4492
4525
  "type": "integer",
@@ -4515,7 +4548,7 @@
4515
4548
  "type": "integer",
4516
4549
  "minimum": 1
4517
4550
  },
4518
- "description": "参考素材图 id 列表,有序,用 images.list 查,最多 10 张"
4551
+ "description": "参考素材图 id 列表,有序,用 images.list 查。**真实上限看所选档位**:textToImages.models 里该档位的 maxInputImages;visualMode=1 或 2 时模板图要先占 1 张,用户能给的再少 1 张。超了 plan 能过、apply 会被拒,所以 plan 前先算好"
4519
4552
  }
4520
4553
  },
4521
4554
  "required": ["projectId", "sourceType", "visualMode", "richness", "modelCode"],
package/dist/index.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- "use strict";var jt=Object.defineProperty;var Vt=(e,t,n)=>t in e?jt(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n;var se=(e,t,n)=>Vt(e,typeof t!="symbol"?t+"":t,n);var ae="https://nbgeo.aimusiclj.com",Oe="best-geo-test",$e="best-geo-test",Ne="bg-test-cli-",Pe="2.0.0-beta.2";var B=2,k=Pe,D=$e,p=Oe,Le="dev",J=Bt(Ft());function Ft(){var e;return(e=process.env.BEST_GEO_API_BASE)!=null?e:ae}var Q=Ne,De=300*1e3,Ue=30*1e3,Me=300*1e3;function Bt(e){return e.replace(/\/+$/,"")}var tt=require("node:child_process");var Ge=require("node:crypto"),X=require("node:os");var d=require("node:fs"),je=require("node:os"),A=require("node:path");var le=require("node:crypto");var _=class extends Error{constructor(n,r,o){super(o);se(this,"reason",n);se(this,"path",r);this.name="LocalConfigError"}},qt={schemaVersion:1,device:null,activeCredential:null,pendingCredential:null};function q(){var e;return(e=process.env.BEST_GEO_CONFIG_DIR)!=null?e:(0,A.join)((0,je.homedir)(),`.${p}`)}function O(){return(0,A.join)(q(),"config.json")}function C(){var n,r,o;let e=O(),t;try{if(!(0,d.existsSync)(e))return null;Gt(e),t=(0,d.readFileSync)(e,"utf8")}catch(i){throw i instanceof _?i:Ve(i,e)}try{let i=JSON.parse(t);if(typeof i!="object"||i==null||i.schemaVersion!==1)throw new Error("unexpected shape");return{schemaVersion:1,device:(n=i.device)!=null?n:null,activeCredential:(r=i.activeCredential)!=null?r:null,pendingCredential:(o=i.pendingCredential)!=null?o:null}}catch{throw new _("corrupted",e,`\u672C\u673A\u914D\u7F6E\u6587\u4EF6\u5185\u5BB9\u4E0D\u5B8C\u6574\u6216\u683C\u5F0F\u4E0D\u5BF9\uFF1A${e}`)}}function Kt(e){let t=q(),n=O(),r=(0,A.join)(t,`.config.json.${(0,le.randomBytes)(6).toString("hex")}.tmp`);try{(0,d.existsSync)(t)||(0,d.mkdirSync)(t,{recursive:!0,mode:448});let o=(0,d.openSync)(r,"wx",384);try{(0,d.writeSync)(o,`${JSON.stringify(e,null,2)}
2
+ "use strict";var jt=Object.defineProperty;var Vt=(e,t,n)=>t in e?jt(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n;var se=(e,t,n)=>Vt(e,typeof t!="symbol"?t+"":t,n);var ae="https://nbgeo.aimusiclj.com",Oe="best-geo-test",$e="best-geo-test",Ne="bg-test-cli-",Pe="2.0.2";var B=2,k=Pe,D=$e,p=Oe,Le="dev",J=Bt(Ft());function Ft(){var e;return(e=process.env.BEST_GEO_API_BASE)!=null?e:ae}var Q=Ne,De=300*1e3,Ue=30*1e3,Me=300*1e3;function Bt(e){return e.replace(/\/+$/,"")}var tt=require("node:child_process");var Ge=require("node:crypto"),X=require("node:os");var d=require("node:fs"),je=require("node:os"),A=require("node:path");var le=require("node:crypto");var _=class extends Error{constructor(n,r,o){super(o);se(this,"reason",n);se(this,"path",r);this.name="LocalConfigError"}},qt={schemaVersion:1,device:null,activeCredential:null,pendingCredential:null};function q(){var e;return(e=process.env.BEST_GEO_CONFIG_DIR)!=null?e:(0,A.join)((0,je.homedir)(),`.${p}`)}function O(){return(0,A.join)(q(),"config.json")}function C(){var n,r,o;let e=O(),t;try{if(!(0,d.existsSync)(e))return null;Gt(e),t=(0,d.readFileSync)(e,"utf8")}catch(i){throw i instanceof _?i:Ve(i,e)}try{let i=JSON.parse(t);if(typeof i!="object"||i==null||i.schemaVersion!==1)throw new Error("unexpected shape");return{schemaVersion:1,device:(n=i.device)!=null?n:null,activeCredential:(r=i.activeCredential)!=null?r:null,pendingCredential:(o=i.pendingCredential)!=null?o:null}}catch{throw new _("corrupted",e,`\u672C\u673A\u914D\u7F6E\u6587\u4EF6\u5185\u5BB9\u4E0D\u5B8C\u6574\u6216\u683C\u5F0F\u4E0D\u5BF9\uFF1A${e}`)}}function Kt(e){let t=q(),n=O(),r=(0,A.join)(t,`.config.json.${(0,le.randomBytes)(6).toString("hex")}.tmp`);try{(0,d.existsSync)(t)||(0,d.mkdirSync)(t,{recursive:!0,mode:448});let o=(0,d.openSync)(r,"wx",384);try{(0,d.writeSync)(o,`${JSON.stringify(e,null,2)}
3
3
  `),(0,d.fsyncSync)(o)}finally{(0,d.closeSync)(o)}(0,d.renameSync)(r,n)}catch(o){if((0,d.existsSync)(r))try{(0,d.unlinkSync)(r)}catch{}throw Ve(o,n)}}function T(e){var n;let t=e((n=C())!=null?n:{...qt});return Kt(t),t}function Gt(e){var r;if(process.platform==="win32")return;let t=(0,d.statSync)(e),n=(r=process.getuid)==null?void 0:r.call(process);if(n!=null&&t.uid!==n)throw new _("not_owner",e,`\u672C\u673A\u914D\u7F6E\u6587\u4EF6\u4E0D\u5C5E\u4E8E\u5F53\u524D\u7528\u6237\uFF1A${e}`);if((t.mode&63)!==0)throw new _("permissions_too_open",e,`\u672C\u673A\u914D\u7F6E\u6587\u4EF6\u6743\u9650\u8FC7\u5BBD\uFF08\u540C\u673A\u5176\u4ED6\u7528\u6237\u53EF\u8BFB\uFF09\uFF1A${e}`)}function Ve(e,t){let n=e==null?void 0:e.code;return n==="EACCES"||n==="EPERM"||n==="EROFS"?new _("denied",t,`\u6CA1\u6709\u6743\u9650\u8BFB\u5199\u672C\u673A\u914D\u7F6E\uFF1A${t}`):e instanceof Error?e:new Error(String(e))}var Fe=3600*1e3;function Be(){return(0,A.join)(q(),"pending-uploads")}var Ht=/^plan_[0-9a-zA-Z]+$/;function de(e){return Ht.test(e)?(0,A.join)(Be(),`${e}.json`):null}function W(e){var n;let t=de(e);if(t==null||!(0,d.existsSync)(t))return null;try{let r=JSON.parse((0,d.readFileSync)(t,"utf8"));return Date.now()-((n=r==null?void 0:r.createdAt)!=null?n:0)<Fe?r:null}catch{return null}}function qe(e,t){let n=de(e);if(n==null)throw new Error(`\u4E0D\u5408\u6CD5\u7684\u8BA1\u5212 ID:${e}`);let r=Be();(0,d.mkdirSync)(r,{recursive:!0,mode:448}),zt(r);let o=(0,A.join)(r,`.${e}.${(0,le.randomBytes)(6).toString("hex")}.tmp`);try{(0,d.writeFileSync)(o,JSON.stringify(t),{mode:384}),(0,d.renameSync)(o,n)}catch(i){if((0,d.existsSync)(o))try{(0,d.unlinkSync)(o)}catch{}throw i}}function Ke(e){let t=de(e);if(t!=null)try{(0,d.unlinkSync)(t)}catch{}}function zt(e){let t=(0,A.join)(q(),"pending-uploads.json");try{(0,d.existsSync)(t)&&(0,d.unlinkSync)(t)}catch{}let n;try{n=(0,d.readdirSync)(e)}catch{return}for(let r of n){if(r.endsWith(".tmp")){try{let i=(0,A.join)(e,r);Date.now()-(0,d.statSync)(i).mtimeMs>=Fe&&(0,d.unlinkSync)(i)}catch{}continue}if(!r.endsWith(".json"))continue;let o=r.slice(0,-5);if(W(o)==null)try{(0,d.unlinkSync)((0,A.join)(e,r))}catch{}}}function He(){var t,n;let e=(t=C())==null?void 0:t.device;return(n=e==null?void 0:e.deviceId)!=null&&n.startsWith(Q)?e.deviceId:null}function Y(){var r,o;let e={deviceName:(0,X.hostname)().slice(0,50),platform:`${(0,X.platform)()}-${process.arch}`},t=(r=C())==null?void 0:r.device;if((o=t==null?void 0:t.deviceId)!=null&&o.startsWith(Q))return t.deviceName===e.deviceName&&t.platform===e.platform?t:T(i=>({...i,device:{...t,...e}})).device;let n={deviceId:`${Q}${(0,Ge.randomUUID)()}`,...e};return T(i=>({...i,device:n})).device}function ze(){return`cli_${Date.now().toString(36)}${Math.random().toString(36).slice(2,8)}`}function E(e,t=ze()){return{ok:!0,code:"OK",requestId:t,data:e}}function l(e,t,n={}){var r;return{ok:!1,code:e,message:t,requestId:(r=n.requestId)!=null?r:ze(),...n.data==null?{}:{data:n.data},...n.nextAction==null?{}:{nextAction:n.nextAction}}}function a(e){process.stdout.write(`${JSON.stringify(e)}
4
4
  `),e.ok||(process.exitCode=1)}async function x(e,t={}){var i,s;let n=new URL(`${J}/v1/agent-cli${e}`);for(let[c,f]of Object.entries((i=t.query)!=null?i:{}))if(f!=null)for(let m of Array.isArray(f)?f:[f])n.searchParams.append(c,String(m));let r={"X-GEO-CLI-Version":k,"X-GEO-Protocol-Version":String(B),"X-GEO-CLI-Package":D};t.projectId!=null&&(r["X-Geo-Product-Id"]=String(t.projectId));let o=null;try{o=He()}catch{}o&&(r["X-Device-ID"]=o),t.apiKey&&(r.Authorization=`Bearer ${t.apiKey}`),t.body!=null&&(r["Content-Type"]="application/json");try{let c=await fetch(n,{method:(s=t.method)!=null?s:"GET",headers:r,body:t.body==null?void 0:JSON.stringify(t.body),signal:AbortSignal.timeout(t.isWrite?Me:Ue)}),f=await c.text();try{let m=JSON.parse(f);return Jt(m)?m:l("SERVER_ERROR",`\u670D\u52A1\u7AEF\u8FD4\u56DE\u4E86\u975E\u9884\u671F\u5185\u5BB9\uFF08HTTP ${c.status}\uFF09`,{data:{transportFailure:!0}})}catch{return l("SERVER_ERROR",`\u670D\u52A1\u7AEF\u8FD4\u56DE\u4E86\u975E\u9884\u671F\u5185\u5BB9\uFF08HTTP ${c.status}\uFF09`,{data:{transportFailure:!0}})}}catch(c){return c instanceof Error&&(c.name==="TimeoutError"||c.name==="AbortError")?l("SERVER_ERROR",t.isWrite?"\u670D\u52A1\u7AEF\u5904\u7406\u8D85\u65F6,\u8FD9\u6B21\u5199\u5165\u7ED3\u679C\u672A\u77E5":"\u670D\u52A1\u7AEF\u54CD\u5E94\u8D85\u65F6",{data:{transportFailure:!0},nextAction:t.isWrite?{type:"ask_user",message:"\u8D85\u65F6\u4E0D\u4EE3\u8868\u6CA1\u5199\u8FDB\u53BB \u2014\u2014 \u670D\u52A1\u7AEF\u53EF\u80FD\u8FD8\u5728\u5904\u7406\u3002**\u5148\u7528\u5BF9\u5E94\u7684\u67E5\u8BE2\u80FD\u529B\u786E\u8BA4\u4E00\u904D**,\u786E\u5B9E\u6CA1\u6709\u518D\u91CD\u65B0 plan;\u76F4\u63A5\u91CD\u8BD5\u4F1A\u5EFA\u51FA\u91CD\u590D\u7684\u4E00\u4EFD,\u800C\u4E14\u4F1A\u518D\u6263\u4E00\u6B21\u8D39\u3002"}:{type:"ask_user",message:"\u670D\u52A1\u7AEF\u54CD\u5E94\u592A\u6162\u3002\u7A0D\u540E\u91CD\u8BD5\u540C\u4E00\u6761\u547D\u4EE4\u5373\u53EF,\u67E5\u8BE2\u4E0D\u4F1A\u4EA7\u751F\u4EFB\u4F55\u5199\u5165"}}):l("SERVER_ERROR",`\u65E0\u6CD5\u8FDE\u63A5\u670D\u52A1\u7AEF\uFF1A${c instanceof Error?c.message:String(c)}`,{data:{transportFailure:!0},nextAction:{type:"ask_user",message:"\u8BF7\u786E\u8BA4\u7F51\u7EDC\u53EF\u7528\uFF0C\u4EE5\u53CA\u670D\u52A1\u7AEF\u5730\u5740\u914D\u7F6E\u6B63\u786E"}})}}function Jt(e){if(typeof e!="object"||e===null)return!1;let t=e;return typeof t.ok=="boolean"&&typeof t.code=="string"}function Qt(e){var t;return!e.ok&&((t=e.data)==null?void 0:t.transportFailure)===!0}function ce(e){return e.ok||Qt(e)?!1:["AUTH_EXPIRED","DEVICE_MISMATCH","ACCESS_DENIED","AUTH_REQUIRED","VALIDATION_FAILED"].includes(e.code)}function U(){var e,t,n;return(n=(t=(e=C())==null?void 0:e.activeCredential)==null?void 0:t.apiKey)!=null?n:null}function Z(){var e,t;return(t=(e=C())==null?void 0:e.activeCredential)!=null?t:null}function Je(){var e,t;return(t=(e=C())==null?void 0:e.pendingCredential)!=null?t:null}function Qe(e){T(t=>({...t,pendingCredential:{apiKey:e,startedAt:new Date().toISOString()}}))}function pe(){T(e=>({...e,pendingCredential:null}))}function ue(e){return T(t=>{let n=t.pendingCredential;return n?{...t,activeCredential:{apiKey:n.apiKey,...e},pendingCredential:null}:t}).activeCredential}function We(){T(e=>({...e,activeCredential:null,pendingCredential:null}))}var R=require("node:crypto"),Ze=require("node:http");function Xe(e){let t=`
5
5
  (function () {
@@ -10,7 +10,7 @@
10
10
  {
11
11
  "step": 1,
12
12
  "action": "确定内容来源与视觉方式",
13
- "note": "内容来源二选一:sourceType=1 用已有文章(给 articleId,从 articles.list 查)、sourceType=2 用自定义正文(给 content,至少 20 个有效字符)。视觉方式三选一:visualMode=1 让 AI 自动挑模板(最省事)、=2 指定模板(先用 answerCards.templates 查可用模板拿 templateId)、=3 自定义风格(给 customStylePrompt)。richness 决定页数档位,模型档位用 textToImages.models 查 modelCode。"
13
+ "note": "内容来源二选一:sourceType=1 用已有文章(给 articleId,从 articles.list 查)、sourceType=2 用自定义正文(给 content,至少 20 个有效字符)。视觉方式三选一:visualMode=1 让 AI 自动挑模板(最省事)、=2 指定模板(先用 answerCards.templates 查可用模板拿 templateId)、=3 自定义风格(给 customStylePrompt)。richness 决定页数档位,模型档位用 textToImages.models 查 modelCode。**参考图上限看档位**:每个档位最多能喂 maxInputImages 张图;visualMode=1 或 2 时模板图先占 1 张,用户能选的再少 1 张;maxInputImages 为 0 的档位只能用 visualMode=3。超了 plan 能过、apply 才被拒,plan 前就要算好。"
14
14
  },
15
15
  {
16
16
  "step": 2,
@@ -70,7 +70,8 @@
70
70
  "VALIDATION_FAILED": "参数不合法,按 capabilities 里的 inputSchema 修正后重试。提示词/模型不存在、提示词类型不对、项目下没有知识资料、图片数量不够配图,都走这个码,message 里写明了是哪一种。",
71
71
  "PLAN_EXPIRED": "计划超过 30 分钟没执行。重新 plan,把新摘要再给用户确认一次——旧 planId 已经不能用了。",
72
72
  "PLAN_COST_CHANGED": "扣费方式在确认期间变了。重新 plan,把新的费用说明再念给用户。",
73
- "SERVER_ERROR": "看它出现在哪一步。**apply 阶段**多半是余额不足——建任务要按篇数扣费,扣费失败会落成这个码;**先别重试 apply**,把 message 原样转达给用户,让他确认账户余额。**plan 阶段**则与余额无关,按 message 说的处理。"
73
+ "QUOTA_EXCEEDED": "账户余额(积分/算力)不足——建任务要按篇数扣费。把 message 原样转达给用户,让他确认账户余额或联系管理员充值,不要重试 apply——余额不够重试也不会成功。",
74
+ "SERVER_ERROR": "服务端出错,**不是余额问题**(余额不足是 QUOTA_EXCEEDED)。常见原因是站点侧配置缺失或服务端临时故障。**apply 阶段先别重试**——可能已经建出来了,先用 articleTasks.list 确认;把 message 和 requestId 一起转达给用户,让他联系服务商。"
74
75
  },
75
76
  "completionCriteria": "读:已经如实说明任务跑到哪一步、写出来多少篇、审核通过多少。写:plan 摘要已原样念给用户、用户明确同意、apply 成功,并告诉了他任务在后台跑、大概要等一会儿。"
76
77
  }
@@ -73,16 +73,17 @@
73
73
  "不要把 articles.update 当成追加。正文/标签/摘要都是整体覆盖,只传一段新内容会把原来的全冲掉",
74
74
  "不要在用户没同意 plan 摘要之前就 apply。他说「帮我写篇文章」不等于同意了你写的这一篇",
75
75
  "不要为了省事把 articles.create 连着调好几次试效果——每调一次都真的建出一篇,多出来的还得让用户一篇篇去网页删;而且按篇计费",
76
- "已经建好的文章改不了所属项目和文件夹(新建时可以用 folderId 指定),用户要动那两个就让他去网页的文章管理",
76
+ "已经建好的文章改不了所属 GEO 项目,用户要换项目就让他去网页的文章管理。换文件夹用 articles.moveFolder,不用去网页",
77
77
  "不要凭印象填 folderId。合法 id 只能来自 folders.list,猜一个过去会被服务端拒掉"
78
78
  ],
79
79
  "errorRecovery": {
80
- "ACCESS_DENIED": "这条数据不在当前 GEO 项目里,用当前项目的列表能力重新查;要换项目先问用户。",
81
- "VALIDATION_FAILED": "参数不合法,按 capabilities 里的 inputSchema 修正后重试。message 里写明了是哪个字段;长度类还会给出当前值和上限。文章不存在也走这个码——读不到一律当不存在,不区分「没有」和「不是你的」。",
80
+ "ACCESS_DENIED": "这条数据不在当前 GEO 项目里,或者已经不存在了(读不到一律当不存在,不区分「没有」和「不是你的」)。用当前项目的列表能力重新查;要换项目先问用户。",
81
+ "VALIDATION_FAILED": "参数不合法,按 capabilities 里的 inputSchema 修正后重试。message 里写明了是哪个字段;长度类还会给出当前值和上限。",
82
82
  "PLAN_STALE": "这篇文章在用户确认期间被别人改过。重新 articles.get 读当前内容、重新 plan,把新摘要再给用户确认一次。不要拿旧 planId 重试。",
83
83
  "PLAN_EXPIRED": "计划超过 30 分钟没执行。重新 plan,把新摘要再给用户确认一次——旧 planId 已经不能用了。",
84
84
  "PLAN_COST_CHANGED": "扣费方式在确认期间变了。重新 plan,把新的费用说明再念给用户。",
85
- "SERVER_ERROR": "看它出现在哪一步。**apply 阶段**多半是余额不足——新建文章是这条链路上唯一会扣费的动作,扣费失败会落成这个码;**先别重试 apply**,把 message 原样转达给用户,让他确认账户余额。**plan 阶段**则与余额无关,按 message 说的处理,别让用户去查余额。"
85
+ "QUOTA_EXCEEDED": "账户余额(积分/算力)不足。这条链路上新建、复制、生成摘要、生成封面都会扣费。把 message 原样转达给用户,让他确认账户余额或联系管理员充值,不要重试 apply——余额不够重试也不会成功。",
86
+ "SERVER_ERROR": "服务端出错,**不是余额问题**(余额不足是 QUOTA_EXCEEDED)。常见原因是站点侧配置缺失或服务端临时故障。**apply 阶段先别重试**——可能已经写进去了,先用 articles.list 确认;把 message 和 requestId 一起转达给用户,让他联系服务商。"
86
87
  },
87
88
  "completionCriteria": "读:已经如实呈现用户关心的文章列表(含总数)或指定那一篇的信息,用户要正文时才给了正文。写:plan 摘要已原样念给用户、用户明确同意、apply 成功,并把结果(文章 ID、还差不差封面)告诉了他。"
88
89
  }
@@ -34,7 +34,7 @@
34
34
  "step": 5,
35
35
  "action": "改名称或标签走 knowledge.update",
36
36
  "capability": "knowledge.update",
37
- "note": "同样先 plan 再 apply。只能改这两样,改所属项目、加删文档都要去网页。"
37
+ "note": "同样先 plan 再 apply。只能改这两样。加文档用 knowledge.addFiles;改所属项目、删文档要去网页。"
38
38
  },
39
39
  {
40
40
  "step": 6,
@@ -60,11 +60,12 @@
60
60
  "用户说「补进 XX 知识库」时不要新建库。那是 knowledge.addFiles 的活"
61
61
  ],
62
62
  "errorRecovery": {
63
- "ACCESS_DENIED": "这条数据不在当前 GEO 项目里,用当前项目的列表能力重新查;要换项目先问用户。",
64
- "VALIDATION_FAILED": "参数不合法。常见原因:files 为空、某个文档缺 name 或 file、知识库名称为空或只有空格、以及**知识库不存在**(读不到一律当不存在,不区分「没有」和「不是你的」)。按提示补齐后重试。**还有一种与参数无关的情况**:站点还没配置这个功能的价格——这时按 nextAction 说的让用户联系服务商,别去改参数重试,改了也过不去。分辨方法是看 nextAction.message。",
63
+ "ACCESS_DENIED": "这条数据不在当前 GEO 项目里,或者已经不存在了(读不到一律当不存在,不区分「没有」和「不是你的」)。用当前项目的列表能力重新查;要换项目先问用户。",
64
+ "VALIDATION_FAILED": "参数不合法。常见原因:files 为空、某个文档缺 name 或 file、知识库名称为空或只有空格。按提示补齐后重试。**还有一种与参数无关的情况**:站点还没配置这个功能的价格——这时按 nextAction 说的让用户联系服务商,别去改参数重试,改了也过不去。分辨方法是看 nextAction.message。",
65
65
  "PLAN_STALE": "确认期间这个知识库被别人改过。重新 plan,把新摘要再给用户确认一次。",
66
66
  "PLAN_COST_CHANGED": "确认之后扣费方式变了(比如管理员把这个功能改成从另一种账户扣)。用户上次点头同意的不是现在这笔,**别直接重试 apply**。重新 plan,把新的费用说明再给用户确认一次。注意:响应里**不含**「原来是什么、现在是什么」,别向用户复述具体是从哪种变成了哪种。",
67
- "SERVER_ERROR": "看它出现在哪一步。**apply 阶段**多半是余额不足——这是唯一会扣费的能力,扣费失败会落成这个码;**先别重试 apply**,把 message 原样转达给用户,让他确认账户余额。**plan 阶段**则与余额无关,按 message 说的处理,别让用户去查余额。"
67
+ "QUOTA_EXCEEDED": "账户余额(积分/算力)不足。knowledge.create 和 knowledge.addFiles 都按文档扣费。把 message 原样转达给用户,让他确认账户余额或联系管理员充值,不要重试 apply——余额不够重试也不会成功。",
68
+ "SERVER_ERROR": "服务端出错,**不是余额问题**(余额不足是 QUOTA_EXCEEDED)。常见原因是站点侧配置缺失或服务端临时故障。**apply 阶段先别重试**——可能已经写进去了,先用 knowledge.get / knowledge.list 确认;把 message 和 requestId 一起转达给用户,让他联系服务商。"
68
69
  },
69
70
  "completionCriteria": "查询类:已如实呈现知识库列表或指定那个的文档解析状态。新建类:用户看过摘要并明确同意后才执行,且执行后说清了「正在解析、暂不可用」。",
70
71
  "writeFlow": {
@@ -79,7 +80,7 @@
79
80
  "计划 30 分钟内有效,只能执行一次。",
80
81
  "notice 里会写清这次要新增几个文档、按文档计费扣几次——按下去之前用户就该知道。",
81
82
  "摘要里的 files 只列文档名,不回显正文。用户要核对内容,让他看自己给你的原始资料。",
82
- "knowledge.update 只能改名称和标签。改所属项目、加文档、删文档都要去网页做。"
83
+ "knowledge.update 只能改名称和标签。加文档用 knowledge.addFiles;改所属项目、删文档要去网页做。"
83
84
  ]
84
85
  }
85
86
  }
@@ -78,7 +78,8 @@
78
78
  "PLAN_EXPIRED": "计划超过 30 分钟没执行。重新 plan,把新摘要再给用户确认一次——旧 planId 已经不能用了,文件也要重新走一遍上传。",
79
79
  "UPLOAD_FAILED": "文件传到一半断了。素材记录还没建,什么都没留下——把情况告诉用户,重新走一遍 plan 就行,不要反复重试 apply。",
80
80
  "PLAN_COST_CHANGED": "扣费方式在确认期间变了。重新 plan,把新的费用说明再念给用户。",
81
- "SERVER_ERROR": "看它出现在哪一步。**apply 阶段**多半是余额不足——传图片是这条链路上唯一会扣费的动作,扣费失败会落成这个码;**先别重试 apply**,把 message 原样转达给用户,让他确认账户余额。**plan 阶段**则与余额无关,按 message 说的处理。"
81
+ "QUOTA_EXCEEDED": "账户余额(积分/算力)不足——传图片会扣费。把 message 原样转达给用户,让他确认账户余额或联系管理员充值,不要重试 apply——余额不够重试也不会成功。",
82
+ "SERVER_ERROR": "服务端出错,**不是余额问题**(余额不足是 QUOTA_EXCEEDED)。常见原因是站点侧配置缺失或服务端临时故障。**apply 阶段先别重试**——可能已经建出来了,先用 images.list / videos.list 确认;把 message 和 requestId 一起转达给用户,让他联系服务商。"
82
83
  },
83
84
  "completionCriteria": "查询类:已如实呈现用户关心的素材列表或指定那一条的信息。写入类(新建/改名/改标签):用户看过 plan 摘要并明确同意后才执行,执行完把结果告诉了他。",
84
85
  "writeFlow": {
@@ -46,7 +46,7 @@
46
46
  "step": 7,
47
47
  "action": "要停下来用 publicationTasks.pause,改主意了用 delete",
48
48
  "capability": "publicationTasks.pause",
49
- "note": "两个都只对**还没发出去**的记录有效(删除会连暂停中的一起删掉)。已经发成功的稿子留在平台上,CLI 撤不回来——用户要撤那些,只能去各平台自己删,这一点必须说明白,别让他以为暂停就等于撤回。另外建任务时费用就按记录条数扣过了,删除不改变这笔扣费,用户点删除前得知道。"
49
+ "note": "两个都只对**还没发出去**的记录有效(删除会连暂停中的一起删掉)。已经发成功的稿子留在平台上,CLI 撤不回来——用户要撤那些,只能去各平台自己删,这一点必须说明白,别让他以为暂停就等于撤回。另外建任务时费用就按记录条数扣过了,删除不改变这笔扣费,用户点删除前得知道。**例外是外部导入的任务**(typeLabel=外部导入):它不能暂停或恢复;删除时会连同名下已发布的记录一起删掉,收录统计也会跟着减少,计划摘要会单独写出来,一定要念给用户。"
50
50
  },
51
51
  {
52
52
  "step": 8,
@@ -65,6 +65,12 @@
65
65
  "action": "查投稿进展用 mediaPublications.list,要整体情况用 mediaPublications.summary",
66
66
  "capability": "mediaPublications.summary",
67
67
  "note": "投稿动辄上百条。用户问「投出去的都怎么样了」直接用 summary,念 items 里的 statusLabel(「已拒稿 × 15」),别念 counts 里的数值。投稿有 failReason,被拒稿时把它念出来——这条链路和自媒体发布不同,是有失败原因的。**被拒稿的还要看 refundStatusLabel**:拒稿会原路退款,但退款偶尔会没退成(显示「待退款」,系统会自动补退)——用户问「钱退了吗」看的是这个字段,不是 status。"
68
+ },
69
+ {
70
+ "step": 11,
71
+ "action": "用户在外面自己发过的文章,要算进收录统计:publicationTasks.importLinks",
72
+ "capability": "publicationTasks.importLinks",
73
+ "note": "这是**登记**,不是发布:不扣费,也不会往任何平台发东西。先问清这些链接发的是系统里已有的哪篇文章(用 articles.list 找到 articleId),不是的话问用户要标题(title)新建一篇外部文章——两个只给一个。plan 里逐条写明哪条能导、哪条跳过,**把跳过的和原因念给用户**,别只报「导入 N 条」。「网站暂不支持」的链接导进来也匹配不上收录,不要换个写法重试。导入后在 publicationTasks.list 里是一个「外部导入」任务,apply 结果里的 results 是逐条最终结果,以它为准告诉用户导进去了几条。"
68
74
  }
69
75
  ],
70
76
  "askUserWhen": [
@@ -67,7 +67,8 @@
67
67
  "PLAN_STALE": "任务在用户确认期间被动过(多半是别人也导了一批)。重新 questionTasks.get 读当前状态、重新 plan,把新摘要再给用户确认一次。",
68
68
  "PLAN_EXPIRED": "计划超过 30 分钟没执行。重新 plan,把新摘要再给用户确认一次——旧 planId 已经不能用了。",
69
69
  "PLAN_COST_CHANGED": "扣费方式在确认期间变了。重新 plan,把新的费用说明再念给用户。",
70
- "SERVER_ERROR": "看它出现在哪一步。**apply 阶段**多半是余额不足——创建和重试都要扣费,扣费失败会落成这个码;**先别重试 apply**,把 message 原样转达给用户,让他确认账户余额。**plan 阶段**则与余额无关,按 message 说的处理。"
70
+ "QUOTA_EXCEEDED": "账户余额(积分/算力)不足——创建和重试都要扣费。把 message 原样转达给用户,让他确认账户余额或联系管理员充值,不要重试 apply——余额不够重试也不会成功。",
71
+ "SERVER_ERROR": "服务端出错,**不是余额问题**(余额不足是 QUOTA_EXCEEDED)。常见原因是站点侧配置缺失或服务端临时故障。**apply 阶段先别重试**——可能已经建出来了,先用 questionTasks.list 确认;把 message 和 requestId 一起转达给用户,让他联系服务商。"
71
72
  },
72
73
  "completionCriteria": "读:已经如实说明任务跑到哪一步、生成了哪些问题。写:plan 摘要已原样念给用户、用户明确同意、apply 成功,并告诉了他任务在后台跑(新建/重试)或者哪些问题已经进了问题库(导入)。"
73
74
  }
@@ -91,6 +91,7 @@
91
91
  "PLAN_COST_CHANGED": "扣费方式在确认期间变了。重新 plan,把新的费用说明再念给用户。",
92
92
  "PLAN_STALE": "计划在用户确认期间被改过。重新 get 读当前配置、重新 plan,把新摘要再给用户确认一次——runNow 也一样,因为摘要里承诺的提问次数可能已经变了。",
93
93
  "PLAN_EXPIRED": "计划超过 30 分钟没执行。重新 plan,把新摘要再给用户确认一次,旧 planId 已经不能用了。",
94
- "SERVER_ERROR": "看它出现在哪一步。**apply 阶段**多半是余额不足——云端采集要扣算力,扣费失败会落成这个码;**先别重试 apply**,把 message 原样转达给用户,让他确认账户余额。**plan 阶段**与余额无关,把 requestId 一起给用户去查。"
94
+ "QUOTA_EXCEEDED": "账户余额(积分/算力)不足——云端采集要扣费。把 message 原样转达给用户,让他确认账户余额或联系管理员充值,不要重试 apply——余额不够重试也不会成功。",
95
+ "SERVER_ERROR": "服务端出错,**不是余额问题**(余额不足是 QUOTA_EXCEEDED)。runNow 时最常见的原因是**这个计划已经有一次执行在跑**——用 runs 看最近一次的状态,跑完了再重新 plan runNow,别连着重试。其他情况多半是站点侧配置缺失或服务端临时故障,把 message 和 requestId 一起转达给用户。"
95
96
  }
96
97
  }
package/guides/video.json CHANGED
@@ -73,7 +73,8 @@
73
73
  "PLAN_STALE": "确认期间来源数字人任务合成完了、回填了真实时长,那份按兜底秒数算出来的报价已经不作数。重新 plan,把新的金额再念给用户确认一次——底板只是进度在动不会触发这个码,所以不用担心一直撞。",
74
74
  "PLAN_EXPIRED": "计划超过 30 分钟没执行。重新 plan,把新摘要再给用户确认一次。",
75
75
  "PLAN_COST_CHANGED": "单价在确认期间被改过。重新 plan,把新的费用说明再念给用户。",
76
- "SERVER_ERROR": "看它出现在哪一步。**apply 阶段**多半是余额不足:提交时虽然不扣费,但会校验余额够不够,不够会挡在这里。先别重试,把 message 原样转达给用户,让他确认余额。**plan 阶段**与余额无关,按 message 说的处理。"
76
+ "QUOTA_EXCEEDED": "账户余额(积分/算力)不足:提交时虽然不扣费,但会校验余额够不够,不够会挡在这里。把 message 原样转达给用户,让他确认余额或联系管理员充值,不要重试 apply。",
77
+ "SERVER_ERROR": "服务端出错,**不是余额问题**(余额不足是 QUOTA_EXCEEDED)。常见原因是站点侧配置缺失或服务端临时故障。**apply 阶段先别重试**——可能已经提交了,先用 dhVideos.list / clipTasks.list 确认;把 message 和 requestId 一起转达给用户,让他联系服务商。"
77
78
  },
78
79
  "completionCriteria": "查询类:已如实呈现任务状态或资源列表;任务没跑完就说清它还在哪个阶段,不要拿空的 videoUrl 当「失败」。写入类:用户看过 plan 摘要(含费用说明)并明确同意,apply 已返回任务号,并告诉了用户去哪儿查进度。",
79
80
  "writeFlow": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "best-geo-test",
3
- "version": "2.0.0-beta.2",
3
+ "version": "2.0.2",
4
4
  "description": "Best GEO CLI — 给本地 AI 助手调用的 GEO 命令行工具",
5
5
  "bin": {
6
6
  "best-geo-test": "dist/index.cjs"