dsh-multigameassistant 2.0.0 → 2.0.1
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 +7 -3
- package/cordis.patch.yml +3 -1
- package/lib/analyzer.js +3 -3
- package/lib/{chunk-FLQD3DKB.js → chunk-BNGDT7YT.js} +2 -2
- package/lib/{chunk-5WTH2CYW.js → chunk-D7JEXAT5.js} +2 -2
- package/lib/{chunk-BL6OSR2I.js → chunk-HPQCV6WO.js} +77 -5
- package/lib/{chunk-7XMNAHZ2.js → chunk-J46OASOG.js} +1 -1
- package/lib/{chunk-KIAOFNCB.js → chunk-YG4B5G7F.js} +38 -5
- package/lib/{chunk-2DZ75ANX.js → chunk-ZQ6KFVEO.js} +69 -1
- package/lib/emulator.js +2 -2
- package/lib/feishu.js +3 -3
- package/lib/game-intel.js +407 -28
- package/lib/gateway.js +2 -2
- package/lib/guard.js +1 -1
- package/lib/intervene.js +3 -3
- package/lib/monitor.js +3 -3
- package/lib/notify.js +3 -3
- package/lib/orchestrator.js +5 -5
- package/lib/qqbot.js +3 -3
- package/lib/runner.js +3 -3
- package/lib/scheduler.js +1 -1
- package/lib/script-registry.js +41 -8
- package/package.json +4 -3
- package/skills/game-intel.md +8 -0
- package/web/assets/{index-DAKeB3Cw.js → index-Baf6Mpe9.js} +97 -97
- package/web/assets/index-Baf6Mpe9.js.map +1 -0
- package/web/assets/index-BfVFC1Ik.css +1 -0
- package/web/index.html +2 -2
- package/web/assets/index-B8Gy9VoQ.css +0 -1
- package/web/assets/index-DAKeB3Cw.js.map +0 -1
package/lib/monitor.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { createRequire as __adgCreateRequire } from 'node:module'; import { dirname as __adgDirname } from 'node:path'; import { fileURLToPath as __adgFileURLToPath } from 'node:url'; const require = __adgCreateRequire(import.meta.url); const __filename = __adgFileURLToPath(import.meta.url); const __dirname = __adgDirname(__filename);
|
|
2
2
|
import {
|
|
3
3
|
parseDuration
|
|
4
|
-
} from "./chunk-
|
|
5
|
-
import "./chunk-
|
|
4
|
+
} from "./chunk-D7JEXAT5.js";
|
|
5
|
+
import "./chunk-J46OASOG.js";
|
|
6
6
|
import {
|
|
7
7
|
writeFileAtomic
|
|
8
8
|
} from "./chunk-CCAB6XXZ.js";
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
MONITOR_CAPABILITY,
|
|
12
12
|
MonitorSettings,
|
|
13
13
|
external_exports
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-HPQCV6WO.js";
|
|
15
15
|
import "./chunk-2UFLGPDY.js";
|
|
16
16
|
|
|
17
17
|
// packages/monitor/lib/index.js
|
package/lib/notify.js
CHANGED
|
@@ -16,10 +16,10 @@ import {
|
|
|
16
16
|
replyPlain,
|
|
17
17
|
sessionConversations,
|
|
18
18
|
textReply
|
|
19
|
-
} from "./chunk-
|
|
20
|
-
import "./chunk-
|
|
19
|
+
} from "./chunk-BNGDT7YT.js";
|
|
20
|
+
import "./chunk-ZQ6KFVEO.js";
|
|
21
21
|
import "./chunk-CCAB6XXZ.js";
|
|
22
|
-
import "./chunk-
|
|
22
|
+
import "./chunk-HPQCV6WO.js";
|
|
23
23
|
import "./chunk-2UFLGPDY.js";
|
|
24
24
|
export {
|
|
25
25
|
AdgNotify,
|
package/lib/orchestrator.js
CHANGED
|
@@ -4,17 +4,17 @@ import {
|
|
|
4
4
|
PARAMS_SCHEMA,
|
|
5
5
|
parseDuration,
|
|
6
6
|
taskParams
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-D7JEXAT5.js";
|
|
8
8
|
import {
|
|
9
9
|
TaskInputError,
|
|
10
10
|
renderTask
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-J46OASOG.js";
|
|
12
12
|
import {
|
|
13
13
|
MAIN,
|
|
14
14
|
finalText,
|
|
15
15
|
sessionConversations
|
|
16
|
-
} from "./chunk-
|
|
17
|
-
import "./chunk-
|
|
16
|
+
} from "./chunk-BNGDT7YT.js";
|
|
17
|
+
import "./chunk-ZQ6KFVEO.js";
|
|
18
18
|
import {
|
|
19
19
|
writeFileAtomic
|
|
20
20
|
} from "./chunk-CCAB6XXZ.js";
|
|
@@ -33,7 +33,7 @@ import {
|
|
|
33
33
|
isMarker,
|
|
34
34
|
taskMessage,
|
|
35
35
|
withStartEnd
|
|
36
|
-
} from "./chunk-
|
|
36
|
+
} from "./chunk-HPQCV6WO.js";
|
|
37
37
|
import "./chunk-2UFLGPDY.js";
|
|
38
38
|
|
|
39
39
|
// packages/orchestrator/lib/index.js
|
package/lib/qqbot.js
CHANGED
|
@@ -4,8 +4,8 @@ import {
|
|
|
4
4
|
questionText,
|
|
5
5
|
replyMarkdown,
|
|
6
6
|
replyPlain
|
|
7
|
-
} from "./chunk-
|
|
8
|
-
import "./chunk-
|
|
7
|
+
} from "./chunk-BNGDT7YT.js";
|
|
8
|
+
import "./chunk-ZQ6KFVEO.js";
|
|
9
9
|
import {
|
|
10
10
|
writeFileAtomic
|
|
11
11
|
} from "./chunk-CCAB6XXZ.js";
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
QQPending,
|
|
16
16
|
QQSettings,
|
|
17
17
|
external_exports
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-HPQCV6WO.js";
|
|
19
19
|
import "./chunk-2UFLGPDY.js";
|
|
20
20
|
|
|
21
21
|
// packages/qqbot/lib/index.js
|
package/lib/runner.js
CHANGED
|
@@ -19,9 +19,9 @@ import {
|
|
|
19
19
|
runnerTools,
|
|
20
20
|
setIn,
|
|
21
21
|
taskParams
|
|
22
|
-
} from "./chunk-
|
|
23
|
-
import "./chunk-
|
|
24
|
-
import "./chunk-
|
|
22
|
+
} from "./chunk-D7JEXAT5.js";
|
|
23
|
+
import "./chunk-J46OASOG.js";
|
|
24
|
+
import "./chunk-HPQCV6WO.js";
|
|
25
25
|
import "./chunk-2UFLGPDY.js";
|
|
26
26
|
export {
|
|
27
27
|
AdgRunner,
|
package/lib/scheduler.js
CHANGED
|
@@ -2,7 +2,7 @@ import { createRequire as __adgCreateRequire } from 'node:module'; import { dirn
|
|
|
2
2
|
import {
|
|
3
3
|
SCHEDULE_CAPABILITY,
|
|
4
4
|
external_exports
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-HPQCV6WO.js";
|
|
6
6
|
import "./chunk-2UFLGPDY.js";
|
|
7
7
|
|
|
8
8
|
// packages/scheduler/lib/index.js
|
package/lib/script-registry.js
CHANGED
|
@@ -24,7 +24,7 @@ import {
|
|
|
24
24
|
setupExitText,
|
|
25
25
|
setupKind,
|
|
26
26
|
systemHost
|
|
27
|
-
} from "./chunk-
|
|
27
|
+
} from "./chunk-YG4B5G7F.js";
|
|
28
28
|
import {
|
|
29
29
|
MANIFEST_FILE,
|
|
30
30
|
SKILL_FILE,
|
|
@@ -32,11 +32,11 @@ import {
|
|
|
32
32
|
globToRegExp,
|
|
33
33
|
parseManifest,
|
|
34
34
|
versionOfTag
|
|
35
|
-
} from "./chunk-
|
|
35
|
+
} from "./chunk-J46OASOG.js";
|
|
36
36
|
import {
|
|
37
37
|
sessionConversations
|
|
38
|
-
} from "./chunk-
|
|
39
|
-
import "./chunk-
|
|
38
|
+
} from "./chunk-BNGDT7YT.js";
|
|
39
|
+
import "./chunk-ZQ6KFVEO.js";
|
|
40
40
|
import {
|
|
41
41
|
writeFileAtomic
|
|
42
42
|
} from "./chunk-CCAB6XXZ.js";
|
|
@@ -59,7 +59,7 @@ import {
|
|
|
59
59
|
optimizeScriptPrompt,
|
|
60
60
|
parseGitHubLink,
|
|
61
61
|
taskMessage
|
|
62
|
-
} from "./chunk-
|
|
62
|
+
} from "./chunk-HPQCV6WO.js";
|
|
63
63
|
import "./chunk-2UFLGPDY.js";
|
|
64
64
|
|
|
65
65
|
// packages/script-registry/lib/index.js
|
|
@@ -407,7 +407,7 @@ var StoredScript = external_exports.object({
|
|
|
407
407
|
var PendingSetup = external_exports.object({
|
|
408
408
|
scriptId: external_exports.string(),
|
|
409
409
|
name: external_exports.string(),
|
|
410
|
-
kind: external_exports.enum(["nsis", "inno"]),
|
|
410
|
+
kind: external_exports.enum(["nsis", "inno", "kachina"]),
|
|
411
411
|
/** The installer, kept in the script's downloads folder until it is done. */
|
|
412
412
|
file: external_exports.string(),
|
|
413
413
|
version: external_exports.string(),
|
|
@@ -489,6 +489,7 @@ function stripUndefined(value) {
|
|
|
489
489
|
// packages/script-registry/lib/library.js
|
|
490
490
|
var CATALOGUE_TTL_MS = 24 * 60 * 6e4;
|
|
491
491
|
var PRE_RUN_CHECK_MS = 3e4;
|
|
492
|
+
var MAX_SETUP_ONLY_FILES = 4;
|
|
492
493
|
var ScriptLibrary = class {
|
|
493
494
|
toolsDir;
|
|
494
495
|
#options;
|
|
@@ -971,7 +972,7 @@ var ScriptLibrary = class {
|
|
|
971
972
|
async #installJob(scriptId, source, request, channels, pack, ctl) {
|
|
972
973
|
const script = this.#state.scripts.find((s) => s.id === scriptId);
|
|
973
974
|
const previous = script === void 0 ? void 0 : currentVersion(script);
|
|
974
|
-
const have = (version2) => script?.versions.some((v) => v.version === version2) === true;
|
|
975
|
+
const have = (version2) => script?.versions.some((v) => v.version === version2 && (request.asset === void 0 || v.asset?.name === request.asset)) === true;
|
|
975
976
|
const branch = request.branch ?? (request.tag === void 0 && request.asset === void 0 ? script?.sourceBranch : void 0);
|
|
976
977
|
const previousAsset = script?.versions.find((v) => v.version === previous?.version)?.asset?.name;
|
|
977
978
|
const fetched = await this.#fetch(scriptId, channels, pack, previous?.version, ctl, { ...request, branch, previousAsset }, have);
|
|
@@ -1003,6 +1004,10 @@ var ScriptLibrary = class {
|
|
|
1003
1004
|
await rm(versionDir, { recursive: true, force: true });
|
|
1004
1005
|
if (!fetched.incremental) {
|
|
1005
1006
|
await extract(archive, versionDir, { signal: ctl.signal, ...root === void 0 ? {} : { root } });
|
|
1007
|
+
const inner = await this.#takeSoleSetup(versionDir, archive);
|
|
1008
|
+
if (inner !== void 0) {
|
|
1009
|
+
return this.#handOffSetup(inner.kind, { scriptId, file: inner.file, version, asset: fetched.asset, dir: versionDir, source: script?.source ?? source, ...pack === void 0 ? {} : { packId: pack.manifest.id }, update: script !== void 0 }, request.byAgent === true, ctl);
|
|
1010
|
+
}
|
|
1006
1011
|
} else {
|
|
1007
1012
|
const patch = `${versionDir}.patch`;
|
|
1008
1013
|
await rm(patch, { recursive: true, force: true });
|
|
@@ -1096,6 +1101,30 @@ var ScriptLibrary = class {
|
|
|
1096
1101
|
}
|
|
1097
1102
|
return setup.version;
|
|
1098
1103
|
}
|
|
1104
|
+
/**
|
|
1105
|
+
* An unpacked archive that is only a setup program (one exe, a few files at
|
|
1106
|
+
* most, and that exe an installer): the exe is moved beside the archive,
|
|
1107
|
+
* the unpacked folder and the archive deleted. @returns where the exe is
|
|
1108
|
+
* now and what installer it is; undefined for anything else (left as it is).
|
|
1109
|
+
*/
|
|
1110
|
+
async #takeSoleSetup(dir, archive) {
|
|
1111
|
+
const files = await listFiles(dir).catch(() => []);
|
|
1112
|
+
const exes = files.filter((f) => f.toLowerCase().endsWith(".exe"));
|
|
1113
|
+
if (exes.length !== 1 || files.length > MAX_SETUP_ONLY_FILES)
|
|
1114
|
+
return void 0;
|
|
1115
|
+
const inside = join2(dir, ...exes[0].split("/"));
|
|
1116
|
+
const kind = await setupKind(inside);
|
|
1117
|
+
if (kind === void 0)
|
|
1118
|
+
return void 0;
|
|
1119
|
+
const file = join2(dirname2(archive), basename(inside));
|
|
1120
|
+
if (!samePath(file, archive)) {
|
|
1121
|
+
await rm(file, { force: true });
|
|
1122
|
+
await rename2(inside, file);
|
|
1123
|
+
await rm(archive, { force: true });
|
|
1124
|
+
}
|
|
1125
|
+
await rm(dir, { recursive: true, force: true });
|
|
1126
|
+
return { file, kind };
|
|
1127
|
+
}
|
|
1099
1128
|
/** The setup program waiting to be run for a script, if any. */
|
|
1100
1129
|
pendingSetup(id) {
|
|
1101
1130
|
return this.#state.setups.find((s) => s.scriptId === id);
|
|
@@ -1202,6 +1231,10 @@ var ScriptLibrary = class {
|
|
|
1202
1231
|
ctl.phase("extracting", { message: `\u89E3\u538B ${fetched.asset.name}` });
|
|
1203
1232
|
await rm(staging, { recursive: true, force: true });
|
|
1204
1233
|
await extract(archive, staging, { signal: ctl.signal, ...fetched.incremental || root === void 0 ? {} : { root } });
|
|
1234
|
+
const inner = fetched.incremental ? void 0 : await this.#takeSoleSetup(staging, archive);
|
|
1235
|
+
if (inner !== void 0) {
|
|
1236
|
+
return this.#handOffSetup(inner.kind, { scriptId: script.id, file: inner.file, version, asset: fetched.asset, dir: target, source: script.source, ...pack === void 0 ? {} : { packId: pack.manifest.id }, update: true }, byAgent, ctl);
|
|
1237
|
+
}
|
|
1205
1238
|
const prefix = fetched.incremental ? await patchPrefix(staging, target, root) : void 0;
|
|
1206
1239
|
const from = prefix === void 0 ? staging : join2(staging, prefix);
|
|
1207
1240
|
const keep = await keptFiles(pack, target);
|
|
@@ -3253,7 +3286,7 @@ function scriptTools(library, approve) {
|
|
|
3253
3286
|
}),
|
|
3254
3287
|
tool({
|
|
3255
3288
|
name: TOOL_NAMES.setupRun,
|
|
3256
|
-
description: `\u8FD0\u884C\u811A\u672C\u5B89\u88C5\u6216\u66F4\u65B0\u65F6\u4E0B\u8F7D\u5230\u7684\u5B89\u88C5\u7A0B\u5E8F\uFF08NSIS / Inno Setup \u7684 setup.exe\uFF0C\u6709\u7684\u811A\u672C\u53EA\u53D1\u5E03\u8FD9\u79CD\u5B8C\u6574\u5305\uFF09\u3002quiet\uFF08\u9ED8\u8BA4 true\uFF09\uFF1A\u4E0D\u5F39\u7A97\u53E3\uFF0C\u9759\u9ED8\u88C5\u8FDB\u811A\u672C\u7684\u7248\u672C\u76EE\u5F55\u5E76\u7B49\u5B83\u88C5\u5B8C\uFF0C\u8FD4\u56DE\u9000\u51FA\u7801\u548C\u88C5\u51FA\u6765\u7684\u6587\u4EF6\uFF1Bfalse\uFF1A\u6253\u5F00\u5B89\u88C5\u7A0B\u5E8F\u81EA\u5DF1\u7684\u7A97\u53E3\uFF08\u5B89\u88C5\u4F4D\u7F6E\u5DF2\u9884\u5148\u586B\u597D\uFF09\u540E\u7ACB\u5373\u8FD4\u56DE\uFF0C\u518D\u7528 screen_capture / screen_tap \u4E00\u6B65\u6B65\u70B9\u5B8C\u3002\u88C5\u597D\u540E\u7528 ${TOOL_NAMES.import} \u5BFC\u5165\u90A3\u4E2A\u76EE\u5F55\uFF08path \u586B\u8FD4\u56DE\u7684 dir\uFF0Cid \u586B\u8FD9\u4E2A\u811A\u672C\u7684 id\uFF09\uFF0C\u5B89\u88C5\u624D\u7B97\u5B8C\u6210\u3002\u53EA\u80FD\u8FD0\u884C\u811A\u672C\u5E93\u4E0B\u8F7D\u7684\u5B89\u88C5\u7A0B\u5E8F\u3002`,
|
|
3289
|
+
description: `\u8FD0\u884C\u811A\u672C\u5B89\u88C5\u6216\u66F4\u65B0\u65F6\u4E0B\u8F7D\u5230\u7684\u5B89\u88C5\u7A0B\u5E8F\uFF08NSIS / Inno Setup / Kachina \u7684 setup.exe\uFF0C\u6216\u53EA\u88C5\u7740\u5B83\u7684\u538B\u7F29\u5305\uFF0C\u4F8B\u5982 Mirror\u9171 \u7684 BetterGI\uFF1B\u6709\u7684\u811A\u672C\u53EA\u53D1\u5E03\u8FD9\u79CD\u5B8C\u6574\u5305\uFF09\u3002quiet\uFF08\u9ED8\u8BA4 true\uFF09\uFF1A\u4E0D\u5F39\u7A97\u53E3\uFF0C\u9759\u9ED8\u88C5\u8FDB\u811A\u672C\u7684\u7248\u672C\u76EE\u5F55\u5E76\u7B49\u5B83\u88C5\u5B8C\uFF0C\u8FD4\u56DE\u9000\u51FA\u7801\u548C\u88C5\u51FA\u6765\u7684\u6587\u4EF6\uFF1Bfalse\uFF1A\u6253\u5F00\u5B89\u88C5\u7A0B\u5E8F\u81EA\u5DF1\u7684\u7A97\u53E3\uFF08\u5B89\u88C5\u4F4D\u7F6E\u5DF2\u9884\u5148\u586B\u597D\uFF09\u540E\u7ACB\u5373\u8FD4\u56DE\uFF0C\u518D\u7528 screen_capture / screen_tap \u4E00\u6B65\u6B65\u70B9\u5B8C\u3002\u88C5\u597D\u540E\u7528 ${TOOL_NAMES.import} \u5BFC\u5165\u90A3\u4E2A\u76EE\u5F55\uFF08path \u586B\u8FD4\u56DE\u7684 dir\uFF0Cid \u586B\u8FD9\u4E2A\u811A\u672C\u7684 id\uFF09\uFF0C\u5B89\u88C5\u624D\u7B97\u5B8C\u6210\u3002\u53EA\u80FD\u8FD0\u884C\u811A\u672C\u5E93\u4E0B\u8F7D\u7684\u5B89\u88C5\u7A0B\u5E8F\u3002`,
|
|
3257
3290
|
properties: {
|
|
3258
3291
|
id: { type: "string", description: "\u811A\u672C id\uFF08script_install / script_update \u7684\u7ED3\u679C\u91CC\u6709\uFF09\u3002" },
|
|
3259
3292
|
quiet: { type: "boolean", description: "\u9759\u9ED8\u5B89\u88C5\u5E76\u7B49\u5F85\u7ED3\u675F\uFF1B\u9ED8\u8BA4 true\u3002\u9759\u9ED8\u5931\u8D25\u6216\u9700\u8981\u5728\u754C\u9762\u91CC\u9009\u62E9\u65F6\u7528 false\u3002" }
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-multigameassistant",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.1",
|
|
4
4
|
"description": "多游戏助手 MultiGameAssistant 的 dsh 插件版:让 agent 管好各个游戏的日常脚本(安装、编排定时流水线、看护运行、查活动),界面在自己的网页里。",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"dsh",
|
|
@@ -16,7 +16,8 @@
|
|
|
16
16
|
"homepage": "https://github.com/haaahhhis/MultiGameAssistant",
|
|
17
17
|
"repository": {
|
|
18
18
|
"type": "git",
|
|
19
|
-
"url": "git+https://github.com/haaahhhis/MultiGameAssistant.git"
|
|
19
|
+
"url": "git+https://github.com/haaahhhis/MultiGameAssistant.git",
|
|
20
|
+
"directory": "packages/dsh-plugin"
|
|
20
21
|
},
|
|
21
22
|
"bugs": {
|
|
22
23
|
"url": "https://github.com/haaahhhis/MultiGameAssistant/issues"
|
|
@@ -59,7 +60,7 @@
|
|
|
59
60
|
],
|
|
60
61
|
"peerDependencies": {
|
|
61
62
|
"@deepseek-ai/cordis": "*",
|
|
62
|
-
"@deepseek-ai/dsh-credentials": "
|
|
63
|
+
"@deepseek-ai/dsh-credentials": ">=0.2.1-rc.5 <0.3.0-0"
|
|
63
64
|
},
|
|
64
65
|
"dsh": {
|
|
65
66
|
"bundle": {
|
package/skills/game-intel.md
CHANGED
|
@@ -27,6 +27,14 @@ description: 游戏活动信息:查有什么活动、还剩几天、商店换
|
|
|
27
27
|
7. 最后用 `ask_user_question` 问用户要不要把游戏关掉,选项「关掉游戏」「先开着」。游戏是你这次用 `game_launch` 打开的,就把「关掉游戏」放第一个、标签后面加 ` (Recommended)`。用户选关掉就 `game_close`,然后告诉用户已经关了;选开着就结束。第 2 步因为有脚本在用而结束的,不要问、也不要关。
|
|
28
28
|
- 流水线的 agent 节点里没人等着回答:不要问,节点要求里说了关就关,没说就开着。
|
|
29
29
|
|
|
30
|
+
## 用户自己加或改活动
|
|
31
|
+
|
|
32
|
+
用户说「帮我加一个活动」「把 XX 改成 …结束」「给这个活动换张图」时用 `game_activity_save`,不要用 `game_record`(那是记读到的):
|
|
33
|
+
|
|
34
|
+
- 新加:写 `game`、`name`,有时间就写 `starts_at` / `ends_at`(游戏服务器时间)。改已有的:先 `game_activities` 找到 `id`,只写要改的字段。
|
|
35
|
+
- 图片 `image`:用户给的图片网址、本机图片文件路径,或 `screenshot`(这个对话最近一张截图,比如刚用 `screen_capture` 截的活动页)。
|
|
36
|
+
- 用户填的内容比数据站优先,刷新不会改掉。要恢复成来源的:`clear` 列出字段,或 `game_activity_remove`(what=mine)。用户要删掉才用 `game_activity_remove`(what=all)。
|
|
37
|
+
|
|
30
38
|
## 日报
|
|
31
39
|
|
|
32
40
|
每天按「游戏」页里设置的时间自动发到飞书。用户要现在看:`game_report`;要发出去:`game_report`(send=true)。
|