gaoding-cli 1.0.0-alpha.5

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.
Files changed (177) hide show
  1. package/CHANGELOG.md +88 -0
  2. package/LICENSE +21 -0
  3. package/README.md +136 -0
  4. package/SECURITY.md +34 -0
  5. package/dist/bin/gd-cli.d.ts +2 -0
  6. package/dist/bin/gd-cli.js +10 -0
  7. package/dist/src/api/app-runner.d.ts +33 -0
  8. package/dist/src/api/app-runner.js +1177 -0
  9. package/dist/src/api/dam-client.d.ts +111 -0
  10. package/dist/src/api/dam-client.js +897 -0
  11. package/dist/src/api/direct-auth.d.ts +3 -0
  12. package/dist/src/api/direct-auth.js +11 -0
  13. package/dist/src/api/direct-client.d.ts +27 -0
  14. package/dist/src/api/direct-client.js +151 -0
  15. package/dist/src/api/direct-tools.d.ts +43 -0
  16. package/dist/src/api/direct-tools.js +1155 -0
  17. package/dist/src/api/hub-client.d.ts +20 -0
  18. package/dist/src/api/hub-client.js +99 -0
  19. package/dist/src/api/sso-client.d.ts +60 -0
  20. package/dist/src/api/sso-client.js +140 -0
  21. package/dist/src/api/task-poller.d.ts +38 -0
  22. package/dist/src/api/task-poller.js +72 -0
  23. package/dist/src/api/tool-invoker.d.ts +12 -0
  24. package/dist/src/api/tool-invoker.js +11 -0
  25. package/dist/src/api/usage-client.d.ts +39 -0
  26. package/dist/src/api/usage-client.js +179 -0
  27. package/dist/src/auth/credential-store-v2.d.ts +12 -0
  28. package/dist/src/auth/credential-store-v2.js +59 -0
  29. package/dist/src/commands/auth.d.ts +2 -0
  30. package/dist/src/commands/auth.js +191 -0
  31. package/dist/src/commands/dam.d.ts +2 -0
  32. package/dist/src/commands/dam.js +293 -0
  33. package/dist/src/commands/models.d.ts +2 -0
  34. package/dist/src/commands/models.js +78 -0
  35. package/dist/src/commands/org.d.ts +2 -0
  36. package/dist/src/commands/org.js +137 -0
  37. package/dist/src/commands/skills.d.ts +2 -0
  38. package/dist/src/commands/skills.js +213 -0
  39. package/dist/src/commands/tools.d.ts +4 -0
  40. package/dist/src/commands/tools.js +383 -0
  41. package/dist/src/commands/update.d.ts +2 -0
  42. package/dist/src/commands/update.js +167 -0
  43. package/dist/src/commands/usage.d.ts +7 -0
  44. package/dist/src/commands/usage.js +43 -0
  45. package/dist/src/commands/workflows.d.ts +3 -0
  46. package/dist/src/commands/workflows.js +398 -0
  47. package/dist/src/core/auth/auth-provider.d.ts +8 -0
  48. package/dist/src/core/auth/auth-provider.js +12 -0
  49. package/dist/src/core/auth/device-oauth-provider.d.ts +12 -0
  50. package/dist/src/core/auth/device-oauth-provider.js +124 -0
  51. package/dist/src/core/auth/org-manager.d.ts +26 -0
  52. package/dist/src/core/auth/org-manager.js +224 -0
  53. package/dist/src/core/auth/signature.d.ts +19 -0
  54. package/dist/src/core/auth/signature.js +33 -0
  55. package/dist/src/core/auth/types.d.ts +52 -0
  56. package/dist/src/core/auth/types.js +3 -0
  57. package/dist/src/core/output/cli-error.d.ts +5 -0
  58. package/dist/src/core/output/cli-error.js +8 -0
  59. package/dist/src/core/output/detector.d.ts +5 -0
  60. package/dist/src/core/output/detector.js +14 -0
  61. package/dist/src/core/output/engine.d.ts +32 -0
  62. package/dist/src/core/output/engine.js +77 -0
  63. package/dist/src/core/output/envelope.d.ts +40 -0
  64. package/dist/src/core/output/envelope.js +119 -0
  65. package/dist/src/core/output/index.d.ts +4 -0
  66. package/dist/src/core/output/index.js +4 -0
  67. package/dist/src/core/output/live-display.d.ts +15 -0
  68. package/dist/src/core/output/live-display.js +111 -0
  69. package/dist/src/core/output/result-card.d.ts +18 -0
  70. package/dist/src/core/output/result-card.js +39 -0
  71. package/dist/src/core/prompt/index.d.ts +31 -0
  72. package/dist/src/core/prompt/index.js +36 -0
  73. package/dist/src/io.d.ts +14 -0
  74. package/dist/src/io.js +31 -0
  75. package/dist/src/middleware/auth.d.ts +3 -0
  76. package/dist/src/middleware/auth.js +74 -0
  77. package/dist/src/middleware/error-handler.d.ts +3 -0
  78. package/dist/src/middleware/error-handler.js +431 -0
  79. package/dist/src/middleware/interactive-params.d.ts +14 -0
  80. package/dist/src/middleware/interactive-params.js +53 -0
  81. package/dist/src/middleware/output.d.ts +14 -0
  82. package/dist/src/middleware/output.js +546 -0
  83. package/dist/src/models/model-catalog.d.ts +26 -0
  84. package/dist/src/models/model-catalog.js +216 -0
  85. package/dist/src/program.d.ts +2 -0
  86. package/dist/src/program.js +152 -0
  87. package/dist/src/registry/agent-contracts.d.ts +43 -0
  88. package/dist/src/registry/agent-contracts.js +483 -0
  89. package/dist/src/registry/app-loader.d.ts +2 -0
  90. package/dist/src/registry/app-loader.js +70 -0
  91. package/dist/src/registry/direct-registry.d.ts +11 -0
  92. package/dist/src/registry/direct-registry.js +234 -0
  93. package/dist/src/registry/registry-cache.d.ts +10 -0
  94. package/dist/src/registry/registry-cache.js +52 -0
  95. package/dist/src/registry/registry-client.d.ts +28 -0
  96. package/dist/src/registry/registry-client.js +50 -0
  97. package/dist/src/registry/types.d.ts +69 -0
  98. package/dist/src/registry/types.js +1 -0
  99. package/dist/src/tty/auth-presenter.d.ts +3 -0
  100. package/dist/src/tty/auth-presenter.js +21 -0
  101. package/dist/src/update/install-source.d.ts +19 -0
  102. package/dist/src/update/install-source.js +139 -0
  103. package/dist/src/update/notifier.d.ts +2 -0
  104. package/dist/src/update/notifier.js +59 -0
  105. package/dist/src/update/update-checker.d.ts +22 -0
  106. package/dist/src/update/update-checker.js +110 -0
  107. package/dist/src/update/version.d.ts +9 -0
  108. package/dist/src/update/version.js +52 -0
  109. package/dist/src/utils/agent-skill-installer.d.ts +57 -0
  110. package/dist/src/utils/agent-skill-installer.js +389 -0
  111. package/dist/src/utils/capability-metadata.d.ts +18 -0
  112. package/dist/src/utils/capability-metadata.js +88 -0
  113. package/dist/src/utils/capability-presenter.d.ts +4 -0
  114. package/dist/src/utils/capability-presenter.js +190 -0
  115. package/dist/src/utils/config.d.ts +16 -0
  116. package/dist/src/utils/config.js +54 -0
  117. package/dist/src/utils/credential-permissions.d.ts +2 -0
  118. package/dist/src/utils/credential-permissions.js +22 -0
  119. package/dist/src/utils/ecommerce-input-guidance.d.ts +15 -0
  120. package/dist/src/utils/ecommerce-input-guidance.js +85 -0
  121. package/dist/src/utils/endpoints.d.ts +52 -0
  122. package/dist/src/utils/endpoints.js +258 -0
  123. package/dist/src/utils/enrich-upload-params.d.ts +6 -0
  124. package/dist/src/utils/enrich-upload-params.js +11 -0
  125. package/dist/src/utils/entitlement.d.ts +17 -0
  126. package/dist/src/utils/entitlement.js +146 -0
  127. package/dist/src/utils/gd-home.d.ts +7 -0
  128. package/dist/src/utils/gd-home.js +26 -0
  129. package/dist/src/utils/help-verify.d.ts +9 -0
  130. package/dist/src/utils/help-verify.js +41 -0
  131. package/dist/src/utils/input-json.d.ts +3 -0
  132. package/dist/src/utils/input-json.js +61 -0
  133. package/dist/src/utils/list-output-format.d.ts +10 -0
  134. package/dist/src/utils/list-output-format.js +34 -0
  135. package/dist/src/utils/logger.d.ts +6 -0
  136. package/dist/src/utils/logger.js +19 -0
  137. package/dist/src/utils/matting-compose.d.ts +10 -0
  138. package/dist/src/utils/matting-compose.js +45 -0
  139. package/dist/src/utils/open-browser.d.ts +1 -0
  140. package/dist/src/utils/open-browser.js +4 -0
  141. package/dist/src/utils/output-path.d.ts +5 -0
  142. package/dist/src/utils/output-path.js +70 -0
  143. package/dist/src/utils/redact.d.ts +3 -0
  144. package/dist/src/utils/redact.js +96 -0
  145. package/dist/src/utils/reference-image.d.ts +8 -0
  146. package/dist/src/utils/reference-image.js +43 -0
  147. package/dist/src/utils/resolve-app-local-images.d.ts +8 -0
  148. package/dist/src/utils/resolve-app-local-images.js +84 -0
  149. package/dist/src/utils/sensitive-path.d.ts +6 -0
  150. package/dist/src/utils/sensitive-path.js +69 -0
  151. package/dist/src/utils/settings-store.d.ts +42 -0
  152. package/dist/src/utils/settings-store.js +50 -0
  153. package/dist/src/utils/sleep.d.ts +1 -0
  154. package/dist/src/utils/sleep.js +3 -0
  155. package/dist/src/utils/spinner.d.ts +2 -0
  156. package/dist/src/utils/spinner.js +4 -0
  157. package/dist/src/utils/static-help.d.ts +2 -0
  158. package/dist/src/utils/static-help.js +3 -0
  159. package/dist/src/utils/tool-display.d.ts +10 -0
  160. package/dist/src/utils/tool-display.js +55 -0
  161. package/dist/src/utils/transient-network-error.d.ts +4 -0
  162. package/dist/src/utils/transient-network-error.js +40 -0
  163. package/dist/src/utils/url-safety.d.ts +6 -0
  164. package/dist/src/utils/url-safety.js +67 -0
  165. package/dist/src/utils/write-app-deliverables.d.ts +18 -0
  166. package/dist/src/utils/write-app-deliverables.js +386 -0
  167. package/package.json +91 -0
  168. package/skills/gd-cli/SKILL.md +57 -0
  169. package/skills/gd-cli/references/auth.md +31 -0
  170. package/skills/gd-cli/references/deliverables.md +22 -0
  171. package/skills/gd-cli/references/entitlement.md +21 -0
  172. package/skills/gd-cli/references/errors.md +19 -0
  173. package/skills/gd-cli/references/org.md +18 -0
  174. package/skills/gd-cli/references/sop.md +25 -0
  175. package/skills/gd-cli/references/tools.md +29 -0
  176. package/skills/gd-cli/references/update.md +16 -0
  177. package/skills/gd-cli/references/workflows.md +22 -0
