openclaw-weiyuan-init 1.0.117 → 1.0.118

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/lib/downloader.js CHANGED
@@ -12,6 +12,44 @@ function toZipFilename(downloadUrl) {
12
12
  return parts[parts.length - 1] || 'weiyuan-openclaw-skill.zip';
13
13
  }
14
14
 
15
+ function parseVersionFromZipFilename(zipFilename) {
16
+ const match = /-v(\d+\.\d+\.\d+)\.zip$/i.exec(String(zipFilename || '').trim());
17
+ return match ? match[1] : '';
18
+ }
19
+
20
+ function buildFallbackReleaseNotes(version) {
21
+ const normalizedVersion = String(version || '').trim();
22
+ if (!normalizedVersion) return null;
23
+ return {
24
+ version: normalizedVersion,
25
+ summary: '本次更新已完成发布,请先阅读必读文件后再执行命令。',
26
+ changes: [
27
+ '已同步最新微元系统运行时与规则文件。',
28
+ '执行任何命令前,请先阅读 CHANGELOG_OPENCLAW.md、release-notes/latest.json、docs/OPENCLAW_WEIYUAN_CLI_QUICKSTART.md、docs/WEIYUAN_AGENT_RULES.md。'
29
+ ],
30
+ releasedAt: new Date().toISOString()
31
+ };
32
+ }
33
+
34
+ function normalizeReleaseNotesForResolvedVersion(releaseNotes, resolvedVersion) {
35
+ const version = String(resolvedVersion || '').trim();
36
+ if (!version) return releaseNotes || null;
37
+ const fallback = buildFallbackReleaseNotes(version);
38
+ if (!releaseNotes || typeof releaseNotes !== 'object') return fallback;
39
+ const notesVersion = String(releaseNotes.version || '').trim();
40
+ const summary = String(releaseNotes.summary || '').trim();
41
+ const changes = Array.isArray(releaseNotes.changes)
42
+ ? releaseNotes.changes.map((item) => String(item || '').trim()).filter(Boolean)
43
+ : [];
44
+ return {
45
+ version,
46
+ summary: summary || fallback.summary,
47
+ changes: changes.length > 0 ? changes : fallback.changes,
48
+ releasedAt: String(releaseNotes.releasedAt || '').trim() || fallback.releasedAt,
49
+ sourceVersion: notesVersion || undefined
50
+ };
51
+ }
52
+
15
53
  async function fetchLatestReleaseNotes(base, nonce) {
16
54
  const notesUrl = `${base}/RELEASE_NOTES_LATEST.json?nocache=${nonce}`;
17
55
  try {
@@ -34,7 +72,16 @@ async function fetchLatestReleaseNotes(base, nonce) {
34
72
 
35
73
  async function resolvePackageSource({ downloadUrl, upgradeBaseUrl, spinner = null }) {
36
74
  if (downloadUrl) {
37
- return { downloadUrl, zipFilename: toZipFilename(downloadUrl), version: null, sha256: '', from: 'download_url', releaseNotes: null };
75
+ const zipFilename = toZipFilename(downloadUrl);
76
+ const version = parseVersionFromZipFilename(zipFilename);
77
+ return {
78
+ downloadUrl,
79
+ zipFilename,
80
+ version: version || null,
81
+ sha256: '',
82
+ from: 'download_url',
83
+ releaseNotes: normalizeReleaseNotesForResolvedVersion(null, version)
84
+ };
38
85
  }
39
86
 
40
87
  const base = trimSlash(upgradeBaseUrl);
@@ -52,7 +99,14 @@ async function resolvePackageSource({ downloadUrl, upgradeBaseUrl, spinner = nul
52
99
  if (spinner) {
53
100
  spinner.text = `已解析最新版本: v${version}`;
54
101
  }
55
- return { downloadUrl: resolvedDownloadUrl, zipFilename, version, sha256, from: 'latest_json', releaseNotes };
102
+ return {
103
+ downloadUrl: resolvedDownloadUrl,
104
+ zipFilename,
105
+ version,
106
+ sha256,
107
+ from: 'latest_json',
108
+ releaseNotes: normalizeReleaseNotesForResolvedVersion(releaseNotes, version)
109
+ };
56
110
  }
57
111
  } catch (_e) {
58
112
  // fallback to txt
@@ -66,7 +120,14 @@ async function resolvePackageSource({ downloadUrl, upgradeBaseUrl, spinner = nul
66
120
  if (spinner) {
67
121
  spinner.text = `已解析最新版本: v${version}`;
68
122
  }
69
- return { downloadUrl: resolvedDownloadUrl, zipFilename, version, sha256: '', from: 'latest_version', releaseNotes };
123
+ return {
124
+ downloadUrl: resolvedDownloadUrl,
125
+ zipFilename,
126
+ version,
127
+ sha256: '',
128
+ from: 'latest_version',
129
+ releaseNotes: normalizeReleaseNotesForResolvedVersion(releaseNotes, version)
130
+ };
70
131
  }
71
132
 
72
133
  async function downloadFile(url, outputPath, spinner = null, expectedSha256 = '') {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openclaw-weiyuan-init",
3
- "version": "1.0.117",
3
+ "version": "1.0.118",
4
4
  "description": "OpenClaw Weiyuan Skill 一键初始化工具",
5
5
  "main": "bin/cli.js",
6
6
  "bin": {
@@ -145,7 +145,7 @@ npm run weiyuan -- doc sync-check --project <projectId>
145
145
 
146
146
  说明:
147
147
 
148
- - 文件上传不再通过 CLI 执行,请直接在项目看板中点击上传按钮。
148
+ - 文件上传已恢复 CLI 直传能力,可使用 `doc upload --project <projectId> --file <路径>`;未显式提供 `--name` 或 `--type` 时会自动补默认值。
149
149
  - 文件删除保留 CLI 能力,智能体 CLI 与小精灵 CLI 都支持删除文件。
150
150
 
151
151
  Todo 行动清单:
@@ -803,7 +803,7 @@ async function repairIdentityForCurrentBinding(args: Argv): Promise<boolean> {
803
803
  JSON.stringify(nextJoinedProjectIds) !== JSON.stringify(identity.joinedProjectIds ?? []) ||
804
804
  nextCurrentProjectId !== String(identity.currentProjectId || "").trim() ||
805
805
  JSON.stringify(nextProjectCursors) !== JSON.stringify(identity.projectCursors ?? {})
806
- if (!changed) return false
806
+ if (!changed) return true
807
807
  await backupCurrentIdentityIfExists(filePath)
808
808
  await writeIdentity(filePath, nextIdentity)
809
809
  return true
@@ -5067,6 +5067,32 @@ function parseIssueAttachmentPaths(raw?: string): string[] {
5067
5067
  .slice(0, ISSUE_ATTACHMENT_MAX_FILES)
5068
5068
  }
5069
5069
 
5070
+ const DOC_UPLOAD_MIME_MAP: Record<string, string> = {
5071
+ ".txt": "text/plain",
5072
+ ".md": "text/markdown",
5073
+ ".markdown": "text/markdown",
5074
+ ".json": "application/json",
5075
+ ".csv": "text/csv",
5076
+ ".pdf": "application/pdf",
5077
+ ".zip": "application/zip",
5078
+ ".doc": "application/msword",
5079
+ ".docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
5080
+ ".xls": "application/vnd.ms-excel",
5081
+ ".xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
5082
+ ".ppt": "application/vnd.ms-powerpoint",
5083
+ ".pptx": "application/vnd.openxmlformats-officedocument.presentationml.presentation",
5084
+ ".png": "image/png",
5085
+ ".jpg": "image/jpeg",
5086
+ ".jpeg": "image/jpeg",
5087
+ ".gif": "image/gif",
5088
+ ".webp": "image/webp",
5089
+ }
5090
+
5091
+ function guessDocMimeType(filePath: string): string {
5092
+ const ext = path.extname(String(filePath || "")).toLowerCase()
5093
+ return DOC_UPLOAD_MIME_MAP[ext] ?? "application/octet-stream"
5094
+ }
5095
+
5070
5096
  async function loadIssueAttachments(attachmentPath?: string): Promise<Array<{ fileName: string; mimeType: string; contentBase64: string }>> {
5071
5097
  const paths = parseIssueAttachmentPaths(attachmentPath)
5072
5098
  if (!paths.length) return []
@@ -5760,8 +5786,93 @@ async function cmdDocList(args: Argv): Promise<void> {
5760
5786
  }
5761
5787
 
5762
5788
  async function cmdDocCreate(args: Argv): Promise<void> {
5763
- void args
5764
- throw new Error("doc_upload_board_only")
5789
+ const filePath = optString(args.flags, "identity") ?? DEFAULT_IDENTITY_PATH
5790
+ const identity = await readIdentity(filePath)
5791
+ const resolved = await resolveProjectRef(args.flags, identity)
5792
+ const interactive = Boolean(args.flags.interactive || args.flags.prompt)
5793
+ const sourceFileRaw = interactive
5794
+ ? await askRequired("请选择要上传的文件路径: ", optString(args.flags, "file"))
5795
+ : mustString(args.flags, "file")
5796
+ const sourceFile = path.resolve(sourceFileRaw)
5797
+ let stat
5798
+ try {
5799
+ stat = await fs.stat(sourceFile)
5800
+ } catch {
5801
+ throw new Error(`invalid_doc_file_path: ${sourceFileRaw}`)
5802
+ }
5803
+ if (!stat.isFile()) throw new Error(`invalid_doc_file_path: ${sourceFileRaw}`)
5804
+ const bytes = await fs.readFile(sourceFile)
5805
+ const uploadNameFallback = path.basename(sourceFile)
5806
+ const uploadTypeFallback = guessDocMimeType(sourceFile)
5807
+ const docName = interactive
5808
+ ? await askRequired("请输入上传后显示的文件名: ", optString(args.flags, "name") ?? optString(args.flags, "title") ?? uploadNameFallback)
5809
+ : String(optString(args.flags, "name") ?? optString(args.flags, "title") ?? uploadNameFallback).trim()
5810
+ const docType = interactive
5811
+ ? await askRequired("请输入文件类型(可留空走自动识别): ", optString(args.flags, "type") ?? optString(args.flags, "docType") ?? uploadTypeFallback)
5812
+ : String(optString(args.flags, "type") ?? optString(args.flags, "docType") ?? uploadTypeFallback).trim()
5813
+ const fileSize = bytes.length
5814
+ if (fileSize > MAX_SHARED_DOC_FILE_BYTES) {
5815
+ throw new Error("doc_file_too_large: 单文件超过 10MB,请压缩后重试。")
5816
+ }
5817
+ const contentHash = sha256Hex(bytes)
5818
+ const storageType = optString(args.flags, "storageType")
5819
+ const storageProvider = optString(args.flags, "storageProvider")
5820
+ const storagePath = optString(args.flags, "storagePath") ?? sourceFile
5821
+ const tags = String(optString(args.flags, "tags") ?? "")
5822
+ .split(",")
5823
+ .map((x) => x.trim())
5824
+ .filter(Boolean)
5825
+ const relatedTaskIds = String(optString(args.flags, "tasks") ?? optString(args.flags, "task") ?? "")
5826
+ .split(",")
5827
+ .map((x) => x.trim())
5828
+ .filter(Boolean)
5829
+ const version = optString(args.flags, "version") ?? "v1"
5830
+ const description = optString(args.flags, "desc") ?? optString(args.flags, "description")
5831
+ const changeSummary = optString(args.flags, "summary")
5832
+ const idempotencyKey = createRequestId(`doc_upload_${path.basename(sourceFile)}`)
5833
+ const { status, json } = await signedRequest({
5834
+ serverBaseUrl: identity.serverBaseUrl,
5835
+ method: "POST",
5836
+ pathWithQuery: `/v1/projects/${resolved.projectId}/docs`,
5837
+ lobsterId: identity.lobsterId,
5838
+ secretKeyBase64: identity.secretKeyBase64,
5839
+ idempotencyKey,
5840
+ body: {
5841
+ docName,
5842
+ docType,
5843
+ fileSize,
5844
+ contentHash,
5845
+ contentBase64: bytes.toString("base64"),
5846
+ storageLocation: { type: storageType ?? undefined, provider: storageProvider, path: storagePath },
5847
+ version,
5848
+ relatedTaskIds,
5849
+ tags,
5850
+ description,
5851
+ changeSummary,
5852
+ },
5853
+ })
5854
+ if (status !== 200) {
5855
+ const msg = String((json as any)?.msg ?? (json as any)?.message ?? "")
5856
+ if (status === 409 && msg.includes("storage_quota_exceeded")) {
5857
+ throw new Error("storage_quota_exceeded: 存储空间已达上限,请联系 founder 升级容量后再上传。")
5858
+ }
5859
+ if (status === 409 && msg === "invalid_storage_profile") {
5860
+ throw new Error("invalid_storage_profile: 当前项目存储配置无效,请联系 founder 检查项目存储设置。")
5861
+ }
5862
+ throw new Error(JSON.stringify(json))
5863
+ }
5864
+ print({
5865
+ ok: true,
5866
+ projectId: resolved.projectId,
5867
+ projectName: resolved.projectName ?? "",
5868
+ docName,
5869
+ docType,
5870
+ sourceFile,
5871
+ fileSize,
5872
+ contentHash,
5873
+ uploadedAt: Date.now(),
5874
+ ...(json.data && typeof json.data === "object" ? (json.data as Record<string, unknown>) : {}),
5875
+ })
5765
5876
  }
5766
5877
 
5767
5878
  async function cmdDocDetail(args: Argv): Promise<void> {
@@ -18,7 +18,9 @@ function toUserError(raw: string): string {
18
18
  if (msg.includes("interactive_input_required")) return "必填内容不能为空,请补充参数后重试。"
19
19
  if (msg.includes("missing_project_name")) return "项目名不能为空,请通过 --name 提供有效项目名。"
20
20
  if (msg.includes("project_name_too_long")) return "项目名不能超过80个字符,请缩短后重试。"
21
- if (msg.includes("doc_upload_board_only")) return "文件上传已改为只支持在项目看板里点击上传按钮完成,CLI 不再执行上传。"
21
+ if (msg.includes("doc_upload_board_only")) return "当前运行时版本过旧,文件上传仍被禁用。请先更新微元系统后再试。"
22
+ if (msg.includes("invalid_doc_file_path")) return "上传文件路径不存在,或该路径不是一个可读取的文件。请检查 --file 后重试。"
23
+ if (msg.includes("invalid_storage_profile")) return "当前项目的存储配置异常,暂时无法上传文件。请联系项目 founder 检查存储设置。"
22
24
  if (msg.includes("invalid_project_name")) return "项目名仅支持中文/英文/数字/空格及 -_.()·,且不能包含HTML标签。"
23
25
  if (msg.includes("task_title_contains_html")) return "任务标题不能包含HTML标签(如 <script>)。"
24
26
  if (msg.includes("task_title_too_long")) return "任务标题不能超过120个字符,请缩短后重试。"
@@ -362,6 +362,90 @@ function extractNicknameFromText(text: string): string | undefined {
362
362
  return v || undefined
363
363
  }
364
364
 
365
+ function extractMemberProfileFieldFromText(
366
+ text: string,
367
+ field: "roleTitle" | "specialties" | "experienceSummary" | "strengthsSummary" | "taskPreferenceTags"
368
+ ): string | undefined {
369
+ const patterns: RegExp[] =
370
+ field === "roleTitle"
371
+ ? [
372
+ /(?:设置|修改|更改|更新)(?:我的)?(?:团队)?角色(?:与能力)?(?:为|叫|成)?\s*[“"']?([^”"'\n]+)[”"']?$/u,
373
+ /(?:我的)?(?:团队)?角色(?:是|为|叫|改成|改为)\s*[“"']?([^”"'\n]+)[”"']?$/u,
374
+ ]
375
+ : field === "specialties"
376
+ ? [
377
+ /(?:设置|修改|更改|更新)(?:我的)?(?:擅长方向|擅长|专长|特长方向)(?:为|成)?\s*[“"']?([^”"'\n]+)[”"']?$/u,
378
+ /(?:我的)?(?:擅长方向|擅长|专长|特长方向)(?:是|为|改成|改为)\s*[“"']?([^”"'\n]+)[”"']?$/u,
379
+ ]
380
+ : field === "experienceSummary"
381
+ ? [
382
+ /(?:设置|修改|更改|更新)(?:我的)?(?:经历概述|经历简介|经验概述|经验简介|经历)(?:为|成)?\s*[“"']?([^”"'\n]+)[”"']?$/u,
383
+ /(?:我的)?(?:经历概述|经历简介|经验概述|经验简介|经历)(?:是|为|改成|改为)\s*[“"']?([^”"'\n]+)[”"']?$/u,
384
+ ]
385
+ : field === "strengthsSummary"
386
+ ? [
387
+ /(?:设置|修改|更改|更新)(?:我的)?(?:特长概述|优势概述|优势简介|特长简介|特长)(?:为|成)?\s*[“"']?([^”"'\n]+)[”"']?$/u,
388
+ /(?:我的)?(?:特长概述|优势概述|优势简介|特长简介|特长)(?:是|为|改成|改为)\s*[“"']?([^”"'\n]+)[”"']?$/u,
389
+ ]
390
+ : [
391
+ /(?:设置|修改|更改|更新)(?:我的)?(?:偏好任务标签|任务偏好标签|偏好标签|任务标签)(?:为|成)?\s*[“"']?([^”"'\n]+)[”"']?$/u,
392
+ /(?:我的)?(?:偏好任务标签|任务偏好标签|偏好标签|任务标签)(?:是|为|改成|改为)\s*[“"']?([^”"'\n]+)[”"']?$/u,
393
+ ]
394
+ for (const pattern of patterns) {
395
+ const value = String(text.match(pattern)?.[1] ?? "").trim()
396
+ if (value) return value
397
+ }
398
+ return undefined
399
+ }
400
+
401
+ function hasMemberProfileCardIntent(text: string): boolean {
402
+ const compact = text.toLowerCase().replace(/\s+/g, "")
403
+ return (
404
+ compact.includes("成员角色卡片") ||
405
+ compact.includes("角色卡片") ||
406
+ compact.includes("成员卡片") ||
407
+ compact.includes("编辑成员信息") ||
408
+ compact.includes("修改成员信息") ||
409
+ compact.includes("设置角色卡片") ||
410
+ compact.includes("角色与能力") ||
411
+ compact.includes("我的角色") ||
412
+ compact.includes("修改角色") ||
413
+ compact.includes("更新角色") ||
414
+ compact.includes("团队角色") ||
415
+ compact.includes("擅长方向") ||
416
+ compact.includes("我的擅长") ||
417
+ compact.includes("我的专长") ||
418
+ compact.includes("经历概述") ||
419
+ compact.includes("经历简介") ||
420
+ compact.includes("经验概述") ||
421
+ compact.includes("我的经历") ||
422
+ compact.includes("特长概述") ||
423
+ compact.includes("优势概述") ||
424
+ compact.includes("我的特长") ||
425
+ compact.includes("我的优势") ||
426
+ compact.includes("偏好任务标签") ||
427
+ compact.includes("任务偏好标签")
428
+ )
429
+ }
430
+
431
+ function extractMemberRemarkIntent(text: string): { target?: string; remark?: string; clear?: boolean } | undefined {
432
+ const trimmed = String(text || "").trim()
433
+ if (!trimmed) return undefined
434
+ const clearMatch =
435
+ trimmed.match(/(?:清空|删除|移除|去掉)(?:我对)?\s*([^,,\s]+)\s*(?:的)?备注$/u) ??
436
+ trimmed.match(/(?:把)?\s*([^,,\s]+)\s*(?:的)?备注(?:清空|删除|移除|去掉)$/u)
437
+ if (clearMatch?.[1]) {
438
+ return { target: clearMatch[1].trim(), clear: true, remark: "-" }
439
+ }
440
+ const saveMatch =
441
+ trimmed.match(/(?:给|帮我给|把)?\s*([^,,\s]+)\s*(?:的)?备注(?:为|成)?\s*([^\n]+)$/u) ??
442
+ trimmed.match(/(?:把)?\s*([^,,\s]+)\s*(?:备注为|备注成)\s*([^\n]+)$/u)
443
+ if (saveMatch?.[1]) {
444
+ return { target: saveMatch[1].trim(), remark: String(saveMatch[2] ?? "").trim() }
445
+ }
446
+ return undefined
447
+ }
448
+
365
449
  function extractProjectNameForCreate(text: string): string | undefined {
366
450
  const m =
367
451
  text.match(/(?:创建|新建)(?:一个|个)?[“"'《【((]?\s*([^”"'》】))\n]+?项目)\s*(?:吧|呀|呢|的)?$/) ??
@@ -1761,22 +1845,33 @@ function fromText(input: SkillInput): string[] {
1761
1845
  if (!nickname) return ["member-profile-edit", "--identity", identity, "--project", input.projectId]
1762
1846
  return ["member-profile-set", "--identity", identity, "--project", input.projectId, "--nickname", nickname]
1763
1847
  }
1764
- if (
1765
- compact.includes("成员角色卡片") ||
1766
- compact.includes("角色卡片") ||
1767
- compact.includes("成员卡片") ||
1768
- compact.includes("编辑成员信息") ||
1769
- compact.includes("修改成员信息") ||
1770
- compact.includes("设置角色卡片")
1771
- ) {
1848
+ if (hasMemberProfileCardIntent(text)) {
1772
1849
  if (!input.projectId) return ["context", "candidates", "--identity", identity]
1773
- return ["member-profile-edit", "--identity", identity, "--project", input.projectId]
1850
+ const roleTitle = extractMemberProfileFieldFromText(text, "roleTitle")
1851
+ const specialties = extractMemberProfileFieldFromText(text, "specialties")
1852
+ const experienceSummary = extractMemberProfileFieldFromText(text, "experienceSummary")
1853
+ const strengthsSummary = extractMemberProfileFieldFromText(text, "strengthsSummary")
1854
+ const taskPreferenceTags = extractMemberProfileFieldFromText(text, "taskPreferenceTags")
1855
+ const argv = ["member-profile-edit", "--identity", identity, "--project", input.projectId]
1856
+ if (roleTitle) argv.push("--roleTitle", roleTitle)
1857
+ if (specialties) argv.push("--specialties", specialties)
1858
+ if (experienceSummary) argv.push("--experienceSummary", experienceSummary)
1859
+ if (strengthsSummary) argv.push("--strengthsSummary", strengthsSummary)
1860
+ if (taskPreferenceTags) argv.push("--taskPreferenceTags", taskPreferenceTags)
1861
+ return argv
1774
1862
  }
1775
- if (compact.includes("成员备注") || compact.includes("备注成员") || compact.includes("给成员备注") || compact.includes("修改备注")) {
1863
+ if (
1864
+ compact.includes("成员备注") ||
1865
+ compact.includes("备注成员") ||
1866
+ compact.includes("给成员备注") ||
1867
+ compact.includes("修改备注") ||
1868
+ compact.includes("清空备注") ||
1869
+ compact.includes("删除备注")
1870
+ ) {
1776
1871
  if (!input.projectId) return ["context", "candidates", "--identity", identity]
1777
- const m = text.match(/(?:给|帮我给)?\s*([^,,\s]+)\s*(?:备注为|备注成|备注)\s*([^\n]+)$/)
1778
- const target = (m?.[1] ?? "").trim()
1779
- const remark = (m?.[2] ?? "").trim()
1872
+ const remarkIntent = extractMemberRemarkIntent(text)
1873
+ const target = String(remarkIntent?.target ?? "").trim()
1874
+ const remark = String(remarkIntent?.remark ?? "").trim()
1780
1875
  if (target && remark) {
1781
1876
  return ["panel", "member-remark", "--identity", identity, "--project", input.projectId, "--target", target, "--remark", remark]
1782
1877
  }
@@ -2385,8 +2480,20 @@ function fromText(input: SkillInput): string[] {
2385
2480
  }
2386
2481
  if (lower.includes("上传文件") || lower.includes("上传文档") || lower.includes("新增文档")) {
2387
2482
  if (!input.projectId) return ["context", "candidates", "--identity", identity]
2388
- if (!input.file || !input.title || !input.docType) return ["doc", "upload", "--identity", identity, "--project", input.projectId, "--interactive"]
2389
- return ["doc", "upload", "--identity", identity, "--project", input.projectId, "--name", input.title, "--type", input.docType, "--file", input.file]
2483
+ if (!input.file) return ["doc", "upload", "--identity", identity, "--project", input.projectId, "--interactive"]
2484
+ return [
2485
+ "doc",
2486
+ "upload",
2487
+ "--identity",
2488
+ identity,
2489
+ "--project",
2490
+ input.projectId,
2491
+ "--file",
2492
+ input.file,
2493
+ ...(input.title ? ["--name", input.title] : []),
2494
+ ...(input.docType ? ["--type", input.docType] : []),
2495
+ ...(input.desc ? ["--desc", input.desc] : []),
2496
+ ]
2390
2497
  }
2391
2498
  if (lower.includes("老规矩") || lower.includes("上次那套")) {
2392
2499
  if (input.projectId) return ["capsule", "recommend", "--identity", identity, "--project", input.projectId, "--query", input.query ?? ""]
@@ -2659,8 +2766,8 @@ function fromAction(input: SkillInput): string[] {
2659
2766
  ]
2660
2767
  case "doc.upload":
2661
2768
  if (!input.projectId) throw new Error("missing_projectId")
2662
- if (!input.file || !input.title || !input.docType) {
2663
- return ["doc", "upload", "--identity", identity, "--project", input.projectId, "--interactive", ...(input.title ? ["--name", input.title] : []), ...(input.docType ? ["--type", input.docType] : []), ...(input.file ? ["--file", input.file] : [])]
2769
+ if (!input.file) {
2770
+ return ["doc", "upload", "--identity", identity, "--project", input.projectId, "--interactive", ...(input.title ? ["--name", input.title] : []), ...(input.docType ? ["--type", input.docType] : [])]
2664
2771
  }
2665
2772
  return [
2666
2773
  "doc",
@@ -2669,12 +2776,10 @@ function fromAction(input: SkillInput): string[] {
2669
2776
  identity,
2670
2777
  "--project",
2671
2778
  input.projectId,
2672
- "--name",
2673
- input.title,
2674
- "--type",
2675
- input.docType,
2676
2779
  "--file",
2677
2780
  input.file,
2781
+ ...(input.title ? ["--name", input.title] : []),
2782
+ ...(input.docType ? ["--type", input.docType] : []),
2678
2783
  ...(input.desc ? ["--desc", input.desc] : []),
2679
2784
  ]
2680
2785
  case "doc.delete":