@xqyz/xq-cli 0.3.9 → 0.3.11
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/CHANGELOG.md +54 -1
- package/README.md +12 -4
- package/package.json +1 -1
- package/src/cli.mjs +264 -23
package/CHANGELOG.md
CHANGED
|
@@ -10,7 +10,59 @@
|
|
|
10
10
|
|
|
11
11
|
## [Unreleased]
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
(暂无未发布变更)
|
|
14
|
+
|
|
15
|
+
## [xq-cli 0.3.11 / WorkBuddy Plugin 0.10.27 / SkillHub 1.0.11] - 2026-08-27
|
|
16
|
+
|
|
17
|
+
### 写作质量与导出设置
|
|
18
|
+
|
|
19
|
+
- WorkBuddy 配置卡将“写作模式”改为“写作质量”,新增“旗舰智笔”,并保留旧参数兼容映射。
|
|
20
|
+
- 极短篇、超短篇按前端规则禁用专家智笔和旗舰智笔;图片来源选项保持直接展示。
|
|
21
|
+
- 表格、流程图、模板、编号、修改标记、页边距和图片尺寸等低频选项统一收纳到默认收起的“导出格式设置”。
|
|
22
|
+
- 同步 CLI、MCP App、Connector 和 Skill 文档,保持配置提交和规划流程不变。
|
|
23
|
+
- `@xqyz/xq-cli@0.3.11` 与 `@xqyz/workbuddy-plugin-xique@0.10.27` 待发布;SkillHub `1.0.11` 上传包待手动上传。
|
|
24
|
+
|
|
25
|
+
## [WorkBuddy Plugin 0.10.26 / SkillHub 1.0.10] - 2026-08-27
|
|
26
|
+
|
|
27
|
+
### MCP 中文显示名
|
|
28
|
+
|
|
29
|
+
- WorkBuddy MCP 配置键统一写入“喜鹊标书”,安装器会将已有 `xique-bid` 配置迁移为中文键并保留原有运行参数。
|
|
30
|
+
- Connector 清单、安装提示和 MCP 初始化名称同步为“喜鹊标书”;Connector ID、工具命名空间和功能路径保持不变。
|
|
31
|
+
- `@xqyz/workbuddy-plugin-xique@0.10.26` 已发布,`latest` 与 `workbuddy-stable` 均指向该版本;SkillHub `1.0.10` 待手动上传。
|
|
32
|
+
|
|
33
|
+
## [WorkBuddy Plugin 0.10.25 / SkillHub 1.0.9] - 2026-08-26
|
|
34
|
+
|
|
35
|
+
### Plugin 发布
|
|
36
|
+
|
|
37
|
+
- WorkBuddy Plugin 固定依赖 `@xqyz/xq-cli@0.3.10`,MCP 运行时拒绝低于该版本的 CLI。
|
|
38
|
+
- MCP 初始化信息的用户可见名称为“喜鹊标书”,保留 `xique-bid` Connector ID、工具命名空间和功能路径不变。
|
|
39
|
+
- Windows 安装器的临时 npm 缓存改为异步清理,避免升级后残留句柄影响 WorkBuddy 重启。
|
|
40
|
+
- `@xqyz/workbuddy-plugin-xique@0.10.25` 已发布,`latest` 与 `workbuddy-stable` 均指向该版本;SkillHub `1.0.9` 上传包已生成,待手动上传。
|
|
41
|
+
|
|
42
|
+
## [WorkBuddy Plugin 0.10.24 / SkillHub 1.0.8] - 2026-08-26
|
|
43
|
+
|
|
44
|
+
### MCP 中文展示名
|
|
45
|
+
|
|
46
|
+
- MCP 初始化信息的用户可见名称改为“喜鹊标书”,同时保留 `xique-bid` 内部标识、工具命名空间和配置升级键不变。
|
|
47
|
+
|
|
48
|
+
### CLI 本地登录页视觉升级
|
|
49
|
+
|
|
50
|
+
- 登录页改为响应式双栏工作台,补充一次登录复用、分阶段工作流和 Key 轮换等接入信息。
|
|
51
|
+
- API Key 说明改为“凭证保存在本机,后续命令无需重复输入”,保留 API Key 登录与浏览器授权两条入口及原有提交接口。
|
|
52
|
+
|
|
53
|
+
### CLI 登录页支持 API Key
|
|
54
|
+
|
|
55
|
+
- `xq-cli login` 默认打开本机登录页,普通用户可在页面中选择浏览器授权或输入 API Key。
|
|
56
|
+
- API Key 只通过本机回环地址提交,由 CLI 调用 `/user/info` 验证后保存;不会进入 URL 或日志。
|
|
57
|
+
- 保留 `xq-cli login --browser` 直接打开浏览器授权,以及 `--no-open` 手动复制本机页面地址。
|
|
58
|
+
|
|
59
|
+
### WorkBuddy Skill 自助更新
|
|
60
|
+
|
|
61
|
+
- 用户只需说“更新喜鹊标书”或“升级喜鹊标书”,即可授权拉取正式 SkillHub `@org-kkw9656k/xique-ai`,无需重复粘贴完整安装提示。
|
|
62
|
+
- 安装器优先下载并校验 SkillHub 最新包;远端不可用、版本落后或要求更高运行版本时使用兼容的内置/已安装 Skill,不覆盖现有新版本。
|
|
63
|
+
- SkillHub 下载只接受经过身份、版本、路径、文件类型和大小校验的 Skill Markdown 内容;更新仍会备份旧 Skill,并在新会话中生效。
|
|
64
|
+
|
|
65
|
+
## [0.3.9 / WorkBuddy Plugin 0.10.23 / SkillHub 1.0.6] - 2026-08-26
|
|
14
66
|
|
|
15
67
|
### WorkBuddy 规划模式自动推进
|
|
16
68
|
|
|
@@ -18,6 +70,7 @@
|
|
|
18
70
|
- WorkBuddy 检测到 `analysis_ready` 后自动对同一 `cid` 执行 `plan confirm-outline`,不再展示 `analysis-review` 或智能解读确认卡。
|
|
19
71
|
- 已被旧版本误标失败、但错误中已记录解析 `success=3` 的规划任务,在查询同一 `runId` 时会原地恢复并自动确认生成大纲。
|
|
20
72
|
- 保留大纲和目录人工确认闸门;自动推进只覆盖后台智能解读到大纲生成这一段,不会提前生成正文。
|
|
73
|
+
- WorkBuddy Plugin `0.10.22` 发布时依赖范围被 npm 写成 `^0.3.9`,已弃用且未进入 `workbuddy-stable`;`0.10.23` 恢复固定依赖 `0.3.9`。
|
|
21
74
|
|
|
22
75
|
## [0.3.8 / WorkBuddy Plugin 0.10.21 / SkillHub 1.0.5] - 2026-08-25
|
|
23
76
|
|
package/README.md
CHANGED
|
@@ -76,7 +76,15 @@ xq-cli export --cid <cid> --out D:\output
|
|
|
76
76
|
|
|
77
77
|
Fresh installs default to the production API address `https://ai.bidfile.qianlima.com/api`. Use `--base-url` only when you need to target another API endpoint.
|
|
78
78
|
|
|
79
|
-
`login` now defaults to browser
|
|
79
|
+
`login` now defaults to a local page with browser and API Key choices. If you explicitly pass `--name` and `--password`, the CLI uses password login. If you pass `--api-key`, it saves the API key locally and uses it for later requests.
|
|
80
|
+
|
|
81
|
+
When no credential flags are supplied, `xq-cli login` opens a local login page on
|
|
82
|
+
`127.0.0.1` with both choices: browser authorization or an API Key from the
|
|
83
|
+
Xique API Key management page. The page submits the Key only to the local CLI,
|
|
84
|
+
which verifies it with `/user/info` before saving it to the user-scoped config.
|
|
85
|
+
Use `xq-cli login --browser` to skip the local page and open browser
|
|
86
|
+
authorization directly, or `xq-cli login --no-open` to copy the local page URL
|
|
87
|
+
manually. Never paste an API Key into chat or commit it to a repository.
|
|
80
88
|
|
|
81
89
|
`directory view` reads the complete generated directory tree without triggering outline, directory, or content generation. Add `--json` for the raw API structure, or `--out <file-or-directory>` to save a UTF-8 JSON document.
|
|
82
90
|
|
|
@@ -176,7 +184,7 @@ The wizard will prompt for:
|
|
|
176
184
|
|
|
177
185
|
- source bid file
|
|
178
186
|
- article length
|
|
179
|
-
- writing
|
|
187
|
+
- writing quality (standard writing / expert / flagship)
|
|
180
188
|
- visual style
|
|
181
189
|
- table quantity / color / style
|
|
182
190
|
- planning mode
|
|
@@ -254,7 +262,7 @@ xq-cli choices export --json
|
|
|
254
262
|
Outline generation now supports frontend-backed options such as:
|
|
255
263
|
|
|
256
264
|
- `--page-scope` / `--page-scope-code`
|
|
257
|
-
- `--base`
|
|
265
|
+
- `--writing-quality` (0=standard writing, 1=expert, 2=flagship; `--base` remains a compatibility alias)
|
|
258
266
|
- `--theme-style`
|
|
259
267
|
- `--table-quantity`
|
|
260
268
|
- `--table-color`
|
|
@@ -283,7 +291,7 @@ Export now supports frontend-backed style options such as:
|
|
|
283
291
|
Example outline config:
|
|
284
292
|
|
|
285
293
|
```bash
|
|
286
|
-
xq-cli outline --cid <cid> --page-scope 3 --
|
|
294
|
+
xq-cli outline --cid <cid> --page-scope 3 --writing-quality flagship --theme-style 4 --table-quantity rich --table-color blue --table-style zebra --mermaid-style blue --knowledge-img 1 --scene-img 1 --plan-mode quick --wait
|
|
287
295
|
```
|
|
288
296
|
|
|
289
297
|
Example export config:
|
package/package.json
CHANGED
package/src/cli.mjs
CHANGED
|
@@ -183,6 +183,26 @@ const BASE_OPTIONS = [
|
|
|
183
183
|
{ value: '0', label: 'standard', description: 'standard writing', aliases: ['0', 'standard', 'default'] },
|
|
184
184
|
{ value: '1', label: 'expert', description: 'expert polish / public knowledge reference', aliases: ['1', 'expert', 'polish'] },
|
|
185
185
|
];
|
|
186
|
+
const WRITING_QUALITY_OPTIONS = [
|
|
187
|
+
{
|
|
188
|
+
value: 0,
|
|
189
|
+
label: 'standard-writing',
|
|
190
|
+
description: 'standard writing',
|
|
191
|
+
aliases: ['0', 'standard', 'standard-writing', '标准', '标准写作'],
|
|
192
|
+
},
|
|
193
|
+
{
|
|
194
|
+
value: 1,
|
|
195
|
+
label: 'expert',
|
|
196
|
+
description: 'expert writing',
|
|
197
|
+
aliases: ['1', 'expert', '专家智笔'],
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
value: 2,
|
|
201
|
+
label: 'flagship',
|
|
202
|
+
description: 'flagship deep-thinking writing',
|
|
203
|
+
aliases: ['2', 'flagship', '旗舰', '旗舰智笔'],
|
|
204
|
+
},
|
|
205
|
+
];
|
|
186
206
|
const THEME_STYLE_OPTIONS = [
|
|
187
207
|
{ value: 1, label: 'enhanced', description: 'enhanced image-rich layout', aliases: ['1', 'enhanced'] },
|
|
188
208
|
{ value: 2, label: 'table', description: 'table-first layout', aliases: ['2', 'table', 'table-first'] },
|
|
@@ -291,6 +311,7 @@ const PAGE_SCOPE_PROMPT_LABELS = {
|
|
|
291
311
|
const BASE_PROMPT_LABELS = {
|
|
292
312
|
0: '\u6807\u51C6\u5199\u4F5C',
|
|
293
313
|
1: '\u4E13\u5BB6\u667A\u7B14',
|
|
314
|
+
2: '\u65D7\u8230\u667A\u7B14',
|
|
294
315
|
};
|
|
295
316
|
const THEME_STYLE_PROMPT_LABELS = {
|
|
296
317
|
1: '\u589E\u5F3A\u56FE\u6587',
|
|
@@ -441,7 +462,7 @@ function printHelp() {
|
|
|
441
462
|
xq-cli: xique brand task CLI
|
|
442
463
|
|
|
443
464
|
Commands
|
|
444
|
-
login
|
|
465
|
+
login Open a local login page or save xique credentials locally
|
|
445
466
|
init Upload files and initialize a task
|
|
446
467
|
parse-status Query or wait for parse completion
|
|
447
468
|
period-status Query engineering project period confirmation status
|
|
@@ -472,6 +493,7 @@ Plan actions
|
|
|
472
493
|
|
|
473
494
|
Examples
|
|
474
495
|
xq-cli login
|
|
496
|
+
xq-cli login --no-open
|
|
475
497
|
xq-cli login --name your-account --password your-password
|
|
476
498
|
xq-cli login --api-key xq_sk_xxx
|
|
477
499
|
xq-cli login --browser
|
|
@@ -489,7 +511,7 @@ Examples
|
|
|
489
511
|
xq-cli outline --cid <cid> --wait --ignore-short-requirement
|
|
490
512
|
xq-cli outline --cid <cid> --wait --ignore-missing-bill
|
|
491
513
|
xq-cli outline --cid <cid> --wait --reference-type 0
|
|
492
|
-
xq-cli outline --cid <cid> --page-scope 3 --
|
|
514
|
+
xq-cli outline --cid <cid> --page-scope 3 --writing-quality flagship --theme-style 4 --table-quantity rich --plan-mode quick --wait
|
|
493
515
|
xq-cli outline view --cid <cid>
|
|
494
516
|
xq-cli outline view --cid <cid> --out D:\\output\\outline.json
|
|
495
517
|
xq-cli outline update --cid <cid> --file D:\\output\\outline.json --dry-run --json
|
|
@@ -517,8 +539,9 @@ Common options
|
|
|
517
539
|
--timeout-sec <n> Poll timeout in seconds, default 600
|
|
518
540
|
--interval-sec <n> Poll interval in seconds, default 10
|
|
519
541
|
--reference-type <0|1|2> Outline reference choice: 0=merge, 1=format only, 2=score only
|
|
520
|
-
--browser
|
|
542
|
+
--browser Skip the local login page and open browser authorization directly
|
|
521
543
|
--api-key <key> Save a user API key locally and verify it with /user/info
|
|
544
|
+
--no-open Do not open the local login page automatically
|
|
522
545
|
--interactive Open prompt menus for the current command
|
|
523
546
|
--dry-run Preview an outline update without saving it
|
|
524
547
|
--yes Confirm an outline update without an interactive prompt
|
|
@@ -529,7 +552,8 @@ Common options
|
|
|
529
552
|
Outline config
|
|
530
553
|
--page-scope <code> Full-length preset. See "xq-cli choices outline"
|
|
531
554
|
--page-scope-code <code> Alias of --page-scope
|
|
532
|
-
--
|
|
555
|
+
--writing-quality <0|1|2|standard|expert|flagship> 0=standard writing, 1=expert, 2=flagship
|
|
556
|
+
--base <0|1|standard|expert> Deprecated compatibility alias for writing quality
|
|
533
557
|
--theme-style <1|2|3|4|5|enhanced|table|rich|basic|text>
|
|
534
558
|
--table-quantity <0|1|2|none|few|rich>
|
|
535
559
|
--table-color <black|blue|red|green|purple|cyan|orange>
|
|
@@ -610,33 +634,42 @@ async function handleLogin(args, state) {
|
|
|
610
634
|
}, [
|
|
611
635
|
`login success: ${state.user.username}`,
|
|
612
636
|
'mode: api-key',
|
|
637
|
+
'authType: api-key',
|
|
613
638
|
`baseUrl: ${baseUrl}`,
|
|
614
639
|
`config: ${CONFIG_FILE}`,
|
|
615
640
|
]);
|
|
616
641
|
return;
|
|
617
642
|
}
|
|
618
643
|
const loginMode = resolveLoginMode(args);
|
|
619
|
-
const
|
|
620
|
-
? await loginWithBrowser(baseUrl, sourceFrom, args)
|
|
621
|
-
:
|
|
644
|
+
const loginResult = loginMode === 'browser'
|
|
645
|
+
? { result: await loginWithBrowser(baseUrl, sourceFrom, args), authType: 'token' }
|
|
646
|
+
: loginMode === 'page'
|
|
647
|
+
? await loginWithLoginPage(baseUrl, sourceFrom, args)
|
|
648
|
+
: { result: await loginWithPassword(baseUrl, sourceFrom, args), authType: 'token' };
|
|
649
|
+
const result = loginResult.result;
|
|
650
|
+
const apiKeyFromPage = loginResult.apiKey || '';
|
|
622
651
|
|
|
623
652
|
saveLoginState(state, {
|
|
624
653
|
baseUrl,
|
|
625
|
-
name: stringOption(args, 'name', result.data?.user?.username || ''),
|
|
654
|
+
name: stringOption(args, 'name', result.data?.user?.username || result.data?.username || ''),
|
|
626
655
|
sourceFrom,
|
|
627
656
|
result,
|
|
657
|
+
apiKey: apiKeyFromPage,
|
|
658
|
+
authType: loginResult.authType,
|
|
628
659
|
});
|
|
629
660
|
|
|
630
661
|
outputResult(args, {
|
|
631
662
|
command: 'login',
|
|
632
663
|
mode: loginMode,
|
|
633
|
-
authType:
|
|
664
|
+
authType: loginResult.authType,
|
|
634
665
|
baseUrl,
|
|
635
666
|
username: state.user.username,
|
|
636
|
-
tokenSaved:
|
|
667
|
+
tokenSaved: loginResult.authType === 'token',
|
|
668
|
+
apiKeySaved: loginResult.authType === 'api-key',
|
|
637
669
|
}, [
|
|
638
670
|
`login success: ${state.user.username}`,
|
|
639
671
|
`mode: ${loginMode}`,
|
|
672
|
+
`authType: ${loginResult.authType}`,
|
|
640
673
|
`baseUrl: ${baseUrl}`,
|
|
641
674
|
`config: ${CONFIG_FILE}`,
|
|
642
675
|
]);
|
|
@@ -651,7 +684,7 @@ function resolveLoginMode(args) {
|
|
|
651
684
|
}
|
|
652
685
|
const hasName = stringOption(args, 'name');
|
|
653
686
|
const hasPassword = stringOption(args, 'password');
|
|
654
|
-
return hasName || hasPassword ? 'password' : '
|
|
687
|
+
return hasName || hasPassword ? 'password' : 'page';
|
|
655
688
|
}
|
|
656
689
|
|
|
657
690
|
async function loginWithApiKey(baseUrl, apiKey) {
|
|
@@ -702,6 +735,53 @@ async function loginWithBrowser(baseUrl, sourceFrom, args) {
|
|
|
702
735
|
}
|
|
703
736
|
}
|
|
704
737
|
|
|
738
|
+
async function loginWithLoginPage(baseUrl, sourceFrom, args) {
|
|
739
|
+
const timeoutMs = secondsToMs(numberOption(args, 'timeoutSec', DEFAULT_LOGIN_TIMEOUT_MS / 1000));
|
|
740
|
+
const loginState = randomUUID();
|
|
741
|
+
const server = await startBrowserLoginServer({
|
|
742
|
+
loginState,
|
|
743
|
+
onApiKey: async apiKey => ({
|
|
744
|
+
result: await loginWithApiKey(baseUrl, apiKey),
|
|
745
|
+
apiKey,
|
|
746
|
+
}),
|
|
747
|
+
renderPage: ({ redirectUri }) => renderLoginPage({
|
|
748
|
+
authorizeUrl: buildBrowserAuthorizeUrl(baseUrl, redirectUri, loginState, sourceFrom),
|
|
749
|
+
}),
|
|
750
|
+
});
|
|
751
|
+
writeNotice(args, `login page url: ${server.pageUrl}`);
|
|
752
|
+
if (process.env.XQ_CLI_NO_BROWSER !== '1') {
|
|
753
|
+
if (openBrowser(server.pageUrl)) {
|
|
754
|
+
writeNotice(args, 'login page: waiting for API key or browser authorization');
|
|
755
|
+
} else {
|
|
756
|
+
writeNotice(args, 'login page: automatic open failed, paste the URL above into a browser on this machine');
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
try {
|
|
761
|
+
const selected = await withTimeout(
|
|
762
|
+
server.result,
|
|
763
|
+
timeoutMs,
|
|
764
|
+
`Login timed out after ${Math.round(timeoutMs / 1000)} seconds.`,
|
|
765
|
+
);
|
|
766
|
+
if (selected.mode === 'api-key') {
|
|
767
|
+
return {
|
|
768
|
+
result: selected.result,
|
|
769
|
+
apiKey: selected.apiKey,
|
|
770
|
+
authType: 'api-key',
|
|
771
|
+
};
|
|
772
|
+
}
|
|
773
|
+
return {
|
|
774
|
+
result: await postJson(createClient(baseUrl), '/user/cli/token', {
|
|
775
|
+
code: selected.code,
|
|
776
|
+
state: selected.state,
|
|
777
|
+
}),
|
|
778
|
+
authType: 'token',
|
|
779
|
+
};
|
|
780
|
+
} finally {
|
|
781
|
+
await server.close();
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
|
|
705
785
|
function writeNotice(args, message) {
|
|
706
786
|
if (booleanOption(args, 'json')) {
|
|
707
787
|
console.error(message);
|
|
@@ -2005,7 +2085,13 @@ async function fetchAuthoritativeTaskState(client, cid, options = {}) {
|
|
|
2005
2085
|
|
|
2006
2086
|
function buildOutlineParams(snapshot, args) {
|
|
2007
2087
|
const pageScopeCode = enumOption(args, ['pageScope', 'pageScopeCode'], PAGE_SCOPE_OPTIONS, snapshot.pageScopeCode ?? DEFAULT_PAGE_SCOPE_CODE);
|
|
2008
|
-
const
|
|
2088
|
+
const writingQuality = enumOption(
|
|
2089
|
+
args,
|
|
2090
|
+
['writingQuality', 'writingMode', 'base'],
|
|
2091
|
+
WRITING_QUALITY_OPTIONS,
|
|
2092
|
+
snapshot.writingQuality ?? (String(snapshot.base ?? DEFAULT_BASE) === '1' ? 1 : 0),
|
|
2093
|
+
);
|
|
2094
|
+
const base = pageScopeCode <= 0 ? '0' : writingQuality === 1 ? '1' : '0';
|
|
2009
2095
|
const uuid = snapshot.uuid;
|
|
2010
2096
|
const title = stringOption(args, 'title', snapshot.projectName || snapshot.title);
|
|
2011
2097
|
const plan = stringOption(args, 'plan', snapshot.plan || '');
|
|
@@ -2034,7 +2120,9 @@ function buildOutlineParams(snapshot, args) {
|
|
|
2034
2120
|
tableStyle: enumOption(args, 'tableStyle', TABLE_STYLE_OPTIONS, snapshot.tableStyle),
|
|
2035
2121
|
annexIds: snapshot.annexIds || [],
|
|
2036
2122
|
knowledgeProductIds: snapshot.knowledgeProductIds || [],
|
|
2037
|
-
base
|
|
2123
|
+
base,
|
|
2124
|
+
writingQuality,
|
|
2125
|
+
deepThinkingFlowVersion: writingQuality === 2 ? 1 : null,
|
|
2038
2126
|
bidFileIds: [uuid],
|
|
2039
2127
|
directoryNodes: [],
|
|
2040
2128
|
generateType: 1,
|
|
@@ -2156,13 +2244,17 @@ async function verifyParserWakeUp(client, state, cid, uuid, params, planningMode
|
|
|
2156
2244
|
const parseAdvanced = [1, 3, 4].includes(parseSuccess);
|
|
2157
2245
|
const selectionRequired = expectedMultiBidId && expectedMultiBidId !== 'notMultiBid';
|
|
2158
2246
|
const selectionMatches = !selectionRequired || selectedMultiBidId === expectedMultiBidId;
|
|
2247
|
+
const selectionMetadataMissing = selectionRequired && !selectedMultiBidId;
|
|
2159
2248
|
// Planning mode persists the full configuration again when
|
|
2160
2249
|
// `plan confirm-outline` is called. Some backend deployments complete
|
|
2161
2250
|
// intelligent analysis (success=3) without mirroring planMode or the
|
|
2162
2251
|
// selected package onto getTaskDetail. Treat the parse result as the
|
|
2163
2252
|
// authority here so WorkBuddy can trigger the explicit outline
|
|
2164
2253
|
// confirmation instead of failing before that call.
|
|
2165
|
-
|
|
2254
|
+
// The same response shape occurs in quick mode: an advanced parse
|
|
2255
|
+
// with an omitted package field is still ahead of the success=2
|
|
2256
|
+
// selection gate. Keep rejecting an explicitly different package.
|
|
2257
|
+
if (parseAdvanced && (planningMode || selectionMatches || selectionMetadataMissing)) {
|
|
2166
2258
|
return latest;
|
|
2167
2259
|
}
|
|
2168
2260
|
|
|
@@ -3285,6 +3377,7 @@ function buildChoicesPayload(scope) {
|
|
|
3285
3377
|
payload.outline = {
|
|
3286
3378
|
pageScope: PAGE_SCOPE_OPTIONS,
|
|
3287
3379
|
base: BASE_OPTIONS,
|
|
3380
|
+
writingQuality: WRITING_QUALITY_OPTIONS,
|
|
3288
3381
|
themeStyle: THEME_STYLE_OPTIONS,
|
|
3289
3382
|
tableQuantity: TABLE_QUANTITY_OPTIONS,
|
|
3290
3383
|
tableColor: TABLE_COLOR_OPTIONS,
|
|
@@ -3329,6 +3422,7 @@ function renderChoicesLines(payload) {
|
|
|
3329
3422
|
lines.push('outline:');
|
|
3330
3423
|
lines.push(` page-scope: ${formatChoiceOptions(PAGE_SCOPE_OPTIONS)}`);
|
|
3331
3424
|
lines.push(` base: ${formatChoiceOptions(BASE_OPTIONS)}`);
|
|
3425
|
+
lines.push(` writing-quality: ${formatChoiceOptions(WRITING_QUALITY_OPTIONS)}`);
|
|
3332
3426
|
lines.push(` theme-style: ${formatChoiceOptions(THEME_STYLE_OPTIONS)}`);
|
|
3333
3427
|
lines.push(` table-quantity: ${formatChoiceOptions(TABLE_QUANTITY_OPTIONS)}`);
|
|
3334
3428
|
lines.push(` table-color: ${formatChoiceOptions(TABLE_COLOR_OPTIONS)}`);
|
|
@@ -3443,18 +3537,20 @@ async function collectOutlineInteractiveArgs(args, snapshot, context = null, opt
|
|
|
3443
3537
|
nextArgs.pageScope = pageScopeCode;
|
|
3444
3538
|
|
|
3445
3539
|
if (pageScopeCode <= 0) {
|
|
3446
|
-
promptContext.promptStream.write('\u5DF2\u9009\u62E9\u77ED\u7BC7\u6A21\u5F0F\uFF0C\u5199\u4F5C\
|
|
3540
|
+
promptContext.promptStream.write('\u5DF2\u9009\u62E9\u77ED\u7BC7\u6A21\u5F0F\uFF0C\u5199\u4F5C\u8D28\u91CF\u5C06\u56FA\u5B9A\u4E3A\u201C\u6807\u51C6\u5199\u4F5C\u201D\u3002\n');
|
|
3541
|
+
nextArgs.writingQuality = 0;
|
|
3447
3542
|
nextArgs.base = '0';
|
|
3448
3543
|
} else {
|
|
3449
|
-
nextArgs.
|
|
3450
|
-
title: '\u5199\u4F5C\
|
|
3451
|
-
question: '\u8BF7\u9009\u62E9\u5199\u4F5C\
|
|
3452
|
-
options:
|
|
3544
|
+
nextArgs.writingQuality = await promptChoice(promptContext, {
|
|
3545
|
+
title: '\u5199\u4F5C\u8D28\u91CF',
|
|
3546
|
+
question: '\u8BF7\u9009\u62E9\u5199\u4F5C\u8D28\u91CF',
|
|
3547
|
+
options: WRITING_QUALITY_OPTIONS.map(option => ({
|
|
3453
3548
|
...option,
|
|
3454
3549
|
promptLabel: BASE_PROMPT_LABELS[option.value] || option.label,
|
|
3455
3550
|
})),
|
|
3456
|
-
defaultValue: enumOption(args, 'base',
|
|
3551
|
+
defaultValue: enumOption(args, ['writingQuality', 'writingMode', 'base'], WRITING_QUALITY_OPTIONS, defaults.writingQuality),
|
|
3457
3552
|
});
|
|
3553
|
+
nextArgs.base = nextArgs.writingQuality === 1 ? '1' : '0';
|
|
3458
3554
|
}
|
|
3459
3555
|
|
|
3460
3556
|
nextArgs.themeStyle = await promptChoice(promptContext, {
|
|
@@ -3677,9 +3773,11 @@ async function collectExportInteractiveArgs(args, snapshot, context = null, opti
|
|
|
3677
3773
|
}
|
|
3678
3774
|
|
|
3679
3775
|
function buildInteractiveSnapshotDefaults(source = {}) {
|
|
3776
|
+
const writingQuality = source.writingQuality ?? (String(source.base ?? DEFAULT_BASE) === '1' ? 1 : 0);
|
|
3680
3777
|
return {
|
|
3681
3778
|
pageScopeCode: source.pageScopeCode ?? DEFAULT_PAGE_SCOPE_CODE,
|
|
3682
3779
|
base: source.base ?? DEFAULT_BASE,
|
|
3780
|
+
writingQuality,
|
|
3683
3781
|
themeStyle: source.themeStyle ?? DEFAULT_THEME_STYLE,
|
|
3684
3782
|
tableQuantity: source.tableQuantity ?? DEFAULT_TABLE_QUANTITY,
|
|
3685
3783
|
tableColor: source.tableColor ?? DEFAULT_TABLE_COLOR,
|
|
@@ -4116,7 +4214,7 @@ function buildBrowserAuthorizeUrl(baseUrl, redirectUri, state, sourceFrom) {
|
|
|
4116
4214
|
return `${baseUrl}/user/cli/authorize?${query.toString()}`;
|
|
4117
4215
|
}
|
|
4118
4216
|
|
|
4119
|
-
async function startBrowserLoginServer() {
|
|
4217
|
+
async function startBrowserLoginServer({ loginState = '', renderPage = null, onApiKey = null } = {}) {
|
|
4120
4218
|
let settled = false;
|
|
4121
4219
|
let resolveResult;
|
|
4122
4220
|
let rejectResult;
|
|
@@ -4124,7 +4222,7 @@ async function startBrowserLoginServer() {
|
|
|
4124
4222
|
resolveResult = resolve;
|
|
4125
4223
|
rejectResult = reject;
|
|
4126
4224
|
});
|
|
4127
|
-
const server = http.createServer((request, response) => {
|
|
4225
|
+
const server = http.createServer(async (request, response) => {
|
|
4128
4226
|
const origin = server.address();
|
|
4129
4227
|
const requestUrl = new URL(request.url || '/', `http://127.0.0.1:${origin?.port || 0}`);
|
|
4130
4228
|
const pathname = requestUrl.pathname;
|
|
@@ -4134,6 +4232,33 @@ async function startBrowserLoginServer() {
|
|
|
4134
4232
|
response.end();
|
|
4135
4233
|
return;
|
|
4136
4234
|
}
|
|
4235
|
+
if (pathname === '/' && typeof renderPage === 'function') {
|
|
4236
|
+
response.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
4237
|
+
response.end(renderPage({
|
|
4238
|
+
redirectUri: `http://127.0.0.1:${origin?.port || 0}${BROWSER_LOGIN_CALLBACK_PATH}`,
|
|
4239
|
+
}));
|
|
4240
|
+
return;
|
|
4241
|
+
}
|
|
4242
|
+
if (pathname === '/api-key' && request.method === 'POST' && typeof onApiKey === 'function') {
|
|
4243
|
+
try {
|
|
4244
|
+
const body = await readJsonRequestBody(request, 16 * 1024);
|
|
4245
|
+
const apiKey = normalizeApiKey(body?.apiKey);
|
|
4246
|
+
if (!apiKey) {
|
|
4247
|
+
throw new Error('请输入 API Key。');
|
|
4248
|
+
}
|
|
4249
|
+
const selected = await onApiKey(apiKey);
|
|
4250
|
+
response.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
4251
|
+
response.end(renderBrowserLoginResultPage('登录成功', 'API Key 已验证,CLI 正在保存登录状态;现在可以关闭此页面。'));
|
|
4252
|
+
if (!settled) {
|
|
4253
|
+
settled = true;
|
|
4254
|
+
resolveResult({ mode: 'api-key', ...selected });
|
|
4255
|
+
}
|
|
4256
|
+
} catch (error) {
|
|
4257
|
+
response.writeHead(400, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
4258
|
+
response.end(renderBrowserLoginResultPage('登录未完成', error.message || 'API Key 验证失败,请检查后重试。'));
|
|
4259
|
+
}
|
|
4260
|
+
return;
|
|
4261
|
+
}
|
|
4137
4262
|
if (pathname !== BROWSER_LOGIN_CALLBACK_PATH) {
|
|
4138
4263
|
response.writeHead(404, { 'Content-Type': 'text/plain; charset=utf-8' });
|
|
4139
4264
|
response.end('Not found');
|
|
@@ -4152,11 +4277,20 @@ async function startBrowserLoginServer() {
|
|
|
4152
4277
|
return;
|
|
4153
4278
|
}
|
|
4154
4279
|
|
|
4280
|
+
if (loginState && state !== loginState) {
|
|
4281
|
+
response.writeHead(400, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
4282
|
+
response.end(renderBrowserLoginResultPage('登录未完成', '授权状态校验失败,请返回 CLI 重新执行登录。'));
|
|
4283
|
+
if (!settled) {
|
|
4284
|
+
settled = true;
|
|
4285
|
+
rejectResult(new Error('Browser login state validation failed.'));
|
|
4286
|
+
}
|
|
4287
|
+
return;
|
|
4288
|
+
}
|
|
4155
4289
|
response.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
4156
4290
|
response.end(renderBrowserLoginResultPage('登录成功', '授权已完成,现在可以回到 CLI 继续使用了。'));
|
|
4157
4291
|
if (!settled) {
|
|
4158
4292
|
settled = true;
|
|
4159
|
-
resolveResult({ code, state });
|
|
4293
|
+
resolveResult({ mode: 'browser', code, state });
|
|
4160
4294
|
}
|
|
4161
4295
|
});
|
|
4162
4296
|
server.on('error', error => {
|
|
@@ -4178,11 +4312,111 @@ async function startBrowserLoginServer() {
|
|
|
4178
4312
|
const redirectUri = `http://127.0.0.1:${address.port}${BROWSER_LOGIN_CALLBACK_PATH}`;
|
|
4179
4313
|
return {
|
|
4180
4314
|
redirectUri,
|
|
4315
|
+
pageUrl: `http://127.0.0.1:${address.port}/`,
|
|
4316
|
+
loginState,
|
|
4181
4317
|
result,
|
|
4182
4318
|
close: () => closeServer(server),
|
|
4183
4319
|
};
|
|
4184
4320
|
}
|
|
4185
4321
|
|
|
4322
|
+
async function readJsonRequestBody(request, maxBytes) {
|
|
4323
|
+
const chunks = [];
|
|
4324
|
+
let total = 0;
|
|
4325
|
+
for await (const chunk of request) {
|
|
4326
|
+
total += chunk.length;
|
|
4327
|
+
if (total > maxBytes) {
|
|
4328
|
+
throw new Error('请求内容过大。');
|
|
4329
|
+
}
|
|
4330
|
+
chunks.push(chunk);
|
|
4331
|
+
}
|
|
4332
|
+
const text = Buffer.concat(chunks).toString('utf8');
|
|
4333
|
+
try {
|
|
4334
|
+
if (String(request.headers['content-type'] || '').includes('application/x-www-form-urlencoded')) {
|
|
4335
|
+
return Object.fromEntries(new URLSearchParams(text));
|
|
4336
|
+
}
|
|
4337
|
+
return JSON.parse(text || '{}');
|
|
4338
|
+
} catch {
|
|
4339
|
+
throw new Error('请求格式无效。');
|
|
4340
|
+
}
|
|
4341
|
+
}
|
|
4342
|
+
|
|
4343
|
+
function renderLoginPage({ authorizeUrl }) {
|
|
4344
|
+
return `<!doctype html>
|
|
4345
|
+
<html lang="zh-CN">
|
|
4346
|
+
<head>
|
|
4347
|
+
<meta charset="UTF-8" />
|
|
4348
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
4349
|
+
<title>喜鹊标书登录</title>
|
|
4350
|
+
<style>
|
|
4351
|
+
:root{font-family:Inter,Segoe UI,Microsoft YaHei,sans-serif;color:#182238;background:#eef3fb;}
|
|
4352
|
+
*{box-sizing:border-box;} body{min-height:100vh;margin:0;padding:32px;display:grid;place-items:center;background:#eef3fb;}
|
|
4353
|
+
.page-shell{width:min(100%,1080px);display:grid;grid-template-columns:minmax(0,1fr) 448px;gap:24px;align-items:stretch;}
|
|
4354
|
+
.brand-panel{position:relative;overflow:hidden;display:flex;min-height:584px;flex-direction:column;justify-content:space-between;padding:42px 44px;border:1px solid #dce5f4;border-radius:24px;background:linear-gradient(145deg,#f8fbff 0%,#eef4ff 58%,#e9f0fc 100%);box-shadow:0 20px 55px rgba(35,58,105,.10);}
|
|
4355
|
+
.brand-panel:after{content:"";position:absolute;width:310px;height:310px;right:-128px;bottom:-142px;border:1px solid rgba(83,111,179,.20);border-radius:50%;box-shadow:0 0 0 26px rgba(83,111,179,.05),0 0 0 52px rgba(83,111,179,.04);}
|
|
4356
|
+
.brand-top,.brand-footer{position:relative;z-index:1;display:flex;align-items:center;justify-content:space-between;gap:12px;}
|
|
4357
|
+
.brand-kicker{display:flex;align-items:center;gap:10px;color:#536da9;font-size:12px;font-weight:800;letter-spacing:.18em;}
|
|
4358
|
+
.brand-symbol{display:grid;width:30px;height:30px;place-items:center;border-radius:10px;color:#fff;background:#536da9;box-shadow:0 7px 16px rgba(83,109,169,.25);font-size:18px;letter-spacing:0;}
|
|
4359
|
+
.brand-status{display:flex;align-items:center;gap:7px;color:#6b7b99;font-size:12px;}
|
|
4360
|
+
.brand-status i{width:7px;height:7px;border-radius:50%;background:#35a779;box-shadow:0 0 0 4px rgba(53,167,121,.13);}
|
|
4361
|
+
.brand-copy{position:relative;z-index:1;margin:auto 0;max-width:470px;}
|
|
4362
|
+
.brand-copy h1{margin:0;color:#14213b;font-size:clamp(38px,5vw,62px);font-weight:800;letter-spacing:-.055em;line-height:1.08;}
|
|
4363
|
+
.brand-copy h1 em{font-style:normal;color:#536da9;}
|
|
4364
|
+
.brand-copy p{max-width:400px;margin:24px 0 0;color:#637593;font-size:16px;line-height:1.85;}
|
|
4365
|
+
.brand-features{display:grid;grid-template-columns:repeat(3,1fr);gap:10px;margin:34px 0 0;}
|
|
4366
|
+
.brand-feature{padding:14px 13px;border:1px solid rgba(188,204,231,.72);border-radius:12px;background:rgba(255,255,255,.58);}
|
|
4367
|
+
.brand-feature strong,.brand-feature span{display:block;}.brand-feature strong{color:#324a7e;font-size:13px;}.brand-feature span{margin-top:5px;color:#7a89a3;font-size:11px;line-height:1.45;}
|
|
4368
|
+
.brand-footer{justify-content:flex-start;color:#8290a8;font-size:11px;}
|
|
4369
|
+
.card{width:100%;min-height:584px;padding:42px 40px;border:1px solid #e0e7f2;border-radius:24px;background:#fff;box-shadow:0 20px 55px rgba(35,58,105,.13);}
|
|
4370
|
+
.card-heading{display:flex;align-items:center;gap:11px;margin-bottom:24px;}.card-heading-mark{display:grid;width:38px;height:38px;place-items:center;border:1px solid #dce4f4;border-radius:12px;color:#536da9;background:#f2f6ff;font-size:18px;}.card-heading small{display:block;color:#7a89a3;font-size:11px;font-weight:700;letter-spacing:.14em;text-transform:uppercase;}.card-heading h2{margin:3px 0 0;color:#182238;font-size:25px;letter-spacing:-.03em;}
|
|
4371
|
+
.muted{margin:0 0 28px;color:#6e7e99;line-height:1.75;font-size:14px;}
|
|
4372
|
+
.field-label{display:flex;align-items:center;justify-content:space-between;margin:0 0 9px;color:#2c3a55;font-size:13px;font-weight:700;}.field-label span{color:#a4afc0;font-size:11px;font-weight:500;}
|
|
4373
|
+
.input-wrap{position:relative;}.field-icon{position:absolute;top:50%;left:15px;width:18px;height:18px;transform:translateY(-50%);}.field-icon:before{content:"";position:absolute;top:1px;left:5px;width:7px;height:7px;border:1.5px solid #7183a5;border-radius:50%;}.field-icon:after{content:"";position:absolute;top:8px;left:8px;width:1.5px;height:9px;background:#7183a5;box-shadow:3px 5px 0 -0.25px #7183a5;}
|
|
4374
|
+
input{display:block;width:100%;height:50px;padding:0 14px 0 47px;border:1px solid #d4deec;border-radius:12px;outline:0;color:#1c2b46;background:#fbfcfe;font:inherit;font-size:14px;transition:border-color .18s,box-shadow .18s,background .18s;} input::placeholder{color:#aeb9c9;} input:focus{border-color:#6d86bc;background:#fff;box-shadow:0 0 0 4px rgba(83,109,169,.12);}
|
|
4375
|
+
button,a{display:flex;width:100%;min-height:50px;box-sizing:border-box;align-items:center;justify-content:center;gap:8px;padding:12px 14px;border-radius:12px;font:inherit;font-size:14px;font-weight:700;text-align:center;text-decoration:none;cursor:pointer;transition:transform .18s,box-shadow .18s,border-color .18s,background .18s;}
|
|
4376
|
+
button{margin-top:13px;border:0;background:#536da9;color:#fff;box-shadow:0 10px 22px rgba(83,109,169,.23);} button:hover{background:#47619b;box-shadow:0 13px 26px rgba(83,109,169,.28);transform:translateY(-1px);} button:disabled{cursor:wait;opacity:.72;transform:none;}
|
|
4377
|
+
.button-arrow{font-size:18px;line-height:1;}.divider{display:flex;align-items:center;gap:12px;color:#a1aec2;margin:23px 0 13px;font-size:12px;}.divider:before,.divider:after{content:"";height:1px;background:#e8edf4;flex:1;}
|
|
4378
|
+
a{border:1px solid #d5dfed;color:#304364;background:#fff;} a:hover{border-color:#91a6cc;background:#f7f9fd;transform:translateY(-1px);}
|
|
4379
|
+
.hint{margin:16px 0 0;color:#8390a6;font-size:12px;line-height:1.7;}.hint strong{color:#536da9;font-weight:700;}.secure-note{display:flex;align-items:center;gap:8px;margin-top:30px;padding-top:17px;border-top:1px solid #edf0f5;color:#9aa6b7;font-size:11px;}.secure-note span{width:7px;height:7px;border-radius:50%;background:#35a779;box-shadow:0 0 0 4px rgba(53,167,121,.10);}
|
|
4380
|
+
@media (max-width:820px){body{padding:18px;}.page-shell{grid-template-columns:1fr;max-width:520px;}.brand-panel{display:none;}.card{min-height:0;padding:32px 26px;border-radius:20px;}}
|
|
4381
|
+
@media (max-width:420px){body{padding:12px;}.card{padding:27px 20px;}.card-heading h2{font-size:22px;}}
|
|
4382
|
+
</style>
|
|
4383
|
+
</head>
|
|
4384
|
+
<body>
|
|
4385
|
+
<div class="page-shell">
|
|
4386
|
+
<section class="brand-panel" aria-label="喜鹊标书 CLI">
|
|
4387
|
+
<div class="brand-top">
|
|
4388
|
+
<div class="brand-kicker"><span class="brand-symbol">↗</span> XIQUE CLI</div>
|
|
4389
|
+
<div class="brand-status"><i></i> 本机安全接入</div>
|
|
4390
|
+
</div>
|
|
4391
|
+
<div class="brand-copy">
|
|
4392
|
+
<h1>把喜鹊标书<br /><em>带到终端</em></h1>
|
|
4393
|
+
<p>一次登录,连接初始化、大纲、正文与 Word 导出。把重复操作交给 CLI,把精力留给标书本身。</p>
|
|
4394
|
+
<div class="brand-features">
|
|
4395
|
+
<div class="brand-feature"><strong>一次登录</strong><span>后续命令自动复用</span></div>
|
|
4396
|
+
<div class="brand-feature"><strong>分阶段工作流</strong><span>从大纲到正文可控推进</span></div>
|
|
4397
|
+
<div class="brand-feature"><strong>随时可轮换</strong><span>账号中心独立管理 Key</span></div>
|
|
4398
|
+
</div>
|
|
4399
|
+
</div>
|
|
4400
|
+
<div class="brand-footer">喜鹊标书 AI · 命令行工作台</div>
|
|
4401
|
+
</section>
|
|
4402
|
+
<main class="card">
|
|
4403
|
+
<div class="card-heading"><span class="card-heading-mark">⌁</span><div><small>LOCAL ACCESS</small><h2>登录喜鹊标书</h2></div></div>
|
|
4404
|
+
<p class="muted">使用 API Key 登录后,xq-cli 会在本机保存凭证,后续命令无需重复输入。</p>
|
|
4405
|
+
<form method="post" action="/api-key" onsubmit="this.querySelector('button').disabled=true">
|
|
4406
|
+
<label class="field-label" for="api-key">API Key <span>xq_sk_ 开头</span></label>
|
|
4407
|
+
<div class="input-wrap"><span class="field-icon" aria-hidden="true"></span><input id="api-key" name="apiKey" type="password" autocomplete="off" placeholder="xq_sk_..." required /></div>
|
|
4408
|
+
<button type="submit"><span>使用 API Key 登录</span><span class="button-arrow">→</span></button>
|
|
4409
|
+
</form>
|
|
4410
|
+
<div class="divider">或</div>
|
|
4411
|
+
<a href="${escapeHtml(authorizeUrl)}"><span>使用浏览器授权登录</span><span class="button-arrow">↗</span></a>
|
|
4412
|
+
<p class="hint">API Key 可在喜鹊的 API Key 管理页创建。验证成功后即可关闭页面。</p>
|
|
4413
|
+
<div class="secure-note"><span></span>登录状态仅用于当前 CLI 工作流</div>
|
|
4414
|
+
</main>
|
|
4415
|
+
</div>
|
|
4416
|
+
</body>
|
|
4417
|
+
</html>`;
|
|
4418
|
+
}
|
|
4419
|
+
|
|
4186
4420
|
function renderBrowserLoginResultPage(title, message) {
|
|
4187
4421
|
return `<!doctype html>
|
|
4188
4422
|
<html lang="zh-CN">
|
|
@@ -4765,6 +4999,8 @@ function pickOutlineConfig(params) {
|
|
|
4765
4999
|
return compactObject({
|
|
4766
5000
|
pageScopeCode: params.pageScopeCode,
|
|
4767
5001
|
base: params.base,
|
|
5002
|
+
writingQuality: params.writingQuality,
|
|
5003
|
+
deepThinkingFlowVersion: params.deepThinkingFlowVersion,
|
|
4768
5004
|
themeStyle: params.themeStyle,
|
|
4769
5005
|
tableQuantity: params.tableQuantity,
|
|
4770
5006
|
tableColor: params.tableColor,
|
|
@@ -4787,6 +5023,9 @@ function buildOutlineConfigSummary(params) {
|
|
|
4787
5023
|
return [
|
|
4788
5024
|
`pageScope=${describeEnumValue(PAGE_SCOPE_OPTIONS, params.pageScopeCode)}`,
|
|
4789
5025
|
`base=${describeEnumValue(BASE_OPTIONS, params.base)}`,
|
|
5026
|
+
params.writingQuality !== undefined
|
|
5027
|
+
? `writingQuality=${describeEnumValue(WRITING_QUALITY_OPTIONS, params.writingQuality)}`
|
|
5028
|
+
: null,
|
|
4790
5029
|
params.themeStyle !== undefined ? `themeStyle=${describeEnumValue(THEME_STYLE_OPTIONS, params.themeStyle)}` : null,
|
|
4791
5030
|
params.tableQuantity !== undefined ? `tableQuantity=${describeEnumValue(TABLE_QUANTITY_OPTIONS, params.tableQuantity)}` : null,
|
|
4792
5031
|
params.tableColor !== undefined ? `tableColor=${describeEnumValue(TABLE_COLOR_OPTIONS, params.tableColor)}` : null,
|
|
@@ -4982,6 +5221,8 @@ function pickTaskSnapshot(source) {
|
|
|
4982
5221
|
rating: source.rating,
|
|
4983
5222
|
plan: source.plan,
|
|
4984
5223
|
base: source.base,
|
|
5224
|
+
writingQuality: source.writingQuality,
|
|
5225
|
+
deepThinkingFlowVersion: source.deepThinkingFlowVersion,
|
|
4985
5226
|
pageScopeCode: source.pageScopeCode,
|
|
4986
5227
|
task_status: source.task_status,
|
|
4987
5228
|
plan_mode_phase: source.plan_mode_phase,
|