@@ -0,0 +1,234 @@
1
+ const commonRateLimit = { rpm: 30, daily: 1000 };
2
+ const requiredAkskHeaders = ["X-AccessKey", "X-Signature", "X-Timestamp"];
3
+ export const DIRECT_TOOLS = [
4
+ tool("asset.upload", ["upload", "cdn.upload"], "素材上传(CDN)", "上传本地文件生成可访问 CDN URL;不做 DAM 入库", "asset", [
5
+ param("file", "file", true, "--file", "本地图片/视频文件"),
6
+ ]),
7
+ tool("text.title", ["title"], "智能标题", "根据商品或场景 brief 生成标题", "text", [
8
+ param("prompt", "string", false, "--prompt", "标题需求"),
9
+ param("brief", "string", false, "--brief", "同 --prompt"),
10
+ ]),
11
+ tool("text.prompt", ["prompt", "prompt-advise", "text.prompt-advise"], "提示词优化", "根据 brief 和可选参考图扩写生图提示词", "text", [
12
+ param("prompt", "string", true, "--prompt", "原始需求"),
13
+ param("image", "file", false, "--image", "参考图 URL 或本地文件"),
14
+ param("require_image", "boolean", false, "--require-image", "要求必须使用真实参考图,缺图时不退化为纯文本提示词"),
15
+ ]),
16
+ tool("image.cutout", ["cutout", "image.matting", "matting"], "智能抠图", "用户要去背景、透明底、白底图、批量抠图时使用;默认输出透明 PNG,并保留 mask/source 便于排查", "image", [
17
+ param("image", "file", true, "--image", "图片 URL 或本地文件"),
18
+ param("mode", "string", false, "--mode", "auto / portrait / product / graphic"),
19
+ param("compose_mask", "boolean", false, "--compose-mask", "将后端 mask 与原图合成透明 PNG,默认开启"),
20
+ param("raw_mask", "boolean", false, "--raw-mask", "仅返回后端 mask,不做合成"),
21
+ ]),
22
+ tool("image.generate", ["generate"], "AI 生图", "用户要生成商品主图、海报、场景图、种草图时使用;可传商品图作为参考", "image", [
23
+ param("prompt", "string", true, "--prompt", "生图提示词"),
24
+ param("image", "file", false, "--image", "参考图 URL 或本地文件"),
25
+ param("ratio", "string", false, "--ratio", "比例,如 1:1 / 3:4"),
26
+ param("model", "string", false, "--model", "模型 code / 名称 / auto"),
27
+ param("require_image", "boolean", false, "--require-image", "要求必须使用真实参考图,缺图时不退化为文生图"),
28
+ param("style_code", "string", false, "--style-code", "模型或风格 code"),
29
+ ], true, 600),
30
+ tool("image.svg", ["vectorize", "svg"], "转矢量图", "图片转 SVG", "image", [
31
+ param("image", "file", true, "--image", "图片 URL 或本地文件"),
32
+ param("mode", "string", false, "--mode", "auto / binary"),
33
+ ]),
34
+ tool("image.super-res", ["upscale", "super-res", "image.upscale"], "高清放大", "用户要图片高清化、变清晰、放大、提升分辨率时使用,支持 hd / uhd / uhd-plus", "image", [
35
+ param("image", "file", true, "--image", "图片 URL 或本地文件"),
36
+ param("mode", "string", false, "--mode", "hd / uhd / uhd-plus"),
37
+ ], true, 600),
38
+ tool("video.generate", ["video", "generate-video", "text-to-video", "image-to-video", "稿定视频", "视频生成", "文生视频", "图生视频", "动画短片"], "AI 视频", "稿定 AI 视频生成能力,支持文生视频、图生视频和动画短片生成", "video", [
39
+ param("prompt", "string", true, "--prompt", "视频提示词"),
40
+ param("image", "file", false, "--image", "首帧参考图 URL 或本地文件"),
41
+ param("duration", "string", false, "--duration", "时长"),
42
+ param("model", "string", false, "--model", "模型 code / 名称 / auto"),
43
+ param("require_image", "boolean", false, "--require-image", "要求必须使用真实首帧参考图,缺图时不退化为文生视频"),
44
+ param("style_code", "string", false, "--style-code", "模型或风格 code"),
45
+ ], true, 900),
46
+ ];
47
+ export const PUBLIC_DIRECT_TOOLS = DIRECT_TOOLS.filter(isPublicToolSpec);
48
+ export const DIRECT_APPS = [
49
+ {
50
+ id: "listing-gallery",
51
+ aliases: [],
52
+ name: "商品图库素材包",
53
+ description: "从一张商品图生成可上架的 Listing 图库,包含白底主图、单卖点证明图、材质结构细节图、生活方式图、标题卖点和上线检查说明",
54
+ category: "ecommerce",
55
+ internal_apps: [],
56
+ required_tools: ["image.cutout", "text.prompt", "image.generate", "text.title"],
57
+ asset_operations: ["asset.upload"],
58
+ estimated_duration: 1500,
59
+ input: [
60
+ param("image", "file", true, "--image", "商品图片 URL 或本地文件"),
61
+ param("brief", "string", true, "--brief", "商品卖点、类目、目标平台或图库需求"),
62
+ param("ratio", "string", false, "--ratio", "统一输出比例;未指定时按图位使用 1:1 / 4:5"),
63
+ param("copy_mode", "string", false, "--copy-mode", "文案模式:auto / render-text / layout-copy / no-text / ask;auto 会按 brief 判断是否需要画内短文案"),
64
+ param("model", "string", false, "--model", "生图模型 code / 名称 / auto;未指定时按 Web 默认返回顺序选择"),
65
+ ],
66
+ output: outputSpec("workflow"),
67
+ outputs: ["manifest.json", "README.md", "assets/"],
68
+ examples: [
69
+ "gd-cli workflows run listing-gallery --image ./sku.png --brief \"夏季防晒衣,轻薄透气,户外通勤;卖点图短文案:轻薄防晒 通勤无负担\" --copy-mode render-text",
70
+ ],
71
+ supports_batch: false,
72
+ consumes_quota: true,
73
+ },
74
+ {
75
+ id: "pdp-a-plus",
76
+ aliases: [],
77
+ name: "详情页/A+模块素材包",
78
+ description: "按购买说服顺序生成详情页/A+模块素材,包含首屏 Hero、痛点解决、结构细节、真实使用、对比规格和模块文案",
79
+ category: "ecommerce",
80
+ internal_apps: [],
81
+ required_tools: ["image.cutout", "text.prompt", "image.generate", "text.title"],
82
+ asset_operations: ["asset.upload"],
83
+ estimated_duration: 1800,
84
+ input: [
85
+ param("image", "file", true, "--image", "商品图片 URL 或本地文件"),
86
+ param("brief", "string", true, "--brief", "商品卖点、购买疑虑、功能参数或详情页需求"),
87
+ param("ratio", "string", false, "--ratio", "统一输出比例;未指定时按模块使用 16:9 / 4:5 / 1:1"),
88
+ param("copy_mode", "string", false, "--copy-mode", "文案模式:auto / render-text / layout-copy / no-text / ask;auto 会按 brief 判断是否需要画内短文案"),
89
+ param("model", "string", false, "--model", "生图模型 code / 名称 / auto;未指定时按 Web 默认返回顺序选择"),
90
+ ],
91
+ output: outputSpec("workflow"),
92
+ outputs: ["manifest.json", "README.md", "assets/"],
93
+ examples: [
94
+ "gd-cli workflows run pdp-a-plus --image ./air-purifier.png --brief \"桌面空气净化器,静音,滤芯可更换,适合卧室;首屏短文案:静音净化 安心入睡\" --copy-mode render-text",
95
+ ],
96
+ supports_batch: false,
97
+ consumes_quota: true,
98
+ },
99
+ {
100
+ id: "social-seeding-pack",
101
+ aliases: [],
102
+ name: "小红书种草图文包",
103
+ description: "生成更像真实创作者内容的小红书种草图文,包含移动端封面图、真实场景图、标题、正文、标签和首屏检查说明",
104
+ category: "ecommerce",
105
+ internal_apps: [],
106
+ required_tools: ["image.cutout", "text.prompt", "image.generate", "text.title"],
107
+ asset_operations: ["asset.upload"],
108
+ estimated_duration: 1200,
109
+ input: [
110
+ param("image", "file", true, "--image", "商品图片 URL 或本地文件"),
111
+ param("brief", "string", true, "--brief", "商品卖点、笔记角度、目标人群或种草需求"),
112
+ param("ratio", "string", false, "--ratio", "统一输出比例;未指定时封面 3:4、场景图 9:16"),
113
+ param("copy_mode", "string", false, "--copy-mode", "文案模式:auto / render-text / layout-copy / no-text / ask;auto 会按 brief 判断是否需要画内短文案"),
114
+ param("model", "string", false, "--model", "生图模型 code / 名称 / auto;未指定时按 Web 默认返回顺序选择"),
115
+ ],
116
+ output: outputSpec("workflow"),
117
+ outputs: ["manifest.json", "README.md", "assets/"],
118
+ examples: [
119
+ "gd-cli workflows run social-seeding-pack --image ./serum.png --brief \"屏障修护精华,清爽不黏,适合通勤包分享;封面短文案:通勤包里的清爽修护\" --copy-mode render-text",
120
+ ],
121
+ supports_batch: false,
122
+ consumes_quota: true,
123
+ },
124
+ {
125
+ id: "campaign-kv-pack",
126
+ aliases: [],
127
+ name: "Campaign KV 多渠道素材包",
128
+ description: "生成可延展到官网、活动页、社媒和电商投放的无字 Campaign KV,包含多比例主视觉、标题利益点和渠道裁切建议",
129
+ category: "ecommerce",
130
+ internal_apps: [],
131
+ required_tools: ["image.cutout", "text.prompt", "image.generate", "text.title"],
132
+ asset_operations: ["asset.upload"],
133
+ estimated_duration: 1500,
134
+ input: [
135
+ param("image", "file", true, "--image", "商品图片 URL 或本地文件"),
136
+ param("brief", "string", true, "--brief", "Campaign 主题、目标人群、核心卖点和渠道"),
137
+ param("ratios", "string", false, "--ratios", "输出比例列表,默认 16:9,1:1,4:5"),
138
+ param("copy_mode", "string", false, "--copy-mode", "文案模式:auto / render-text / layout-copy / no-text / ask;auto 会按 brief 判断是否需要画内短文案"),
139
+ param("model", "string", false, "--model", "生图模型 code / 名称 / auto;未指定时按 Web 默认返回顺序选择"),
140
+ ],
141
+ output: outputSpec("workflow"),
142
+ outputs: ["manifest.json", "README.md", "assets/"],
143
+ examples: [
144
+ "gd-cli workflows run campaign-kv-pack --image ./running-shoes.png --brief \"城市跑鞋新品 Campaign,轻量缓震,面向通勤跑者;主标题:轻跑进城\" --copy-mode render-text",
145
+ ],
146
+ supports_batch: false,
147
+ consumes_quota: true,
148
+ },
149
+ ];
150
+ export const DIRECT_REGISTRY = {
151
+ version: "direct-20260521",
152
+ updated_at: "2026-05-21T00:00:00.000Z",
153
+ tools: DIRECT_TOOLS,
154
+ apps: DIRECT_APPS,
155
+ };
156
+ export function resolveToolSpec(id) {
157
+ return DIRECT_TOOLS.find((tool) => tool.name === id || tool.aliases?.includes(id));
158
+ }
159
+ export function resolvePublicToolSpec(id) {
160
+ return PUBLIC_DIRECT_TOOLS.find((tool) => tool.name === id || tool.aliases?.includes(id));
161
+ }
162
+ export function isPublicToolSpec(tool) {
163
+ return !tool.tags.includes("internal");
164
+ }
165
+ export function resolveAppSpec(id) {
166
+ return DIRECT_APPS.find((app) => app.id === id || app.aliases?.includes(id));
167
+ }
168
+ export function appToolDependencies(app) {
169
+ return uniqueStrings([
170
+ ...(app.required_tools ?? []),
171
+ ...(app.asset_operations ?? []).filter((id) => resolvePublicToolSpec(id)),
172
+ ]);
173
+ }
174
+ export function appsDependingOnTool(toolId) {
175
+ return DIRECT_APPS.filter((app) => appToolDependencies(app).includes(toolId));
176
+ }
177
+ function uniqueStrings(values) {
178
+ return [...new Set(values.filter(Boolean))];
179
+ }
180
+ function tool(name, aliases, displayName, description, category, input, async = false, timeout = 120, internal = false) {
181
+ return {
182
+ name,
183
+ aliases,
184
+ version: "1.0.0",
185
+ display_name: displayName,
186
+ description,
187
+ category,
188
+ tags: internal ? [category, "direct", "internal"] : [category, "direct"],
189
+ endpoint: `direct:${name}`,
190
+ method: "POST",
191
+ auth_required: true,
192
+ async,
193
+ timeout,
194
+ rate_limit: commonRateLimit,
195
+ input,
196
+ output: outputSpec(category),
197
+ examples: [
198
+ {
199
+ description,
200
+ input: {},
201
+ output: {},
202
+ },
203
+ ],
204
+ runtime: runtimeForTool(name),
205
+ required_env: requiredAkskHeaders,
206
+ };
207
+ }
208
+ function param(name, type, required, cliFlag, description) {
209
+ return {
210
+ name,
211
+ type,
212
+ required,
213
+ description,
214
+ cli_flag: cliFlag,
215
+ };
216
+ }
217
+ function outputSpec(type) {
218
+ return {
219
+ type,
220
+ properties: {
221
+ url: { type: "string", description: "输出资源 URL" },
222
+ text: { type: "string", description: "输出文本" },
223
+ },
224
+ };
225
+ }
226
+ function runtimeForTool(name) {
227
+ if (name === "image.generate" || name === "video.generate")
228
+ return "tool-intent-dify";
229
+ if (name === "image.super-res")
230
+ return "super-resolution";
231
+ if (name === "image.svg")
232
+ return "img2svg";
233
+ return "dify";
234
+ }
@@ -0,0 +1,10 @@
1
+ import type { RegistryResponse } from "./types.js";
2
+ import type { RegistryClient } from "./registry-client.js";
3
+ export declare class RegistryCache {
4
+ private client;
5
+ constructor(client: RegistryClient);
6
+ get(forceRefresh?: boolean): Promise<RegistryResponse>;
7
+ private readCache;
8
+ private writeCache;
9
+ private refreshInBackground;
10
+ }
@@ -0,0 +1,52 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { REGISTRY_CACHE_FILE, CACHE_TTL_MS } from "../utils/config.js";
4
+ import { logger } from "../utils/logger.js";
5
+ import { ensureCredentialDir, ensureCredentialFile } from "../utils/credential-permissions.js";
6
+ export class RegistryCache {
7
+ client;
8
+ constructor(client) {
9
+ this.client = client;
10
+ }
11
+ async get(forceRefresh = false) {
12
+ void forceRefresh;
13
+ const data = await this.client.fetchRegistry();
14
+ this.writeCache(data);
15
+ return data;
16
+ }
17
+ readCache() {
18
+ if (!fs.existsSync(REGISTRY_CACHE_FILE))
19
+ return null;
20
+ try {
21
+ ensureCredentialDir(path.dirname(REGISTRY_CACHE_FILE));
22
+ ensureCredentialFile(REGISTRY_CACHE_FILE);
23
+ const raw = fs.readFileSync(REGISTRY_CACHE_FILE, "utf-8");
24
+ const entry = JSON.parse(raw);
25
+ const age = Date.now() - new Date(entry.fetched_at).getTime();
26
+ if (age > CACHE_TTL_MS)
27
+ return null;
28
+ return entry.data;
29
+ }
30
+ catch {
31
+ return null;
32
+ }
33
+ }
34
+ writeCache(data) {
35
+ const dir = path.dirname(REGISTRY_CACHE_FILE);
36
+ ensureCredentialDir(dir);
37
+ const entry = {
38
+ fetched_at: new Date().toISOString(),
39
+ data,
40
+ };
41
+ fs.writeFileSync(REGISTRY_CACHE_FILE, JSON.stringify(entry, null, 2), { mode: 0o600 });
42
+ ensureCredentialFile(REGISTRY_CACHE_FILE);
43
+ }
44
+ refreshInBackground() {
45
+ this.client
46
+ .fetchRegistry()
47
+ .then((data) => this.writeCache(data))
48
+ .catch(() => {
49
+ logger.debug("Registry 后台刷新失败,继续使用缓存");
50
+ });
51
+ }
52
+ }
@@ -0,0 +1,28 @@
1
+ import type { HubClient } from "../api/hub-client.js";
2
+ import type { RegistryResponse } from "./types.js";
3
+ export declare class RegistryClient {
4
+ private client;
5
+ constructor(client: HubClient);
6
+ fetchRegistry(): Promise<RegistryResponse>;
7
+ getDetail(id: string): Promise<import("./types.js").ToolSpec | import("./types.js").AppSpec>;
8
+ search(query: string, options?: {
9
+ type?: string;
10
+ limit?: number;
11
+ }): Promise<{
12
+ results: ({
13
+ id: string;
14
+ type: string;
15
+ display_name: string;
16
+ description: string;
17
+ category: "asset" | "text" | "image" | "video" | "agent" | "template" | "infrastructure";
18
+ spec: import("./types.js").ToolSpec;
19
+ } | {
20
+ id: string;
21
+ type: string;
22
+ display_name: string;
23
+ description: string;
24
+ category: string;
25
+ spec: import("./types.js").AppSpec;
26
+ })[];
27
+ }>;
28
+ }
@@ -0,0 +1,50 @@
1
+ import { DIRECT_APPS, DIRECT_REGISTRY, PUBLIC_DIRECT_TOOLS, resolveAppSpec, resolveToolSpec, } from "./direct-registry.js";
2
+ export class RegistryClient {
3
+ client;
4
+ constructor(client) {
5
+ this.client = client;
6
+ }
7
+ async fetchRegistry() {
8
+ void this.client;
9
+ return DIRECT_REGISTRY;
10
+ }
11
+ async getDetail(id) {
12
+ const tool = resolveToolSpec(id);
13
+ if (tool)
14
+ return tool;
15
+ const app = resolveAppSpec(id);
16
+ if (app)
17
+ return app;
18
+ throw new Error(`未找到能力: ${id}`);
19
+ }
20
+ async search(query, options) {
21
+ const q = query.trim().toLowerCase();
22
+ const toolResults = PUBLIC_DIRECT_TOOLS.map((spec) => ({
23
+ id: spec.name,
24
+ type: "tool",
25
+ display_name: spec.display_name,
26
+ description: spec.description,
27
+ category: spec.category,
28
+ spec,
29
+ }));
30
+ const appResults = DIRECT_APPS.map((spec) => ({
31
+ id: spec.id,
32
+ type: "app",
33
+ display_name: spec.name,
34
+ description: spec.description,
35
+ category: spec.category,
36
+ spec,
37
+ }));
38
+ const all = [
39
+ ...(!options?.type || options.type === "tool" ? toolResults : []),
40
+ ...(!options?.type || options.type === "app" ? appResults : []),
41
+ ].filter((item) => {
42
+ if (!q)
43
+ return true;
44
+ return (item.id.toLowerCase().includes(q) ||
45
+ item.display_name.toLowerCase().includes(q) ||
46
+ item.description.toLowerCase().includes(q));
47
+ });
48
+ return { results: all.slice(0, options?.limit ?? all.length) };
49
+ }
50
+ }
@@ -0,0 +1,69 @@
1
+ export interface RegistryResponse {
2
+ version: string;
3
+ updated_at: string;
4
+ tools: ToolSpec[];
5
+ apps: AppSpec[];
6
+ }
7
+ export interface ToolSpec {
8
+ name: string;
9
+ aliases?: string[];
10
+ version: string;
11
+ display_name: string;
12
+ description: string;
13
+ category: "image" | "text" | "video" | "agent" | "infrastructure" | "template" | "asset";
14
+ tags: string[];
15
+ endpoint: string;
16
+ method: "GET" | "POST" | "PUT";
17
+ auth_required: boolean;
18
+ async: boolean;
19
+ timeout: number;
20
+ rate_limit: {
21
+ rpm: number;
22
+ daily: number;
23
+ };
24
+ input: ParamSpec[];
25
+ output: OutputSpec;
26
+ examples: ExampleSpec[];
27
+ runtime?: string;
28
+ required_env?: string[];
29
+ }
30
+ export interface AppSpec {
31
+ id: string;
32
+ aliases?: string[];
33
+ name: string;
34
+ description: string;
35
+ category: string;
36
+ internal_apps: string[];
37
+ required_tools: string[];
38
+ asset_operations?: string[];
39
+ estimated_duration: number;
40
+ input: ParamSpec[];
41
+ output: OutputSpec;
42
+ examples?: string[];
43
+ outputs?: string[];
44
+ supports_batch?: boolean;
45
+ consumes_quota?: boolean;
46
+ }
47
+ /** @deprecated Use AppSpec */
48
+ export type SceneSpec = AppSpec;
49
+ export interface ParamSpec {
50
+ name: string;
51
+ type: "string" | "number" | "boolean" | "file" | "object";
52
+ required: boolean;
53
+ default?: unknown;
54
+ enum?: unknown[];
55
+ description: string;
56
+ cli_flag: string;
57
+ }
58
+ export interface OutputSpec {
59
+ type: string;
60
+ properties: Record<string, {
61
+ type: string;
62
+ description: string;
63
+ }>;
64
+ }
65
+ export interface ExampleSpec {
66
+ description: string;
67
+ input: Record<string, unknown>;
68
+ output: Record<string, unknown>;
69
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,3 @@
1
+ export declare function printAuthQrAndLink(uri: string): Promise<void>;
2
+ export declare function emitAuthEvent(event: Record<string, unknown>): void;
3
+ export declare function formatRemainingSeconds(expiresAtMs: number): string;
@@ -0,0 +1,21 @@
1
+ import chalk from "chalk";
2
+ import qrcode from "qrcode";
3
+ import { getIO } from "../io.js";
4
+ export async function printAuthQrAndLink(uri) {
5
+ console.log(chalk.bold("请扫码或打开链接完成授权:"));
6
+ console.log(`${chalk.cyan(uri)}`);
7
+ if (getIO().stdoutIsTTY) {
8
+ const qr = await qrcode.toString(uri, { type: "terminal", small: true });
9
+ console.log("");
10
+ console.log(qr);
11
+ }
12
+ }
13
+ export function emitAuthEvent(event) {
14
+ if (getIO().stdoutIsTTY)
15
+ return;
16
+ console.log(JSON.stringify(event));
17
+ }
18
+ export function formatRemainingSeconds(expiresAtMs) {
19
+ const left = Math.max(0, Math.ceil((expiresAtMs - Date.now()) / 1000));
20
+ return `${left}s`;
21
+ }
@@ -0,0 +1,19 @@
1
+ export type PackageManager = "npm" | "pnpm" | "yarn" | "brew";
2
+ export type InstallSourceKind = "global" | "linked" | "local" | "npx";
3
+ export interface InstallSource {
4
+ manager: PackageManager;
5
+ kind: InstallSourceKind;
6
+ binPath: string;
7
+ realBinPath: string;
8
+ packageRoot?: string;
9
+ reason?: string;
10
+ }
11
+ export interface UpdateCommand {
12
+ command: string;
13
+ args: string[];
14
+ display: string;
15
+ }
16
+ export declare function detectInstallSource(managerOverride?: string): InstallSource;
17
+ export declare function classifyInstallSource(binPath: string, packageRoot: string | undefined, cwd: string): InstallSourceKind;
18
+ export declare function buildUpdateCommand(version: string, source: Pick<InstallSource, "manager">): UpdateCommand;
19
+ export declare function findPackageRoot(startFile: string): string | undefined;
@@ -0,0 +1,139 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { CLI_PACKAGE_NAME } from "../utils/config.js";
4
+ export function detectInstallSource(managerOverride) {
5
+ const binPath = process.argv[1] ?? "";
6
+ const realBinPath = safeRealpath(binPath) ?? binPath;
7
+ const packageRoot = findPackageRoot(realBinPath);
8
+ const manager = normalizeManager(managerOverride) ?? inferPackageManager(realBinPath);
9
+ const kind = process.env.GD_CLI_DEV === "1"
10
+ ? "linked"
11
+ : classifyInstallSource(binPath, packageRoot, process.cwd());
12
+ return {
13
+ manager,
14
+ kind,
15
+ binPath,
16
+ realBinPath,
17
+ packageRoot,
18
+ reason: blockedReason(kind),
19
+ };
20
+ }
21
+ export function classifyInstallSource(binPath, packageRoot, cwd) {
22
+ const normalizedBin = normalizePath(binPath);
23
+ const normalizedRoot = packageRoot ? normalizePath(packageRoot) : "";
24
+ if (normalizedRoot && !normalizedRoot.includes("/node_modules/")) {
25
+ return "linked";
26
+ }
27
+ if (normalizedBin.includes("/.npm/_npx/")
28
+ || normalizedRoot.includes("/.npm/_npx/")) {
29
+ return "npx";
30
+ }
31
+ const localNodeModules = `${normalizePath(path.resolve(cwd, "node_modules"))}/`;
32
+ if (normalizedBin.includes("/node_modules/.bin/")
33
+ || normalizedRoot.startsWith(localNodeModules)) {
34
+ return "local";
35
+ }
36
+ return "global";
37
+ }
38
+ export function buildUpdateCommand(version, source) {
39
+ const spec = `${CLI_PACKAGE_NAME}@${version}`;
40
+ if (source.manager === "pnpm") {
41
+ return {
42
+ command: "pnpm",
43
+ args: ["add", "-g", spec],
44
+ display: `pnpm add -g ${spec}`,
45
+ };
46
+ }
47
+ if (source.manager === "yarn") {
48
+ return {
49
+ command: "yarn",
50
+ args: ["global", "add", spec],
51
+ display: `yarn global add ${spec}`,
52
+ };
53
+ }
54
+ if (source.manager === "brew") {
55
+ return {
56
+ command: "brew",
57
+ args: ["upgrade", "gaoding-cli"],
58
+ display: "brew upgrade gaoding-cli",
59
+ };
60
+ }
61
+ return {
62
+ command: "npm",
63
+ args: ["install", "-g", spec],
64
+ display: `npm install -g ${spec}`,
65
+ };
66
+ }
67
+ function inferPackageManager(realBinPath) {
68
+ const forced = normalizeManager(process.env.GD_CLI_UPDATE_MANAGER);
69
+ if (forced)
70
+ return forced;
71
+ const userAgent = process.env.npm_config_user_agent ?? "";
72
+ if (userAgent.startsWith("pnpm/"))
73
+ return "pnpm";
74
+ if (userAgent.startsWith("yarn/"))
75
+ return "yarn";
76
+ if (userAgent.startsWith("npm/"))
77
+ return "npm";
78
+ const npmExecPath = process.env.npm_execpath ?? "";
79
+ if (npmExecPath.includes("pnpm"))
80
+ return "pnpm";
81
+ if (npmExecPath.includes("yarn"))
82
+ return "yarn";
83
+ if (realBinPath.includes(`${path.sep}.pnpm${path.sep}`))
84
+ return "pnpm";
85
+ if (realBinPath.includes(`${path.sep}.config${path.sep}yarn${path.sep}`))
86
+ return "yarn";
87
+ if (realBinPath.includes(`${path.sep}homebrew${path.sep}`) || realBinPath.includes(`${path.sep}Cellar${path.sep}`)) {
88
+ return "brew";
89
+ }
90
+ return "npm";
91
+ }
92
+ function normalizeManager(value) {
93
+ if (!value)
94
+ return null;
95
+ if (value === "npm" || value === "pnpm" || value === "yarn" || value === "brew") {
96
+ return value;
97
+ }
98
+ return null;
99
+ }
100
+ export function findPackageRoot(startFile) {
101
+ let dir = fs.existsSync(startFile) && fs.statSync(startFile).isDirectory()
102
+ ? startFile
103
+ : path.dirname(startFile);
104
+ while (dir && dir !== path.dirname(dir)) {
105
+ const pkg = path.join(dir, "package.json");
106
+ if (fs.existsSync(pkg)) {
107
+ try {
108
+ const parsed = JSON.parse(fs.readFileSync(pkg, "utf8"));
109
+ if (parsed.name === CLI_PACKAGE_NAME)
110
+ return dir;
111
+ }
112
+ catch {
113
+ return undefined;
114
+ }
115
+ }
116
+ dir = path.dirname(dir);
117
+ }
118
+ return undefined;
119
+ }
120
+ function safeRealpath(file) {
121
+ try {
122
+ return fs.realpathSync(file);
123
+ }
124
+ catch {
125
+ return undefined;
126
+ }
127
+ }
128
+ function normalizePath(value) {
129
+ return value.replace(/\\/g, "/").replace(/\/+$/, "");
130
+ }
131
+ function blockedReason(kind) {
132
+ if (kind === "linked")
133
+ return "当前 gd-cli 是 npm link 或本地开发 checkout";
134
+ if (kind === "local")
135
+ return "当前 gd-cli 安装在项目 node_modules 中";
136
+ if (kind === "npx")
137
+ return "当前 gd-cli 由 npx 临时运行";
138
+ return undefined;
139
+ }
@@ -0,0 +1,2 @@
1
+ import type { Command } from "commander";
2
+ export declare function maybeNotifyUpdate(command: Command): Promise<void>;