draftgo-cli 3.0.43 → 3.0.44

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/README.md CHANGED
@@ -353,6 +353,7 @@ checkout 会通过 MCP 获取元数据和专用下载地址,流式写入临时
353
353
  - `--allow-offline` / `--no-mcp-setup`:允许 connect 在 MCP 暂不可用时保存,或跳过宿主配置。
354
354
  - `--yes`:跳过支持该选项的交互确认。
355
355
  - `--mobile-check auto|always|never`:控制 `verify-ui` 是否执行。
356
+ - `--token auto|never`:`verify-ui` 默认读取 `.draftgo/config.json`,对与 `server` 同源的地址自动附加 `token=<SAT>`;配置无 SAT、跨源地址或 `never` 模式均不附加。
356
357
  - `--screenshot on-failure|always|never`:控制 UI 截图。
357
358
  - `--delivery local|preview|deploy`:控制 deploy 行为。
358
359
  - `--timeout <ms>`:控制 connect、MCP test 或 context 的远端请求超时。
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "draftgo-cli",
3
- "version": "3.0.43",
3
+ "version": "3.0.44",
4
4
  "description": "Install and manage the DraftGo skill across AI coding agents (Claude Code, Codex, Cursor, Windsurf, Antigravity, Copilot, Gemini, Kiro).",
