weaver-work-cli 0.1.8 → 0.1.20
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 +11 -11
- package/dist/cmd/action.js +76 -0
- package/dist/cmd/index.js +2 -0
- package/dist/cmd/refs/index.js +103 -0
- package/dist/cmd/register.js +31 -0
- package/dist/cmd/root.js +1 -0
- package/dist/cmd/setup/index.js +25 -5
- package/dist/cmd/skills/index.js +37 -5
- package/dist/core/connector.js +54 -0
- package/dist/core/context.js +2 -1
- package/dist/core/input.js +48 -0
- package/dist/core/output.js +298 -3
- package/dist/core/refs.js +432 -0
- package/dist/core/state.js +26 -0
- package/dist/internal/e10/auth/commands.js +2 -2
- package/dist/internal/e10/auth/session.js +14 -0
- package/dist/internal/e10/auth/xiaoe.js +116 -51
- package/dist/internal/e10/request-runtime.js +5 -0
- package/dist/internal/skills/install.js +148 -28
- package/dist/internal/skills/reader.js +12 -9
- package/dist/shortcuts/blog/continuation.js +74 -0
- package/dist/shortcuts/blog/errors.js +60 -0
- package/dist/shortcuts/blog/host.js +175 -0
- package/dist/shortcuts/blog/index.js +324 -0
- package/dist/shortcuts/blog/manifest.js +415 -0
- package/dist/shortcuts/blog/operations/comment.js +125 -0
- package/dist/shortcuts/blog/operations/comments.js +31 -0
- package/dist/shortcuts/blog/operations/edit.js +131 -0
- package/dist/shortcuts/blog/operations/export.js +46 -0
- package/dist/shortcuts/blog/operations/like.js +80 -0
- package/dist/shortcuts/blog/operations/publish.js +157 -0
- package/dist/shortcuts/blog/operations/query-user.js +58 -0
- package/dist/shortcuts/blog/operations/query.js +96 -0
- package/dist/shortcuts/blog/operations/registry.js +54 -0
- package/dist/shortcuts/blog/operations/remind.js +176 -0
- package/dist/shortcuts/blog/operations/shared.js +330 -0
- package/dist/shortcuts/blog/operations/types.js +16 -0
- package/dist/shortcuts/blog/operations.js +9 -0
- package/dist/shortcuts/caizhilian/continuation.js +70 -0
- package/dist/shortcuts/caizhilian/errors.js +53 -0
- package/dist/shortcuts/caizhilian/host.js +190 -0
- package/dist/shortcuts/caizhilian/index.js +186 -0
- package/dist/shortcuts/caizhilian/manifest.js +42 -0
- package/dist/shortcuts/caizhilian/operations/api.js +801 -0
- package/dist/shortcuts/caizhilian/operations/confirm.js +75 -0
- package/dist/shortcuts/caizhilian/operations/files.js +306 -0
- package/dist/shortcuts/caizhilian/operations/form.js +170 -0
- package/dist/shortcuts/caizhilian/operations/handlers/collab.js +611 -0
- package/dist/shortcuts/caizhilian/operations/handlers/document.js +890 -0
- package/dist/shortcuts/caizhilian/operations/handlers/file-collection.js +346 -0
- package/dist/shortcuts/caizhilian/operations/handlers/file-upload.js +192 -0
- package/dist/shortcuts/caizhilian/operations/handlers/fileops.js +570 -0
- package/dist/shortcuts/caizhilian/operations/handlers/folder.js +969 -0
- package/dist/shortcuts/caizhilian/operations/handlers/search.js +318 -0
- package/dist/shortcuts/caizhilian/operations/handlers/setting-attach.js +294 -0
- package/dist/shortcuts/caizhilian/operations/handlers/setting-backup.js +423 -0
- package/dist/shortcuts/caizhilian/operations/handlers/setting-encrypt.js +238 -0
- package/dist/shortcuts/caizhilian/operations/handlers/setting-storage.js +364 -0
- package/dist/shortcuts/caizhilian/operations/handlers/system.js +106 -0
- package/dist/shortcuts/caizhilian/operations/registry.js +151 -0
- package/dist/shortcuts/caizhilian/operations/shared.js +408 -0
- package/dist/shortcuts/caizhilian/operations/specs.js +623 -0
- package/dist/shortcuts/caizhilian/operations/types.js +57 -0
- package/dist/shortcuts/caizhilian/operations.js +21 -0
- package/dist/shortcuts/contract/continuation.js +70 -0
- package/dist/shortcuts/contract/errors.js +62 -0
- package/dist/shortcuts/contract/host.js +205 -0
- package/dist/shortcuts/contract/index.js +318 -0
- package/dist/shortcuts/contract/manifest.js +596 -0
- package/dist/shortcuts/contract/operations/clause-reference.js +78 -0
- package/dist/shortcuts/contract/operations/form-info.js +371 -0
- package/dist/shortcuts/contract/operations/read.js +118 -0
- package/dist/shortcuts/contract/operations/registry.js +43 -0
- package/dist/shortcuts/contract/operations/request.js +300 -0
- package/dist/shortcuts/contract/operations/shared.js +133 -0
- package/dist/shortcuts/contract/operations/subject.js +157 -0
- package/dist/shortcuts/contract/operations/template.js +81 -0
- package/dist/shortcuts/contract/operations/types.js +7 -0
- package/dist/shortcuts/contract/operations/workflow.js +52 -0
- package/dist/shortcuts/contract/operations/write.js +131 -0
- package/dist/shortcuts/contract/operations.js +8 -0
- package/dist/shortcuts/hrm/index.js +83 -2
- package/dist/shortcuts/hrm/operations/employee.js +160 -30
- package/dist/shortcuts/hrm/operations/org.js +17 -3
- package/dist/shortcuts/hrm/operations/position.js +18 -2
- package/dist/shortcuts/index.js +5 -1
- package/dist/shortcuts/invoice/index.js +74 -36
- package/dist/shortcuts/invoice/manifest.js +674 -4
- package/dist/shortcuts/invoice/markdown.js +172 -0
- package/dist/shortcuts/invoice/operations/add.js +3 -3
- package/dist/shortcuts/invoice/operations/delete.js +2 -2
- package/dist/shortcuts/invoice/operations/get.js +10 -2
- package/dist/shortcuts/invoice/operations/import.js +2 -2
- package/dist/shortcuts/invoice/operations/registry.js +8 -1
- package/dist/shortcuts/invoice/operations/reim-auto.js +719 -0
- package/dist/shortcuts/invoice/operations/reim.js +85 -2
- package/dist/shortcuts/invoice/operations/shared.js +75 -8
- package/dist/shortcuts/invoice/operations/update.js +2 -2
- package/dist/shortcuts/invoice/operations/upload-and-validate.js +93 -0
- package/dist/shortcuts/invoice/operations/validate-preview.js +2 -1
- package/dist/shortcuts/invoice/projection.js +328 -0
- package/dist/shortcuts/meeting/host.js +18 -1
- package/dist/shortcuts/meeting/manifest.js +30 -18
- package/dist/shortcuts/meeting/operations/eb/catalog.js +390 -0
- package/dist/shortcuts/meeting/operations/eb/conflict.js +389 -0
- package/dist/shortcuts/meeting/operations/eb/factory.js +389 -0
- package/dist/shortcuts/meeting/operations/eb/index.js +22 -0
- package/dist/shortcuts/meeting/operations/env.js +8 -1
- package/dist/shortcuts/meeting/operations/registry.js +2 -0
- package/dist/shortcuts/meeting/operations/signs.js +216 -2
- package/dist/shortcuts/workflow/endpoints.js +2 -1
- package/dist/shortcuts/workflow/errors.js +8 -2
- package/dist/shortcuts/workflow/host.js +6 -3
- package/dist/shortcuts/workflow/operations/form.js +931 -589
- package/dist/shortcuts/workflow/operations/read.js +128 -205
- package/dist/shortcuts/workflow/operations/shared.js +21 -0
- package/dist/shortcuts/workflow/operations/write.js +750 -52
- package/dist/shortcuts/workflow/operations.js +36 -10
- package/docs/_catalog.md +6 -0
- package/docs/agent-invoice.md +5 -1
- package/docs/agent-io-channel-design.md +468 -0
- package/docs/agent-skill-install.md +9 -4
- package/docs/blog.md +123 -0
- package/docs/caizhilian.md +304 -0
- package/docs/contract.md +91 -0
- package/docs/e10-auth.md +2 -2
- package/docs/hrm.md +19 -9
- package/docs/invoice.md +5 -1
- package/docs/meeting.md +1 -1
- package/docs/operation-manual.md +15 -3
- package/docs/skill-review-2026-09-19.md +2 -2
- package/package.json +2 -2
- package/scripts/package-skill.mjs +32 -20
- package/skill-template/business-info.json +113 -14
- package/skill-template/domains/blog.md +24 -0
- package/skill-template/domains/caizhilian.md +22 -0
- package/skill-template/domains/jinchengda.md +23 -0
- package/skill-template/domains/meeting.md +1 -1
- package/skill-template/domains/workflow.md +1 -1
- package/skill-template/skill-template.md +1 -1
- package/skills/weaver-e10-blog/SKILL.md +111 -0
- package/skills/weaver-e10-blog/references/blog-comment.md +51 -0
- package/skills/weaver-e10-blog/references/blog-comments.md +39 -0
- package/skills/weaver-e10-blog/references/blog-default-permission.md +38 -0
- package/skills/weaver-e10-blog/references/blog-disabled-capabilities.md +11 -0
- package/skills/weaver-e10-blog/references/blog-edit.md +51 -0
- package/skills/weaver-e10-blog/references/blog-export.md +42 -0
- package/skills/weaver-e10-blog/references/blog-like.md +50 -0
- package/skills/weaver-e10-blog/references/blog-publish.md +52 -0
- package/skills/weaver-e10-blog/references/blog-query-user.md +45 -0
- package/skills/weaver-e10-blog/references/blog-query.md +49 -0
- package/skills/weaver-e10-blog/references/blog-remind.md +51 -0
- package/skills/weaver-e10-blog/references/blog-resolve-users.md +38 -0
- package/skills/weaver-e10-blog/references/source-manifest.json +1540 -0
- package/skills/weaver-e10-caizhilian/SKILL.md +216 -0
- package/skills/weaver-e10-caizhilian/references/agent-entry.md +106 -0
- package/skills/weaver-e10-caizhilian/references/collaboration.md +112 -0
- package/skills/weaver-e10-caizhilian/references/document.md +111 -0
- package/skills/weaver-e10-caizhilian/references/file-collection.md +136 -0
- package/skills/weaver-e10-caizhilian/references/file-upload.md +309 -0
- package/skills/weaver-e10-caizhilian/references/files.md +120 -0
- package/skills/weaver-e10-caizhilian/references/folder.md +118 -0
- package/skills/weaver-e10-caizhilian/references/org-browser.md +104 -0
- package/skills/weaver-e10-caizhilian/references/setting-attach.md +410 -0
- package/skills/weaver-e10-caizhilian/references/setting-backup.md +372 -0
- package/skills/weaver-e10-caizhilian/references/setting-encrypt.md +399 -0
- package/skills/weaver-e10-caizhilian/references/setting-storage.md +603 -0
- package/skills/weaver-e10-caizhilian/references/source-manifest.json +5079 -0
- package/skills/weaver-e10-caizhilian/references/withheld.md +93 -0
- package/skills/weaver-e10-caizhilian/references/write-protocol.md +120 -0
- package/skills/weaver-e10-calendar/SKILL.md +4 -3
- package/skills/weaver-e10-ebuilder-form/SKILL.md +4 -9
- package/skills/weaver-e10-ebuilder-form/references/context-routing.md +0 -9
- package/skills/weaver-e10-ebuilder-form/references/custom-api.md +1 -5
- package/skills/weaver-e10-ebuilder-form/references/fields-browser.md +1 -5
- package/skills/weaver-e10-ebuilder-form/references/list-nlist.md +1 -5
- package/skills/weaver-e10-ebuilder-form/references/openapi-read.md +1 -5
- package/skills/weaver-e10-ebuilder-form/references/openapi-write.md +1 -5
- package/skills/weaver-e10-esb/SKILL.md +2 -2
- package/skills/weaver-e10-esb/references/source-manifest.json +9 -9
- package/skills/weaver-e10-hrm/SKILL.md +54 -6
- package/skills/weaver-e10-hrm/references/employee.md +89 -15
- package/skills/weaver-e10-hrm/references/org.md +7 -4
- package/skills/weaver-e10-hrm/references/position.md +14 -7
- package/skills/weaver-e10-hrm/references/source-manifest.json +1 -1
- package/skills/weaver-e10-jinchengda/SKILL.md +166 -0
- package/skills/weaver-e10-jinchengda/references/contract-agent-entry.md +82 -0
- package/skills/weaver-e10-jinchengda/references/contract-clause-recommender.md +69 -0
- package/skills/weaver-e10-jinchengda/references/contract-clause-reference-save.md +78 -0
- package/skills/weaver-e10-jinchengda/references/contract-disabled-capabilities.md +27 -0
- package/skills/weaver-e10-jinchengda/references/contract-request-status.md +71 -0
- package/skills/weaver-e10-jinchengda/references/contract-request-write.md +94 -0
- package/skills/weaver-e10-jinchengda/references/contract-signing-subjects.md +89 -0
- package/skills/weaver-e10-jinchengda/references/contract-subject-create.md +77 -0
- package/skills/weaver-e10-jinchengda/references/contract-template-selector.md +66 -0
- package/skills/weaver-e10-jinchengda/references/contract-workflow-discovery.md +94 -0
- package/skills/weaver-e10-jinchengda/references/source-manifest.json +259 -0
- package/skills/weaver-e10-jiuchuanhui/SKILL.md +5 -11
- package/skills/weaver-e10-jucailin/SKILL.md +4 -3
- package/skills/weaver-e10-mail/SKILL.md +4 -11
- package/skills/weaver-e10-meeting/SKILL.md +66 -32
- package/skills/weaver-e10-meeting/references/meeting-change.md +5 -2
- package/skills/weaver-e10-meeting/references/meeting-create.md +2 -1
- package/skills/weaver-e10-meeting/references/meeting-eb.md +114 -0
- package/skills/weaver-e10-meeting/references/meeting-lifecycle.md +9 -8
- package/skills/weaver-e10-meeting/references/meeting-receipts-signs.md +35 -7
- package/skills/weaver-e10-meeting/references/meeting-update.md +1 -1
- package/skills/weaver-e10-okr/SKILL.md +6 -11
- package/skills/weaver-e10-okr/references/source-manifest.json +3 -3
- package/skills/weaver-e10-plan/SKILL.md +3 -3
- package/skills/weaver-e10-plan/references/plan-collect-and-compose.md +1 -1
- package/skills/weaver-e10-plan/references/plan-overview-and-routing.md +1 -1
- package/skills/weaver-e10-plan/references/source-manifest.json +13 -13
- package/skills/weaver-e10-qiyecheng/SKILL.md +4 -10
- package/skills/weaver-e10-qiyecheng/references/source-manifest.json +9 -9
- package/skills/weaver-e10-shared/SKILL.md +36 -25
- package/skills/weaver-e10-shared/references/e10-auth-and-session.md +10 -31
- package/skills/weaver-e10-shared/references/json-output-contract.md +20 -11
- package/skills/weaver-e10-shijingran/SKILL.md +2 -1
- package/skills/weaver-e10-shijingran/references/source-manifest.json +9 -9
- package/skills/weaver-e10-skill-maker/SKILL.md +4 -10
- package/skills/weaver-e10-skill-maker/references/business-skill-generation.md +5 -3
- package/skills/weaver-e10-skill-maker/references/module-cli-generation.md +12 -27
- package/skills/weaver-e10-skill-maker/references/module-gap-audit-and-repair.md +17 -5
- package/skills/weaver-e10-skill-maker/references/source-update-detection.md +4 -27
- package/skills/weaver-e10-wenshuding/SKILL.md +5 -16
- package/skills/weaver-e10-wenshuding/references/source-manifest.json +7 -7
- package/skills/weaver-e10-workflow/SKILL.md +32 -37
- package/skills/weaver-e10-workflow/references/source-manifest.json +39 -75
- package/skills/weaver-e10-workflow/references/workflow-batch.md +90 -29
- package/skills/weaver-e10-workflow/references/workflow-create.md +79 -109
- package/skills/weaver-e10-workflow/references/workflow-memory.md +19 -9
- package/skills/weaver-e10-workflow/references/workflow-operate.md +2 -2
- package/skills/weaver-e10-workflow/references/workflow-query.md +38 -20
- package/skills/weaver-e10-workflow/references/workflow-share.md +18 -2
- package/skills/weaver-e10-workflow/references/workflow-view.md +3 -4
- package/skills/weaver-e10-yepiaotong/SKILL.md +75 -39
- package/skills/weaver-e10-yepiaotong/references/invoice-detail.md +22 -1
- package/skills/weaver-e10-yepiaotong/references/invoice-enterprise-list.md +3 -1
- package/skills/weaver-e10-yepiaotong/references/invoice-output-view.md +135 -0
- package/skills/weaver-e10-yepiaotong/references/invoice-personal-list.md +15 -3
- package/skills/weaver-e10-yepiaotong/references/invoice-reim.md +1 -1
- package/skills/weaver-e10-yepiaotong/references/invoice-summarize.py +217 -0
- package/skills/weaver-e10-yepiaotong/references/invoice-upload-and-validate.md +88 -0
- package/skills/weaver-e10-yepiaotong/references/invoice-validation-preview.md +7 -2
- package/skills/weaver-e10-yepiaotong/references/reim-api-reference.md +89 -9
- package/skills/weaver-e10-yepiaotong/references/reim-examples.md +1 -0
- package/skills/weaver-e10-yepiaotong/references/reim-expense-subject-rules.md +70 -49
- package/skills/weaver-e10-yepiaotong/references/reim-fast-path.md +119 -0
- package/skills/weaver-e10-yepiaotong/references/reim-form-fill-rules.md +55 -36
- package/skills/weaver-e10-yepiaotong/references/reim-matching-rules.md +4 -0
- package/skills/weaver-e10-yepiaotong/references/reim-phone-subsidy-rules.md +149 -0
- package/skills/weaver-e10-yepiaotong/references/reim-workflow.md +125 -5
- package/skills/weaver-e10-yepiaotong/references/source-manifest.json +430 -63
- package/skills/weaver-e10-yimiaoban/SKILL.md +4 -12
- package/skills/weaver-e10-yimiaoban/references/source-manifest.json +3 -3
- package/skills/weaver-e10-ziguanjia/SKILL.md +2 -1
- package/skills/weaver-e10-ziguanjia/references/ziguanjia-agent-entry.md +3 -3
- package/tools/weaver-skill-detector-1.0.13/SKILL.md +9 -9
- package/tools/weaver-skill-detector-1.0.13/references/checklist.md +3 -3
- package/tools/weaver-skill-detector-1.0.13/scripts/__pycache__/validate_skill.cpython-313.pyc +0 -0
- package/tools/weaver-skill-detector-1.0.13/scripts/validate_skill.py +98 -91
- package/scripts/sync-connector-skills.mjs +0 -172
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { CliError, ExitCode } from '../../core/errors.js';
|
|
2
|
+
/** 日报模块结构化错误:type/subtype 驱动 Agent 决策,exitCode 决定进程退出码。 */
|
|
3
|
+
export class BlogCliError extends CliError {
|
|
4
|
+
type;
|
|
5
|
+
subtype;
|
|
6
|
+
code;
|
|
7
|
+
retryable;
|
|
8
|
+
stage;
|
|
9
|
+
details;
|
|
10
|
+
partialData;
|
|
11
|
+
constructor(type, subtype, message, options = {}) {
|
|
12
|
+
super(message, options.exitCode ?? ExitCode.InternalError);
|
|
13
|
+
this.name = 'BlogCliError';
|
|
14
|
+
this.type = type;
|
|
15
|
+
this.subtype = subtype;
|
|
16
|
+
this.code = options.code;
|
|
17
|
+
this.retryable = options.retryable ?? false;
|
|
18
|
+
this.stage = options.stage;
|
|
19
|
+
this.details = options.details;
|
|
20
|
+
this.partialData = options.partialData;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
export function blogValidationError(subtype, message, details) {
|
|
24
|
+
return new BlogCliError('validation', subtype, message, {
|
|
25
|
+
details,
|
|
26
|
+
exitCode: ExitCode.UsageError,
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
export function blogAuthError(subtype, message, details) {
|
|
30
|
+
return new BlogCliError('authentication', subtype, message, {
|
|
31
|
+
details,
|
|
32
|
+
exitCode: ExitCode.AuthError,
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
export function blogNetworkError(subtype, message, options = {}) {
|
|
36
|
+
return new BlogCliError('network', subtype, message, {
|
|
37
|
+
...options,
|
|
38
|
+
retryable: options.retryable ?? true,
|
|
39
|
+
exitCode: ExitCode.NetworkError,
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
export function blogConfirmationError(action, details) {
|
|
43
|
+
return new BlogCliError('confirmation', 'required', '该操作需要明确确认', {
|
|
44
|
+
details: { action, ...details },
|
|
45
|
+
exitCode: ExitCode.ConfirmationRequired,
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
export function blogPartialError(message, partialData, details) {
|
|
49
|
+
return new BlogCliError('partial', 'write_uncertain', message, {
|
|
50
|
+
details,
|
|
51
|
+
partialData,
|
|
52
|
+
exitCode: ExitCode.Partial,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
export function isBlogNetworkError(error) {
|
|
56
|
+
return Boolean(error
|
|
57
|
+
&& typeof error === 'object'
|
|
58
|
+
&& 'type' in error
|
|
59
|
+
&& error.type === 'network');
|
|
60
|
+
}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { ExitCode } from '../../core/errors.js';
|
|
2
|
+
import { requireE10Session } from '../../internal/e10/context.js';
|
|
3
|
+
import { getActiveProfile } from '../../internal/e10/auth/session.js';
|
|
4
|
+
import { createE10RequestRuntime } from '../../internal/e10/request-runtime.js';
|
|
5
|
+
import { BlogCliError, blogAuthError, blogNetworkError, blogValidationError, } from './errors.js';
|
|
6
|
+
const MAX_EXPORT_BYTES = 50 * 1024 * 1024;
|
|
7
|
+
/** E10 登录失效在业务响应体里的 code(实测 -2 既可能是数字也可能是字符串) */
|
|
8
|
+
const SESSION_EXPIRED_CODES = new Set(['-2', -2]);
|
|
9
|
+
function assertPath(requestPath) {
|
|
10
|
+
if (typeof requestPath !== 'string' || !requestPath.startsWith('/') || requestPath.startsWith('//')) {
|
|
11
|
+
throw blogValidationError('path_invalid', '请求路径必须是相对绝对路径');
|
|
12
|
+
}
|
|
13
|
+
if (/^https?:/i.test(requestPath) || /[\r\n]/.test(requestPath) || requestPath.includes('/../')) {
|
|
14
|
+
throw blogValidationError('path_invalid', '请求路径不允许跨域或路径逃逸');
|
|
15
|
+
}
|
|
16
|
+
if (!requestPath.startsWith('/api/')) {
|
|
17
|
+
throw blogValidationError('path_not_allowed', '日报模块只能调用 /api/ 路径');
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
/** 业务码位置在三种响应形态间漂移:顶层 code / res_base.ret / data.res_base.ret */
|
|
21
|
+
function responseCode(value) {
|
|
22
|
+
return value?.code ?? value?.res_base?.ret ?? value?.data?.res_base?.ret;
|
|
23
|
+
}
|
|
24
|
+
function responseMessage(value) {
|
|
25
|
+
if (typeof value?.msg === 'string')
|
|
26
|
+
return value.msg;
|
|
27
|
+
if (typeof value?.message === 'string')
|
|
28
|
+
return value.message;
|
|
29
|
+
if (typeof value?.error === 'string')
|
|
30
|
+
return value.error;
|
|
31
|
+
return '泛微接口返回业务失败';
|
|
32
|
+
}
|
|
33
|
+
function isSessionExpired(value) {
|
|
34
|
+
const code = responseCode(value);
|
|
35
|
+
return code !== undefined && SESSION_EXPIRED_CODES.has(code);
|
|
36
|
+
}
|
|
37
|
+
/** 业务失败判定:fail === true,或 code 存在且不在 {0, 200} 与登录失效码之内 */
|
|
38
|
+
function isBusinessFailure(value) {
|
|
39
|
+
if (value?.fail === true)
|
|
40
|
+
return true;
|
|
41
|
+
const code = responseCode(value);
|
|
42
|
+
if (code === undefined || code === null)
|
|
43
|
+
return false;
|
|
44
|
+
return !SESSION_EXPIRED_CODES.has(code)
|
|
45
|
+
&& code !== 0 && code !== '0' && code !== 200 && code !== '200';
|
|
46
|
+
}
|
|
47
|
+
function inferProfile(ctx) {
|
|
48
|
+
const options = ctx.getGlobalOptions();
|
|
49
|
+
return options.profile || getActiveProfile();
|
|
50
|
+
}
|
|
51
|
+
export function createBlogHost(ctx, dependencies = {}) {
|
|
52
|
+
let e10Session = null;
|
|
53
|
+
let sessionContext = null;
|
|
54
|
+
const requireSession = dependencies.requireSession || requireE10Session;
|
|
55
|
+
async function ensureSession() {
|
|
56
|
+
if (!e10Session) {
|
|
57
|
+
e10Session = await requireSession(ctx);
|
|
58
|
+
sessionContext = {
|
|
59
|
+
baseUrl: e10Session.getBaseUrl(),
|
|
60
|
+
profile: inferProfile(ctx),
|
|
61
|
+
userId: e10Session.userId,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
return e10Session;
|
|
65
|
+
}
|
|
66
|
+
async function getSession() {
|
|
67
|
+
await ensureSession();
|
|
68
|
+
return sessionContext;
|
|
69
|
+
}
|
|
70
|
+
async function runtime() {
|
|
71
|
+
return createE10RequestRuntime(ctx, await ensureSession(), {
|
|
72
|
+
interceptors: dependencies.interceptors,
|
|
73
|
+
fetch: dependencies.fetch,
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
function assertSession(value) {
|
|
77
|
+
if (isSessionExpired(value)) {
|
|
78
|
+
throw blogAuthError('session_expired', 'E10 登录态已失效,请先向用户确认 E10 登录域名,再运行 weaver-work-cli auth login --base-url <域名> --agent_type <当前智能体名称> 完成登录');
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
async function blogRequest(request) {
|
|
82
|
+
const { method = 'POST', path, query, body, operation, timeoutMs = 30_000 } = request;
|
|
83
|
+
assertPath(path);
|
|
84
|
+
const response = await (await runtime()).requestJson({
|
|
85
|
+
module: 'blog',
|
|
86
|
+
operation,
|
|
87
|
+
method,
|
|
88
|
+
path,
|
|
89
|
+
query: query,
|
|
90
|
+
body,
|
|
91
|
+
timeoutMs,
|
|
92
|
+
});
|
|
93
|
+
if (response.status === 401 || response.status === 302) {
|
|
94
|
+
throw blogAuthError('session_expired', 'E10 登录态已失效,请先向用户确认 E10 登录域名,再运行 weaver-work-cli auth login --base-url <域名> --agent_type <当前智能体名称> 完成登录', { httpStatus: response.status });
|
|
95
|
+
}
|
|
96
|
+
if (response.parseError) {
|
|
97
|
+
if (response.status < 200 || response.status >= 300) {
|
|
98
|
+
throw new BlogCliError('api', 'http_error', `泛微接口 HTTP ${response.status}`, {
|
|
99
|
+
code: response.status,
|
|
100
|
+
details: { status: response.status },
|
|
101
|
+
exitCode: ExitCode.GeneralError,
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
throw blogNetworkError('protocol', `接口返回不是合法 JSON(HTTP ${response.status})`, { retryable: false });
|
|
105
|
+
}
|
|
106
|
+
if (response.status < 200 || response.status >= 300) {
|
|
107
|
+
throw new BlogCliError('api', 'http_error', `泛微接口 HTTP ${response.status}`, {
|
|
108
|
+
code: response.status,
|
|
109
|
+
details: { status: response.status, message: responseMessage(response.value) },
|
|
110
|
+
exitCode: ExitCode.GeneralError,
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
assertSession(response.value);
|
|
114
|
+
if (isBusinessFailure(response.value)) {
|
|
115
|
+
throw new BlogCliError('api', 'business_error', responseMessage(response.value), {
|
|
116
|
+
code: String(responseCode(response.value)),
|
|
117
|
+
details: { response: response.value },
|
|
118
|
+
exitCode: ExitCode.GeneralError,
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
return response.value;
|
|
122
|
+
}
|
|
123
|
+
async function blogBinaryRequest(request) {
|
|
124
|
+
const { method = 'POST', path, query, body, operation, timeoutMs = 60_000 } = request;
|
|
125
|
+
assertPath(path);
|
|
126
|
+
const response = await (await runtime()).requestBinary({
|
|
127
|
+
module: 'blog',
|
|
128
|
+
operation,
|
|
129
|
+
method,
|
|
130
|
+
path,
|
|
131
|
+
query: query,
|
|
132
|
+
body,
|
|
133
|
+
timeoutMs,
|
|
134
|
+
headers: { Accept: 'application/octet-stream, */*' },
|
|
135
|
+
});
|
|
136
|
+
if (response.status === 401 || response.status === 302) {
|
|
137
|
+
throw blogAuthError('session_expired', 'E10 登录态已失效,请先向用户确认 E10 登录域名,再运行 weaver-work-cli auth login --base-url <域名> --agent_type <当前智能体名称> 完成登录', { httpStatus: response.status });
|
|
138
|
+
}
|
|
139
|
+
const contentType = response.contentType;
|
|
140
|
+
const declaredLength = Number(response.headers.get('content-length'));
|
|
141
|
+
if (Number.isFinite(declaredLength) && declaredLength > MAX_EXPORT_BYTES) {
|
|
142
|
+
throw blogNetworkError('response_too_large', `导出文件超过 ${MAX_EXPORT_BYTES} 字节限制`, { retryable: false });
|
|
143
|
+
}
|
|
144
|
+
const content = response.content;
|
|
145
|
+
const looksLikeJson = /^[\s\r\n]*[[{]/.test(content.subarray(0, 64).toString('utf8'));
|
|
146
|
+
// 导出接口出错时返回 JSON(登录失效 / 业务失败),需在落盘前识别
|
|
147
|
+
if (response.status < 200 || response.status >= 300 || contentType.includes('json') || looksLikeJson) {
|
|
148
|
+
let value = {};
|
|
149
|
+
try {
|
|
150
|
+
value = JSON.parse(content.toString('utf8'));
|
|
151
|
+
}
|
|
152
|
+
catch {
|
|
153
|
+
value = {};
|
|
154
|
+
}
|
|
155
|
+
assertSession(value);
|
|
156
|
+
throw new BlogCliError('api', 'export_failed', responseMessage(value) || `导出失败(HTTP ${response.status})`, {
|
|
157
|
+
code: response.status,
|
|
158
|
+
details: { status: response.status, preview: content.subarray(0, 500).toString('utf8') },
|
|
159
|
+
exitCode: ExitCode.GeneralError,
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
if (!content.length) {
|
|
163
|
+
throw blogNetworkError('protocol', '导出接口返回空文件', { retryable: false });
|
|
164
|
+
}
|
|
165
|
+
if (content.length > MAX_EXPORT_BYTES) {
|
|
166
|
+
throw blogNetworkError('response_too_large', `导出文件超过 ${MAX_EXPORT_BYTES} 字节限制`, { retryable: false });
|
|
167
|
+
}
|
|
168
|
+
return { content, contentType };
|
|
169
|
+
}
|
|
170
|
+
return {
|
|
171
|
+
blogRequest,
|
|
172
|
+
blogBinaryRequest,
|
|
173
|
+
getSession,
|
|
174
|
+
};
|
|
175
|
+
}
|
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import { ExitCode, isCliError, toErrorEnvelope } from '../../core/errors.js';
|
|
3
|
+
import { createBlogContinuationSigner } from './continuation.js';
|
|
4
|
+
import { blogValidationError } from './errors.js';
|
|
5
|
+
import { createBlogHost } from './host.js';
|
|
6
|
+
import { blogManifest } from './manifest.js';
|
|
7
|
+
import { executeBlogOperation } from './operations.js';
|
|
8
|
+
function asOptions(value) {
|
|
9
|
+
return value && typeof value === 'object' && !Array.isArray(value) ? value : {};
|
|
10
|
+
}
|
|
11
|
+
async function readStdin() {
|
|
12
|
+
const chunks = [];
|
|
13
|
+
for await (const chunk of process.stdin) {
|
|
14
|
+
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
15
|
+
}
|
|
16
|
+
return Buffer.concat(chunks).toString('utf8');
|
|
17
|
+
}
|
|
18
|
+
function stripBom(value) {
|
|
19
|
+
return value.replace(/^\uFEFF+/u, '');
|
|
20
|
+
}
|
|
21
|
+
/** 统一解析 `--input-json` / `--input <path>` / `--input -`,并合并薄包装命令的具名参数。 */
|
|
22
|
+
export async function inputFrom(options, extra = {}) {
|
|
23
|
+
const opts = asOptions(options);
|
|
24
|
+
let input = {};
|
|
25
|
+
if (opts.input && opts.inputJson) {
|
|
26
|
+
throw blogValidationError('input_conflict', '不能同时传 --input 和 --input-json');
|
|
27
|
+
}
|
|
28
|
+
if (opts.inputJson) {
|
|
29
|
+
input = parseJsonInput(String(opts.inputJson), '--input-json');
|
|
30
|
+
}
|
|
31
|
+
if (opts.input) {
|
|
32
|
+
let raw;
|
|
33
|
+
try {
|
|
34
|
+
raw = opts.input === '-' ? await readStdin() : await readFile(String(opts.input), 'utf8');
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
throw blogValidationError('input_unreadable', `无法读取 --input:${String(opts.input)}`);
|
|
38
|
+
}
|
|
39
|
+
input = parseJsonInput(raw, '--input');
|
|
40
|
+
}
|
|
41
|
+
return {
|
|
42
|
+
...input,
|
|
43
|
+
...Object.fromEntries(Object.entries(extra).filter(([, value]) => value !== undefined && value !== '')),
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
function parseJsonInput(raw, label) {
|
|
47
|
+
try {
|
|
48
|
+
const parsed = JSON.parse(stripBom(raw));
|
|
49
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
50
|
+
throw new Error('input must be an object');
|
|
51
|
+
}
|
|
52
|
+
return parsed;
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
throw blogValidationError('input_invalid', `${label} 不是合法 JSON 对象`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
function withJsonInputOptions(command) {
|
|
59
|
+
command
|
|
60
|
+
.option('--input <path>', 'JSON input file, or - for stdin')
|
|
61
|
+
.option('--input-json <json>', 'inline JSON input object');
|
|
62
|
+
return command;
|
|
63
|
+
}
|
|
64
|
+
function intOption(value) {
|
|
65
|
+
if (value === undefined || value === null || value === '')
|
|
66
|
+
return undefined;
|
|
67
|
+
const parsed = Number(value);
|
|
68
|
+
return Number.isInteger(parsed) ? parsed : undefined;
|
|
69
|
+
}
|
|
70
|
+
function namesOption(value) {
|
|
71
|
+
if (typeof value !== 'string')
|
|
72
|
+
return undefined;
|
|
73
|
+
const items = value.split(',').map((item) => item.trim()).filter(Boolean);
|
|
74
|
+
return items.length ? items : undefined;
|
|
75
|
+
}
|
|
76
|
+
function successEnvelope(operation, result) {
|
|
77
|
+
return {
|
|
78
|
+
schemaVersion: 1,
|
|
79
|
+
ok: true,
|
|
80
|
+
operation,
|
|
81
|
+
data: result.data,
|
|
82
|
+
meta: { status: result.status },
|
|
83
|
+
warnings: [],
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
function failureEnvelope(error) {
|
|
87
|
+
const structured = error;
|
|
88
|
+
return {
|
|
89
|
+
schemaVersion: 1,
|
|
90
|
+
ok: false,
|
|
91
|
+
...(structured?.partialData === undefined ? {} : { data: structured.partialData }),
|
|
92
|
+
error: toErrorEnvelope(error),
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
async function executeAndPrint(ctx, operation, input) {
|
|
96
|
+
try {
|
|
97
|
+
const result = await executeBlogOperation(operation, input, {
|
|
98
|
+
host: createBlogHost(ctx),
|
|
99
|
+
continuation: createBlogContinuationSigner(ctx),
|
|
100
|
+
});
|
|
101
|
+
ctx.output.write(successEnvelope(operation, result), { json: true });
|
|
102
|
+
}
|
|
103
|
+
catch (error) {
|
|
104
|
+
console.error(JSON.stringify(failureEnvelope(error), null, 2));
|
|
105
|
+
process.exitCode = isCliError(error) ? error.exitCode : ExitCode.GeneralError;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
export const blogShortcut = {
|
|
109
|
+
name: 'blog',
|
|
110
|
+
description: '泛微E10工作日报 CLI(查询/发布/编辑/评论/点赞/提醒/导出)',
|
|
111
|
+
category: 'shortcut',
|
|
112
|
+
register({ program, action }) {
|
|
113
|
+
const blog = program.command('blog').description('E10 工作日报(查询/发布/编辑/评论/点赞/提醒/导出)');
|
|
114
|
+
blog.command('schema')
|
|
115
|
+
.description('Print blog operation manifest for agents')
|
|
116
|
+
.action(action((ctx) => {
|
|
117
|
+
ctx.output.write(blogManifest, { json: true });
|
|
118
|
+
}));
|
|
119
|
+
withJsonInputOptions(blog.command('run')
|
|
120
|
+
.description('Run a blog operation with JSON input')
|
|
121
|
+
.argument('<operation>', 'operation name, e.g. blog.query')).action(action(async (ctx, operation, options) => {
|
|
122
|
+
await executeAndPrint(ctx, String(operation), await inputFrom(options));
|
|
123
|
+
}));
|
|
124
|
+
withJsonInputOptions(blog.command('query')
|
|
125
|
+
.description('批量查群体日报(下属/关注),按天汇总提交情况')
|
|
126
|
+
.option('--user-type <type>', 'directSubordinate|indirectSubordinate|allSubordinate|myFollow')
|
|
127
|
+
.option('--start <date>', 'start date YYYY-MM-DD')
|
|
128
|
+
.option('--end <date>', 'end date YYYY-MM-DD')
|
|
129
|
+
.option('--keywords <text>', 'keyword filter')
|
|
130
|
+
.option('--page-size <n>', 'page size (max 300)')
|
|
131
|
+
.option('--page-no <n>', 'page number')).action(action(async (ctx, options) => {
|
|
132
|
+
const opts = asOptions(options);
|
|
133
|
+
await executeAndPrint(ctx, 'blog.query', await inputFrom(options, {
|
|
134
|
+
user_type: opts.userType,
|
|
135
|
+
start_date: opts.start,
|
|
136
|
+
end_date: opts.end,
|
|
137
|
+
keywords: opts.keywords,
|
|
138
|
+
page_size: intOption(opts.pageSize),
|
|
139
|
+
page_no: intOption(opts.pageNo),
|
|
140
|
+
}));
|
|
141
|
+
}));
|
|
142
|
+
withJsonInputOptions(blog.command('query-user')
|
|
143
|
+
.description('查单人日报(detailsByDate 逐日扫描,区间上限 62 天)')
|
|
144
|
+
.option('--user-id <id>', 'target user id')
|
|
145
|
+
.option('--name <name>', 'target user name (HRM exact match)')
|
|
146
|
+
.option('--date <date>', 'start date YYYY-MM-DD')
|
|
147
|
+
.option('--end <date>', 'end date (inclusive)')).action(action(async (ctx, options) => {
|
|
148
|
+
const opts = asOptions(options);
|
|
149
|
+
await executeAndPrint(ctx, 'blog.query_user', await inputFrom(options, {
|
|
150
|
+
user_id: opts.userId,
|
|
151
|
+
name: opts.name,
|
|
152
|
+
date: opts.date,
|
|
153
|
+
end_date: opts.end,
|
|
154
|
+
}));
|
|
155
|
+
}));
|
|
156
|
+
withJsonInputOptions(blog.command('resolve-users')
|
|
157
|
+
.description('HRM 按姓名解析 userId')
|
|
158
|
+
.option('--name <name>', 'employee name')).action(action(async (ctx, options) => {
|
|
159
|
+
const opts = asOptions(options);
|
|
160
|
+
await executeAndPrint(ctx, 'blog.resolve_users', await inputFrom(options, { name: opts.name }));
|
|
161
|
+
}));
|
|
162
|
+
withJsonInputOptions(blog.command('comments')
|
|
163
|
+
.description('查某条日报的评论列表')
|
|
164
|
+
.option('--blog-id <id>', 'blog id')
|
|
165
|
+
.option('--page-size <n>', 'page size (max 100)')
|
|
166
|
+
.option('--page-no <n>', 'page number')).action(action(async (ctx, options) => {
|
|
167
|
+
const opts = asOptions(options);
|
|
168
|
+
await executeAndPrint(ctx, 'blog.comments', await inputFrom(options, {
|
|
169
|
+
blog_id: opts.blogId,
|
|
170
|
+
page_size: intOption(opts.pageSize),
|
|
171
|
+
page_no: intOption(opts.pageNo),
|
|
172
|
+
}));
|
|
173
|
+
}));
|
|
174
|
+
withJsonInputOptions(blog.command('default-permission')
|
|
175
|
+
.description('查某日期的默认共享对象')
|
|
176
|
+
.option('--date <date>', 'blog date YYYY-MM-DD')).action(action(async (ctx, options) => {
|
|
177
|
+
const opts = asOptions(options);
|
|
178
|
+
await executeAndPrint(ctx, 'blog.default_permission', await inputFrom(options, { date: opts.date }));
|
|
179
|
+
}));
|
|
180
|
+
withJsonInputOptions(blog.command('export')
|
|
181
|
+
.description('导出日报为 xlsx 文件(拒绝覆盖已存在文件)')
|
|
182
|
+
.option('--start <date>', 'start date YYYY-MM-DD')
|
|
183
|
+
.option('--end <date>', 'end date YYYY-MM-DD')
|
|
184
|
+
.option('--output <path>', 'output .xlsx path')
|
|
185
|
+
.option('--page-size <n>', 'page size')).action(action(async (ctx, options) => {
|
|
186
|
+
const opts = asOptions(options);
|
|
187
|
+
await executeAndPrint(ctx, 'blog.export', await inputFrom(options, {
|
|
188
|
+
start_date: opts.start,
|
|
189
|
+
end_date: opts.end,
|
|
190
|
+
output: opts.output,
|
|
191
|
+
page_size: intOption(opts.pageSize),
|
|
192
|
+
}));
|
|
193
|
+
}));
|
|
194
|
+
const publish = blog.command('publish').description('发布日报命令组(prepare -> apply)');
|
|
195
|
+
withJsonInputOptions(publish.command('prepare')
|
|
196
|
+
.description('Prepare blog.publish(查重 + 回填默认共享 + 签发 continuation)')
|
|
197
|
+
.option('--date <date>', 'blog date YYYY-MM-DD')
|
|
198
|
+
.option('--content <text>', 'blog content')
|
|
199
|
+
.option('--no-share-default', 'skip default share objects')).action(action(async (ctx, options) => {
|
|
200
|
+
const opts = asOptions(options);
|
|
201
|
+
await executeAndPrint(ctx, 'blog.publish.prepare', await inputFrom(options, {
|
|
202
|
+
date: opts.date,
|
|
203
|
+
content: opts.content,
|
|
204
|
+
share_default: opts.shareDefault === false ? false : undefined,
|
|
205
|
+
}));
|
|
206
|
+
}));
|
|
207
|
+
withJsonInputOptions(publish.command('apply')
|
|
208
|
+
.description('Apply blog.publish(需 confirm 与 continuation)')
|
|
209
|
+
.option('--continuation <token>', 'continuation token from prepare')
|
|
210
|
+
.option('--yes', 'confirm the write operation')).action(action(async (ctx, options) => {
|
|
211
|
+
const opts = asOptions(options);
|
|
212
|
+
await executeAndPrint(ctx, 'blog.publish.apply', await inputFrom(options, {
|
|
213
|
+
continuation: opts.continuation,
|
|
214
|
+
confirm: opts.yes === true ? true : undefined,
|
|
215
|
+
}));
|
|
216
|
+
}));
|
|
217
|
+
const edit = blog.command('edit').description('编辑日报命令组(prepare -> apply)');
|
|
218
|
+
withJsonInputOptions(edit.command('prepare')
|
|
219
|
+
.description('Prepare blog.edit(回查原内容与差异 + 签发 continuation)')
|
|
220
|
+
.option('--user-id <id>', 'target user id')
|
|
221
|
+
.option('--name <name>', 'target user name')
|
|
222
|
+
.option('--date <date>', 'blog date YYYY-MM-DD')
|
|
223
|
+
.option('--content <text>', 'new blog content')).action(action(async (ctx, options) => {
|
|
224
|
+
const opts = asOptions(options);
|
|
225
|
+
await executeAndPrint(ctx, 'blog.edit.prepare', await inputFrom(options, {
|
|
226
|
+
user_id: opts.userId,
|
|
227
|
+
name: opts.name,
|
|
228
|
+
date: opts.date,
|
|
229
|
+
content: opts.content,
|
|
230
|
+
}));
|
|
231
|
+
}));
|
|
232
|
+
withJsonInputOptions(edit.command('apply')
|
|
233
|
+
.description('Apply blog.edit(需 confirm 与 continuation)')
|
|
234
|
+
.option('--continuation <token>', 'continuation token from prepare')
|
|
235
|
+
.option('--yes', 'confirm the write operation')).action(action(async (ctx, options) => {
|
|
236
|
+
const opts = asOptions(options);
|
|
237
|
+
await executeAndPrint(ctx, 'blog.edit.apply', await inputFrom(options, {
|
|
238
|
+
continuation: opts.continuation,
|
|
239
|
+
confirm: opts.yes === true ? true : undefined,
|
|
240
|
+
}));
|
|
241
|
+
}));
|
|
242
|
+
const comment = blog.command('comment').description('评论日报命令组(prepare -> apply)');
|
|
243
|
+
withJsonInputOptions(comment.command('prepare')
|
|
244
|
+
.description('Prepare blog.comment(定位目标日报 + 签发 continuation)')
|
|
245
|
+
.option('--blog-id <id>', 'blog id (or date + user)')
|
|
246
|
+
.option('--user-id <id>', 'target user id')
|
|
247
|
+
.option('--name <name>', 'target user name')
|
|
248
|
+
.option('--date <date>', 'blog date YYYY-MM-DD')
|
|
249
|
+
.option('--content <text>', 'comment content')).action(action(async (ctx, options) => {
|
|
250
|
+
const opts = asOptions(options);
|
|
251
|
+
await executeAndPrint(ctx, 'blog.comment.prepare', await inputFrom(options, {
|
|
252
|
+
blog_id: opts.blogId,
|
|
253
|
+
user_id: opts.userId,
|
|
254
|
+
name: opts.name,
|
|
255
|
+
date: opts.date,
|
|
256
|
+
content: opts.content,
|
|
257
|
+
}));
|
|
258
|
+
}));
|
|
259
|
+
withJsonInputOptions(comment.command('apply')
|
|
260
|
+
.description('Apply blog.comment(需 confirm 与 continuation)')
|
|
261
|
+
.option('--continuation <token>', 'continuation token from prepare')
|
|
262
|
+
.option('--yes', 'confirm the write operation')).action(action(async (ctx, options) => {
|
|
263
|
+
const opts = asOptions(options);
|
|
264
|
+
await executeAndPrint(ctx, 'blog.comment.apply', await inputFrom(options, {
|
|
265
|
+
continuation: opts.continuation,
|
|
266
|
+
confirm: opts.yes === true ? true : undefined,
|
|
267
|
+
}));
|
|
268
|
+
}));
|
|
269
|
+
const like = blog.command('like').description('点赞/取消点赞命令组(prepare -> apply)');
|
|
270
|
+
withJsonInputOptions(like.command('prepare')
|
|
271
|
+
.description('Prepare blog.like(定位目标日报 + 签发 continuation)')
|
|
272
|
+
.option('--blog-id <id>', 'blog id (or date + user)')
|
|
273
|
+
.option('--user-id <id>', 'target user id')
|
|
274
|
+
.option('--name <name>', 'target user name')
|
|
275
|
+
.option('--date <date>', 'blog date YYYY-MM-DD')
|
|
276
|
+
.option('--cancel', 'cancel the like (cancelVote)')).action(action(async (ctx, options) => {
|
|
277
|
+
const opts = asOptions(options);
|
|
278
|
+
await executeAndPrint(ctx, 'blog.like.prepare', await inputFrom(options, {
|
|
279
|
+
blog_id: opts.blogId,
|
|
280
|
+
user_id: opts.userId,
|
|
281
|
+
name: opts.name,
|
|
282
|
+
date: opts.date,
|
|
283
|
+
cancel: opts.cancel === true ? true : undefined,
|
|
284
|
+
}));
|
|
285
|
+
}));
|
|
286
|
+
withJsonInputOptions(like.command('apply')
|
|
287
|
+
.description('Apply blog.like(需 confirm 与 continuation)')
|
|
288
|
+
.option('--continuation <token>', 'continuation token from prepare')
|
|
289
|
+
.option('--yes', 'confirm the write operation')).action(action(async (ctx, options) => {
|
|
290
|
+
const opts = asOptions(options);
|
|
291
|
+
await executeAndPrint(ctx, 'blog.like.apply', await inputFrom(options, {
|
|
292
|
+
continuation: opts.continuation,
|
|
293
|
+
confirm: opts.yes === true ? true : undefined,
|
|
294
|
+
}));
|
|
295
|
+
}));
|
|
296
|
+
const remind = blog.command('remind').description('提醒提交日报命令组(prepare -> apply)');
|
|
297
|
+
withJsonInputOptions(remind.command('prepare')
|
|
298
|
+
.description('Prepare blog.remind(解析被提醒人 + 默认文案 + 签发 continuation)')
|
|
299
|
+
.option('--user-ids <id,id,...>', 'remind target user ids')
|
|
300
|
+
.option('--names <name,name,...>', 'remind target names (HRM resolved)')
|
|
301
|
+
.option('--date <date>', 'blog date YYYY-MM-DD')
|
|
302
|
+
.option('--content <text>', 'custom remind content')
|
|
303
|
+
.option('--year <n>', 'blog year')).action(action(async (ctx, options) => {
|
|
304
|
+
const opts = asOptions(options);
|
|
305
|
+
await executeAndPrint(ctx, 'blog.remind.prepare', await inputFrom(options, {
|
|
306
|
+
user_ids: opts.userIds,
|
|
307
|
+
names: namesOption(opts.names),
|
|
308
|
+
date: opts.date,
|
|
309
|
+
content: opts.content,
|
|
310
|
+
year: intOption(opts.year),
|
|
311
|
+
}));
|
|
312
|
+
}));
|
|
313
|
+
withJsonInputOptions(remind.command('apply')
|
|
314
|
+
.description('Apply blog.remind(需 confirm 与 continuation)')
|
|
315
|
+
.option('--continuation <token>', 'continuation token from prepare')
|
|
316
|
+
.option('--yes', 'confirm the write operation')).action(action(async (ctx, options) => {
|
|
317
|
+
const opts = asOptions(options);
|
|
318
|
+
await executeAndPrint(ctx, 'blog.remind.apply', await inputFrom(options, {
|
|
319
|
+
continuation: opts.continuation,
|
|
320
|
+
confirm: opts.yes === true ? true : undefined,
|
|
321
|
+
}));
|
|
322
|
+
}));
|
|
323
|
+
},
|
|
324
|
+
};
|