5
5
  "bin": {
6
6
  "draftgo": "bin/draftgo.js"
@@ -79,7 +79,7 @@ context 一次准备信息
79
79
  ### 页面、导航和文档正文
80
80
 
81
81
  1. 运行 frontend 或 content context,并按需继续通过 MCP 定位资源、取得元数据。
82
- 2. Agent 根据任务自主设计;对已确定的 pages/nav/docs 批量 checkout。
82
+ 2. Agent 根据任务自主设计;页面开发优先考虑 Tailwind CSS 作为基础样式方案,并按任务需要搭配现有组件库;对已确定的 pages/nav/docs 批量 checkout。
83
83
  3. 按唯一资源 owner 读取、搜索和编辑 `.draftgo/worktree/` 正文;独立资源可并行。
84
84
  4. 主 Agent 汇总回读后统一运行一次 `draftgo check`,页面布局或交互变化时再统一运行 `draftgo verify-ui`。
85
85
  5. 用 `draftgo diff <type> <id>` 检查全部 base/local 差异,再运行对应的 `draftgo commit ...`。
@@ -2,7 +2,7 @@
2
2
  "schema_version": "1.0",
3
3
  "id": "draftgo",
4
4
  "name": "DraftGo 开发助手",
5
- "version": "3.0.43",
5
+ "version": "3.0.44",
6
6
  "entry": "SKILL.md",
7
7
  "description": "以 context 聚合编排、Skill/reference 原文、MCP 实时发现、长正文 checkout/commit、统一验证和完成日志为边界的 DraftGo 工作流。",
8
8
  "license": "MIT",
@@ -113,6 +113,8 @@ Important flags:
113
113
  --delivery <mode> (deploy) local | preview | deploy.
114
114
  --dry-run (push) Show diffs without committing.
115
115
  --mobile-check <mode> (verify-ui) auto | always | never.
116
+ --token <mode> (verify-ui) auto | never; auto appends the configured
117
+ SAT to same-origin URLs as the token query parameter.
116
118
  --screenshot <mode> (verify-ui) on-failure | always | never.
117
119
  --browser <name> (verify-ui) chromium | chrome | msedge.
118
120
  --selector <css> (verify-ui) Require a visible key element.
@@ -4,6 +4,7 @@ const fs = require('fs');
4
4
  const path = require('path');
5
5
  const { spawnSync } = require('child_process');
6
6
  const log = require('../logger');
7
+ const { configPath, loadProjectConfig } = require('../projectConfig');
7
8
 
8
9
  const UI_EXTENSIONS = new Set(['.css', '.scss', '.sass', '.less', '.html', '.htm', '.jsx', '.tsx', '.vue', '.svelte']);
9
10
 
@@ -50,6 +51,31 @@ function numberFlag(value, fallback, min, max) {
50
51
  return Number.isFinite(n) ? Math.max(min, Math.min(max, Math.round(n))) : fallback;
51
52
  }
52
53
 
54
+ function configuredUiUrl(projectDir, rawUrl, tokenMode = 'auto') {
55
+ if (tokenMode === 'never') return rawUrl;
56
+ if (!fs.existsSync(configPath(projectDir))) return rawUrl;
57
+
58
+ const config = loadProjectConfig(projectDir, { requireToken: false });
59
+ if (!config.token) return rawUrl;
60
+
61
+ let target;
62
+ try {
63
+ target = new URL(rawUrl);
64
+ } catch {
65
+ return rawUrl;
66
+ }
67
+ const server = new URL(config.server);
68
+ if (target.origin !== server.origin) return rawUrl;
69
+ target.searchParams.set('token', config.token);
70
+ return target.toString();
71
+ }
72
+
73
+ function redactUrlTokens(message) {
74
+ return String(message || '')
75
+ .replace(/([?&]token=)[^&#\s]+/gi, '$1<redacted>')
76
+ .replace(/\bsat_[A-Za-z0-9._~+/-]+/g, '<redacted>');
77
+ }
78
+
53
79
  function executableCandidates() {
54
80
  if (process.platform === 'win32') {
55
81
  const roots = [process.env.PROGRAMFILES, process.env['PROGRAMFILES(X86)'], process.env.LOCALAPPDATA].filter(Boolean);
@@ -93,12 +119,18 @@ async function launchBrowser(chromium, requested) {
93
119
  }
94
120
 
95
121
  async function verifyUi(projectDir, positional, flags = {}) {
96
- const url = String(flags.url || positional[0] || '').trim();
97
- if (!/^https?:\/\//i.test(url)) {
122
+ const rawUrl = String(flags.url || positional[0] || '').trim();
123
+ if (!/^https?:\/\//i.test(rawUrl)) {
98
124
  log.err('用法:draftgo verify-ui <http://localhost:port/path>');
99
125
  return 1;
100
126
  }
101
127
 
128
+ const tokenMode = String(flags.token || 'auto').toLowerCase();
129
+ if (!['auto', 'never'].includes(tokenMode)) {
130
+ log.err('--token 在 verify-ui 中只支持 auto、never。');
131
+ return 1;
132
+ }
133
+
102
134
  const mode = String(flags['mobile-check'] || 'auto').toLowerCase();
103
135
  if (!['auto', 'always', 'never'].includes(mode)) {
104
136
  log.err('--mobile-check 只支持 auto、always、never。');
@@ -110,6 +142,14 @@ async function verifyUi(projectDir, positional, flags = {}) {
110
142
  return 0;
111
143
  }
112
144
 
145
+ let url;
146
+ try {
147
+ url = configuredUiUrl(projectDir, rawUrl, tokenMode);
148
+ } catch (err) {
149
+ log.err(`无法读取 verify-ui 的项目配置:${err.message}`);
150
+ return 1;
151
+ }
152
+
113
153
  let chromium;
114
154
  try {
115
155
  ({ chromium } = require('playwright-core'));
@@ -133,8 +173,8 @@ async function verifyUi(projectDir, positional, flags = {}) {
133
173
  const page = await browser.newPage({ viewport: { width, height } });
134
174
  const consoleErrors = [];
135
175
  const pageErrors = [];
136
- page.on('console', (msg) => { if (msg.type() === 'error') consoleErrors.push(msg.text()); });
137
- page.on('pageerror', (err) => pageErrors.push(err.message));
176
+ page.on('console', (msg) => { if (msg.type() === 'error') consoleErrors.push(redactUrlTokens(msg.text())); });
177
+ page.on('pageerror', (err) => pageErrors.push(redactUrlTokens(err.message)));
138
178
 
139
179
  const response = await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 30000 });
140
180
  if (waitMs) await page.waitForTimeout(waitMs);
@@ -187,7 +227,7 @@ async function verifyUi(projectDir, positional, flags = {}) {
187
227
  if (screenshotPath) log.info(`截图:${screenshotPath}`);
188
228
  return 0;
189
229
  } catch (err) {
190
- log.err(`UI smoke check 失败:${err.message}`);
230
+ log.err(`UI smoke check 失败:${redactUrlTokens(err.message)}`);
191
231
  return 1;
192
232
  } finally {
193
233
  if (browser) await browser.close().catch(() => {});
@@ -198,3 +238,5 @@ module.exports = verifyUi;
198
238
  module.exports.decideMobileCheck = decideMobileCheck;
199
239
  module.exports.gitChangedFiles = gitChangedFiles;
200
240
  module.exports.isUiFile = isUiFile;
241
+ module.exports.configuredUiUrl = configuredUiUrl;
242
+ module.exports.redactUrlTokens = redactUrlTokens;