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/game-intel.js
CHANGED
|
@@ -7,26 +7,28 @@ import {
|
|
|
7
7
|
GAME_MANIFEST_FILE,
|
|
8
8
|
GameManifest,
|
|
9
9
|
parseGameManifest
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-J46OASOG.js";
|
|
11
11
|
import {
|
|
12
12
|
sessionConversations
|
|
13
|
-
} from "./chunk-
|
|
14
|
-
import "./chunk-
|
|
13
|
+
} from "./chunk-BNGDT7YT.js";
|
|
14
|
+
import "./chunk-ZQ6KFVEO.js";
|
|
15
15
|
import {
|
|
16
16
|
writeFileAtomic
|
|
17
17
|
} from "./chunk-CCAB6XXZ.js";
|
|
18
18
|
import {
|
|
19
19
|
GAMES_CAPABILITY,
|
|
20
20
|
GamesSettings,
|
|
21
|
+
OWN_IMAGE,
|
|
22
|
+
SHOT_IMAGE,
|
|
21
23
|
external_exports,
|
|
22
24
|
taskMessage
|
|
23
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-HPQCV6WO.js";
|
|
24
26
|
import "./chunk-2UFLGPDY.js";
|
|
25
27
|
|
|
26
28
|
// packages/game-intel/lib/index.js
|
|
27
29
|
import { createHash } from "node:crypto";
|
|
28
|
-
import { mkdir as mkdir2, readdir, readFile as readFile2, writeFile } from "node:fs/promises";
|
|
29
|
-
import { join as join2 } from "node:path";
|
|
30
|
+
import { mkdir as mkdir2, readdir, readFile as readFile2, rm, writeFile } from "node:fs/promises";
|
|
31
|
+
import { isAbsolute, join as join2, resolve } from "node:path";
|
|
30
32
|
import { Service } from "@deepseek-ai/cordis";
|
|
31
33
|
|
|
32
34
|
// packages/game-intel/lib/calendar.js
|
|
@@ -162,6 +164,7 @@ var KEEP_UNDATED_MS = 14 * MS.DAY;
|
|
|
162
164
|
var MISMATCH_MS = 30 * MS.HOUR;
|
|
163
165
|
var DEFAULT_SETTINGS = { report: { enabled: true, at: "09:00", games: [], soonDays: 3, ai: true }, followed: [] };
|
|
164
166
|
var AGENT_PAGE = { id: "agent", name: "agent \u67E5\u5230\u7684\u7F51\u9875" };
|
|
167
|
+
var OWN_FIELDS = ["name", "startsAt", "endsAt", "kind", "description", "url", "cover"];
|
|
165
168
|
var StoredSchema = external_exports.object({
|
|
166
169
|
activities: external_exports.array(external_exports.looseObject({ id: external_exports.string(), game: external_exports.string(), name: external_exports.string() })).default([]),
|
|
167
170
|
refreshed: external_exports.record(external_exports.string(), external_exports.object({ at: external_exports.number(), ok: external_exports.boolean(), count: external_exports.number(), detail: external_exports.string().optional() })).default({}),
|
|
@@ -345,7 +348,7 @@ var Calendar = class {
|
|
|
345
348
|
delete item.facts[source.id];
|
|
346
349
|
this.#derive(item, timeZone);
|
|
347
350
|
}
|
|
348
|
-
this.#items = this.#items.filter((a) => a.game !== game ||
|
|
351
|
+
this.#items = this.#items.filter((a) => a.game !== game || this.#sourced(a) || a.mine !== void 0);
|
|
349
352
|
this.#prune(now);
|
|
350
353
|
this.#saved.refreshed[game] = { at: now, ok: true, count: events.length };
|
|
351
354
|
await this.save();
|
|
@@ -369,7 +372,8 @@ var Calendar = class {
|
|
|
369
372
|
* time, checked against the site's end); from a web page (`site`) it is
|
|
370
373
|
* that page's word on the event (the user's page it came from, else
|
|
371
374
|
* "agent 查到的网页"), kept beside the data sites' and used where they say
|
|
372
|
-
* nothing.
|
|
375
|
+
* nothing. `shot`: the screenshot read from the screen, already kept
|
|
376
|
+
* (`shot:<file>`): the evidence, and the picture where no source has one.
|
|
373
377
|
* @returns the events written, with how each was matched.
|
|
374
378
|
*/
|
|
375
379
|
async applyRead(game, from, events, context) {
|
|
@@ -397,11 +401,13 @@ var Calendar = class {
|
|
|
397
401
|
...event.cover !== void 0 && /^https:\/\/\S+$/.test(event.cover) ? { cover: event.cover } : {}
|
|
398
402
|
};
|
|
399
403
|
} else {
|
|
404
|
+
const image = context.shot ?? item.screen?.image;
|
|
400
405
|
item.screen = {
|
|
401
406
|
at: now,
|
|
402
407
|
...event.remaining === void 0 ? {} : { remaining: event.remaining },
|
|
403
408
|
...end === void 0 ? {} : { endsAt: end },
|
|
404
|
-
evidence:
|
|
409
|
+
evidence: context.shot !== void 0,
|
|
410
|
+
...image === void 0 ? {} : { image },
|
|
405
411
|
...context.sessionId === void 0 ? {} : { sessionId: context.sessionId }
|
|
406
412
|
};
|
|
407
413
|
if (event.todo !== void 0)
|
|
@@ -414,14 +420,121 @@ var Calendar = class {
|
|
|
414
420
|
delete item.progress;
|
|
415
421
|
}
|
|
416
422
|
this.#derive(item, timeZone);
|
|
417
|
-
if (from === "screen" && context.evidence !== void 0)
|
|
418
|
-
item.screen.evidence = await context.evidence(this.#public(item)).catch(() => false);
|
|
419
423
|
written.push({ activity: this.#public(item), matched: existing !== void 0 });
|
|
420
424
|
}
|
|
421
425
|
this.#prune(now);
|
|
422
426
|
await this.save();
|
|
423
427
|
return written;
|
|
424
428
|
}
|
|
429
|
+
/**
|
|
430
|
+
* The user's own word on an event (`target.id`), or an event of their own
|
|
431
|
+
* (a `name` and no id; one of that name already in the calendar is that
|
|
432
|
+
* one). Fields equal to what the sources say are not kept, so a later
|
|
433
|
+
* refresh still moves them; on an event only the user has, every field is.
|
|
434
|
+
* @returns the event; undefined when there is no event with that id in that game.
|
|
435
|
+
* @throws Error when a new one has no name.
|
|
436
|
+
*/
|
|
437
|
+
async saveOwn(target, patch, now, timeZone) {
|
|
438
|
+
let item;
|
|
439
|
+
if (target.id !== void 0) {
|
|
440
|
+
item = this.#items.find((a) => a.id === target.id && a.game === target.game);
|
|
441
|
+
if (item === void 0)
|
|
442
|
+
return void 0;
|
|
443
|
+
} else {
|
|
444
|
+
const name = typeof patch.name === "string" ? patch.name.trim() : "";
|
|
445
|
+
if (name === "")
|
|
446
|
+
throw new Error("\u65B0\u6D3B\u52A8\u8981\u6709\u540D\u5B57");
|
|
447
|
+
item = this.#items.find((a) => a.game === target.game && a.names.some((n) => idKey(n) === idKey(name))) ?? this.#create(target.game, name);
|
|
448
|
+
}
|
|
449
|
+
const mine = { ...item.mine };
|
|
450
|
+
delete mine.at;
|
|
451
|
+
for (const key of OWN_FIELDS) {
|
|
452
|
+
const value = patch[key];
|
|
453
|
+
if (value === void 0)
|
|
454
|
+
continue;
|
|
455
|
+
if (value === null || typeof value === "string" && value.trim() === "")
|
|
456
|
+
delete mine[key];
|
|
457
|
+
else
|
|
458
|
+
mine[key] = typeof value === "string" ? value.trim() : value;
|
|
459
|
+
}
|
|
460
|
+
if (mine.startsAt !== void 0 && mine.endsAt !== void 0 && mine.endsAt <= mine.startsAt)
|
|
461
|
+
throw new Error("\u7ED3\u675F\u65F6\u95F4\u8981\u665A\u4E8E\u5F00\u59CB\u65F6\u95F4");
|
|
462
|
+
if (this.#sourced(item)) {
|
|
463
|
+
const base = structuredClone(item);
|
|
464
|
+
delete base.mine;
|
|
465
|
+
this.#derive(base, timeZone);
|
|
466
|
+
for (const key of OWN_FIELDS)
|
|
467
|
+
if (mine[key] !== void 0 && mine[key] === base[key])
|
|
468
|
+
delete mine[key];
|
|
469
|
+
}
|
|
470
|
+
if (Object.keys(mine).length === 0)
|
|
471
|
+
delete item.mine;
|
|
472
|
+
else
|
|
473
|
+
item.mine = { ...mine, at: now };
|
|
474
|
+
if (mine.name !== void 0)
|
|
475
|
+
item.names = unique([...item.names, mine.name]);
|
|
476
|
+
if (patch.todo !== void 0)
|
|
477
|
+
item.todo = unique(patch.todo.map((t) => t.trim()).filter((t) => t !== "" && !item.done.includes(t)));
|
|
478
|
+
if (!this.#sourced(item) && item.mine === void 0) {
|
|
479
|
+
this.#items = this.#items.filter((a) => a !== item);
|
|
480
|
+
await this.save();
|
|
481
|
+
return void 0;
|
|
482
|
+
}
|
|
483
|
+
this.#derive(item, timeZone);
|
|
484
|
+
await this.save();
|
|
485
|
+
return this.#public(item);
|
|
486
|
+
}
|
|
487
|
+
/**
|
|
488
|
+
* Take back what the user wrote on an event: the sources' word shows again;
|
|
489
|
+
* an event only the user had goes.
|
|
490
|
+
* @returns the event as it is now; undefined when it went (or was not there).
|
|
491
|
+
*/
|
|
492
|
+
async resetOwn(id, timeZone) {
|
|
493
|
+
const item = this.#items.find((a) => a.id === id);
|
|
494
|
+
if (item === void 0)
|
|
495
|
+
return void 0;
|
|
496
|
+
delete item.mine;
|
|
497
|
+
if (!this.#sourced(item)) {
|
|
498
|
+
this.#items = this.#items.filter((a) => a !== item);
|
|
499
|
+
await this.save();
|
|
500
|
+
return void 0;
|
|
501
|
+
}
|
|
502
|
+
this.#derive(item, timeZone);
|
|
503
|
+
await this.save();
|
|
504
|
+
return this.#public(item);
|
|
505
|
+
}
|
|
506
|
+
/** The pictures the user added that an event still shows (`own:<file>`). */
|
|
507
|
+
ownImages() {
|
|
508
|
+
const out = /* @__PURE__ */ new Set();
|
|
509
|
+
for (const a of this.#items)
|
|
510
|
+
if (a.mine?.cover?.startsWith("own:") === true)
|
|
511
|
+
out.add(a.mine.cover);
|
|
512
|
+
return out;
|
|
513
|
+
}
|
|
514
|
+
/** The screenshots an event was read from that are still kept (`shot:<file>`). */
|
|
515
|
+
shotImages() {
|
|
516
|
+
const out = /* @__PURE__ */ new Set();
|
|
517
|
+
for (const a of this.#items)
|
|
518
|
+
if (a.screen?.image !== void 0)
|
|
519
|
+
out.add(a.screen.image);
|
|
520
|
+
return out;
|
|
521
|
+
}
|
|
522
|
+
/**
|
|
523
|
+
* Screenshots kept before they were pictures (one file per event): now
|
|
524
|
+
* kept as `shot:<file>`, by event id.
|
|
525
|
+
*/
|
|
526
|
+
async adoptShots(shots, timeZone) {
|
|
527
|
+
if (shots.size === 0)
|
|
528
|
+
return;
|
|
529
|
+
for (const item of this.#items) {
|
|
530
|
+
const shot = shots.get(item.id);
|
|
531
|
+
if (shot === void 0 || item.screen === void 0)
|
|
532
|
+
continue;
|
|
533
|
+
item.screen.image = shot;
|
|
534
|
+
this.#derive(item, timeZone(item.game));
|
|
535
|
+
}
|
|
536
|
+
await this.save();
|
|
537
|
+
}
|
|
425
538
|
async remove(id) {
|
|
426
539
|
const before = this.#items.length;
|
|
427
540
|
this.#items = this.#items.filter((a) => a.id !== id);
|
|
@@ -447,6 +560,10 @@ var Calendar = class {
|
|
|
447
560
|
const running = loose.find((a) => (a.startsAt ?? 0) <= now && now <= (a.endsAt ?? Infinity));
|
|
448
561
|
return running ?? loose[0];
|
|
449
562
|
}
|
|
563
|
+
/** Some source (a data site, a web page, the game screen) knows it. */
|
|
564
|
+
#sourced(item) {
|
|
565
|
+
return Object.keys(item.facts).length > 0 || item.screen !== void 0;
|
|
566
|
+
}
|
|
450
567
|
#create(game, name) {
|
|
451
568
|
let id = `${game}/${idKey(name)}`;
|
|
452
569
|
for (let n = 2; this.#items.some((a) => a.id === id); n++)
|
|
@@ -484,7 +601,23 @@ var Calendar = class {
|
|
|
484
601
|
delete item.site;
|
|
485
602
|
else
|
|
486
603
|
item.site = { source: primary.id, name: primary.fact.name, at: primary.fact.at };
|
|
604
|
+
const mine = item.mine;
|
|
605
|
+
if (mine?.name !== void 0) {
|
|
606
|
+
if (item.name !== mine.name)
|
|
607
|
+
item.baseName = item.name;
|
|
608
|
+
item.name = mine.name;
|
|
609
|
+
} else if (item.baseName !== void 0) {
|
|
610
|
+
item.name = item.baseName;
|
|
611
|
+
delete item.baseName;
|
|
612
|
+
}
|
|
613
|
+
for (const key of ["startsAt", "endsAt", "kind", "description", "url", "cover"])
|
|
614
|
+
if (mine?.[key] !== void 0)
|
|
615
|
+
set(key, mine[key]);
|
|
616
|
+
if (item.cover === void 0 && item.screen?.image !== void 0)
|
|
617
|
+
item.cover = item.screen.image;
|
|
487
618
|
delete item.mismatch;
|
|
619
|
+
if (mine?.endsAt !== void 0)
|
|
620
|
+
return;
|
|
488
621
|
const siteEnd = site?.fact.endsAt;
|
|
489
622
|
if (site === void 0 || siteEnd === void 0)
|
|
490
623
|
return;
|
|
@@ -502,6 +635,8 @@ var Calendar = class {
|
|
|
502
635
|
#prune(now) {
|
|
503
636
|
this.#items = this.#items.filter((a) => {
|
|
504
637
|
if (a.endsAt === void 0) {
|
|
638
|
+
if (a.mine !== void 0)
|
|
639
|
+
return true;
|
|
505
640
|
const seen = [a.screen?.at, ...Object.values(a.facts).map((f) => f.at)].filter((t) => t !== void 0);
|
|
506
641
|
return (seen.length === 0 ? now : Math.max(...seen)) + KEEP_UNDATED_MS > now;
|
|
507
642
|
}
|
|
@@ -509,9 +644,10 @@ var Calendar = class {
|
|
|
509
644
|
});
|
|
510
645
|
}
|
|
511
646
|
#public(item) {
|
|
512
|
-
const { names: _names, facts, ...activity } = item;
|
|
647
|
+
const { names: _names, facts, mine, baseName: _baseName, ...activity } = item;
|
|
513
648
|
const sources = Object.entries(facts).map(([id, f]) => ({ id, name: f.name, at: f.at, web: f.web, ...f.endsAt === void 0 ? {} : { endsAt: f.endsAt } }));
|
|
514
|
-
|
|
649
|
+
const own = mine === void 0 ? void 0 : { at: mine.at, fields: OWN_FIELDS.filter((k) => mine[k] !== void 0) };
|
|
650
|
+
return structuredClone({ ...activity, ...sources.length === 0 ? {} : { sources }, ...own === void 0 ? {} : { own } });
|
|
515
651
|
}
|
|
516
652
|
};
|
|
517
653
|
function migrate(item) {
|
|
@@ -988,6 +1124,7 @@ function followedManifest(game) {
|
|
|
988
1124
|
}
|
|
989
1125
|
|
|
990
1126
|
// packages/game-intel/lib/tools.js
|
|
1127
|
+
var OWN_KEYS = { name: "name", starts_at: "startsAt", ends_at: "endsAt", kind: "kind", description: "description", url: "url", image: "cover" };
|
|
991
1128
|
function parse(schema, args) {
|
|
992
1129
|
const parsed = schema.safeParse(args);
|
|
993
1130
|
if (!parsed.success)
|
|
@@ -1022,7 +1159,10 @@ function gameTools(deps) {
|
|
|
1022
1159
|
...a.startsAt !== void 0 && a.startsAt > now ? { starts: shortDate(a.startsAt, timeZone) } : {},
|
|
1023
1160
|
ends: a.endsAt === void 0 ? "\u672A\u77E5" : `${shortDate(a.endsAt, timeZone)}\uFF08${leftText(a.endsAt, now)}\uFF09`,
|
|
1024
1161
|
...a.shopEndsAt === void 0 ? {} : { shop_ends: shortDate(a.shopEndsAt, timeZone) },
|
|
1025
|
-
dates_from: a.site?.name ?? (a.screen !== void 0 ? "\u6E38\u620F\u753B\u9762" : "\u672A\u77E5"),
|
|
1162
|
+
dates_from: a.own?.fields.some((f) => f === "startsAt" || f === "endsAt") === true ? "\u7528\u6237\u81EA\u5DF1\u586B\u7684" : a.site?.name ?? (a.screen !== void 0 ? "\u6E38\u620F\u753B\u9762" : "\u672A\u77E5"),
|
|
1163
|
+
...a.own === void 0 ? {} : { set_by_user: a.own.fields.map((f) => Object.entries(OWN_KEYS).find(([, v]) => v === f)[0]), ...a.sources === void 0 && a.screen === void 0 ? { added_by_user: true } : {} },
|
|
1164
|
+
...a.kind === void 0 ? {} : { kind: a.kind },
|
|
1165
|
+
...a.cover === void 0 ? {} : { image: a.cover.startsWith("own:") ? "\u7528\u6237\u7684\u56FE\u7247" : a.cover.startsWith("shot:") ? "\u6E38\u620F\u622A\u56FE\uFF08\u6CA1\u6709\u522B\u7684\u56FE\u65F6\u7528\u5B83\uFF09" : a.cover },
|
|
1026
1166
|
...a.screen === void 0 ? {} : { read_in_game: shortDate(a.screen.at, timeZone), ...a.progress === void 0 ? {} : { progress: a.progress } },
|
|
1027
1167
|
// The checklist (from the game screen or kept by the user on the board), and the user's own "done".
|
|
1028
1168
|
...a.todo.length + a.done.length === 0 ? {} : { todo: a.todo, done: a.done },
|
|
@@ -1207,6 +1347,87 @@ function gameTools(deps) {
|
|
|
1207
1347
|
};
|
|
1208
1348
|
}
|
|
1209
1349
|
}),
|
|
1350
|
+
tool({
|
|
1351
|
+
name: "game_activity_save",
|
|
1352
|
+
description: [
|
|
1353
|
+
"\u66FF\u7528\u6237\u624B\u52A8\u6DFB\u52A0\u4E00\u4E2A\u6D3B\u52A8\uFF0C\u6216\u6539\u4E00\u4E2A\u5DF2\u6709\u6D3B\u52A8\uFF08id \u4ECE game_activities \u67E5\uFF09\u3002\u7528\u6237\u8BF4\u300C\u5E2E\u6211\u52A0\u4E00\u4E2A XX \u6D3B\u52A8\u300D\u300C\u628A XX \u7684\u7ED3\u675F\u65F6\u95F4\u6539\u6210\u2026\u300D\u300C\u7ED9\u8FD9\u4E2A\u6D3B\u52A8\u6362\u5F20\u56FE\u300D\u65F6\u7528\u3002",
|
|
1354
|
+
"\u5199\u8FDB\u53BB\u7684\u5B57\u6BB5\u662F\u7528\u6237\u81EA\u5DF1\u7684\u8BF4\u6CD5\uFF1A\u6BD4\u6570\u636E\u7AD9\u548C\u7F51\u9875\u4F18\u5148\uFF0C\u5237\u65B0\u4E0D\u4F1A\u6539\u6389\u4E5F\u4E0D\u4F1A\u5220\u6389\uFF1B\u548C\u6765\u6E90\u4E00\u6837\u7684\u503C\u4E0D\u5355\u72EC\u4FDD\u5B58\u3002\u8BFB\u5230\u7684\u7F51\u9875\u6216\u6E38\u620F\u753B\u9762\u7528 game_record\uFF0C\u4E0D\u8981\u7528\u8FD9\u4E2A\u3002",
|
|
1355
|
+
"image \u53EF\u4EE5\u662F\u56FE\u7247\u7F51\u5740\uFF08https\uFF0C\u4F1A\u4E0B\u8F7D\u4FDD\u5B58\uFF09\u3001\u672C\u673A\u56FE\u7247\u6587\u4EF6\u8DEF\u5F84\uFF08\u76F8\u5BF9\u8DEF\u5F84\u6309\u5DE5\u4F5C\u533A\uFF09\u3001\u6216 screenshot\uFF08\u8FD9\u4E2A\u5BF9\u8BDD\u6700\u8FD1\u4E00\u5F20\u622A\u56FE\uFF09\u3002clear \u91CC\u7684\u5B57\u6BB5\u6536\u56DE\u7528\u6237\u7684\u503C\uFF0C\u6062\u590D\u6210\u6765\u6E90\u7684\u3002"
|
|
1356
|
+
].join(""),
|
|
1357
|
+
properties: {
|
|
1358
|
+
game: GAME,
|
|
1359
|
+
id: { type: "string", description: "\u8981\u6539\u7684\u6D3B\u52A8 id\uFF08\u4E0D\u586B\u5C31\u662F\u65B0\u52A0\uFF1B\u540C\u540D\u7684\u5DF2\u6709\u6D3B\u52A8\u4F1A\u5F53\u6210\u540C\u4E00\u4E2A\uFF09\u3002" },
|
|
1360
|
+
name: { type: "string", description: "\u6D3B\u52A8\u540D\uFF1B\u65B0\u52A0\u65F6\u5FC5\u586B\u3002" },
|
|
1361
|
+
starts_at: { type: "string", description: "\u5F00\u59CB\u65F6\u95F4\uFF0C\u5199\u6210 2026/10/25 04:00 \u6216 10/25 04:00\uFF08\u6E38\u620F\u670D\u52A1\u5668\u65F6\u95F4\uFF09\u3002" },
|
|
1362
|
+
ends_at: { type: "string", description: "\u7ED3\u675F\u65F6\u95F4\uFF0C\u5199\u6CD5\u540C\u4E0A\u3002" },
|
|
1363
|
+
kind: { type: "string", description: "\u7C7B\u578B\uFF08\u53EF\u9009\uFF09\uFF0C\u4F8B\u5982\u300CSideStory\u300D\u300C\u7B7E\u5230\u300D\u300C\u9650\u65F6\u5546\u5E97\u300D\u3002" },
|
|
1364
|
+
description: { type: "string", description: "\u8BF4\u660E\uFF08\u53EF\u9009\uFF09\uFF0C500 \u5B57\u4EE5\u5185\u3002" },
|
|
1365
|
+
url: { type: "string", description: "\u6D3B\u52A8\u9875\u9762\u5730\u5740\uFF08\u53EF\u9009\uFF09\u3002" },
|
|
1366
|
+
image: { type: "string", description: "\u6D3B\u52A8\u5361\u7247\u7684\u56FE\u7247\uFF1Ahttps \u56FE\u7247\u7F51\u5740\u3001\u672C\u673A\u56FE\u7247\u6587\u4EF6\u8DEF\u5F84\uFF0C\u6216 screenshot\u3002" },
|
|
1367
|
+
todo: { type: "array", items: { type: "string" }, description: "\u8981\u505A\u7684\u4E8B\uFF08\u53EF\u9009\uFF0C\u66FF\u6362\u539F\u6765\u6CA1\u505A\u5B8C\u7684\u6E05\u5355\uFF09\uFF0C\u4F8B\u5982\u300C\u6D3B\u52A8\u5546\u5E97\u6362\u5B8C\u300D\u3002" },
|
|
1368
|
+
clear: { type: "array", items: { type: "string", enum: Object.keys(OWN_KEYS) }, description: "\u6536\u56DE\u7528\u6237\u586B\u8FC7\u7684\u8FD9\u4E9B\u5B57\u6BB5\uFF08\u6062\u590D\u6210\u6765\u6E90\u7684\u503C\uFF09\u3002" }
|
|
1369
|
+
},
|
|
1370
|
+
required: ["game"],
|
|
1371
|
+
kind: "other",
|
|
1372
|
+
title: (a) => `${typeof a["id"] === "string" ? "\u4FEE\u6539" : "\u6DFB\u52A0"}\u6D3B\u52A8\uFF1A${String(a["name"] ?? a["id"] ?? "")}`,
|
|
1373
|
+
execute: async (args, exec) => {
|
|
1374
|
+
const a = parse(external_exports.object({
|
|
1375
|
+
game: external_exports.string(),
|
|
1376
|
+
id: external_exports.string().nullish(),
|
|
1377
|
+
name: external_exports.string().max(60).nullish(),
|
|
1378
|
+
starts_at: external_exports.string().nullish(),
|
|
1379
|
+
ends_at: external_exports.string().nullish(),
|
|
1380
|
+
kind: external_exports.string().max(20).nullish(),
|
|
1381
|
+
description: external_exports.string().max(500).nullish(),
|
|
1382
|
+
url: external_exports.string().regex(/^https?:\/\/\S+$/, "\u53EA\u80FD\u662F http \u6216 https \u7F51\u5740").nullish(),
|
|
1383
|
+
image: external_exports.string().nullish(),
|
|
1384
|
+
todo: external_exports.array(external_exports.string().min(1).max(80)).max(30).nullish(),
|
|
1385
|
+
clear: external_exports.array(external_exports.enum(Object.keys(OWN_KEYS))).nullish()
|
|
1386
|
+
}), args);
|
|
1387
|
+
const game = known(a.game);
|
|
1388
|
+
if (a.id == null && (a.name == null || a.name.trim() === ""))
|
|
1389
|
+
throw new Error("\u65B0\u52A0\u6D3B\u52A8\u8981\u5199 name\uFF1B\u6539\u5DF2\u6709\u7684\u6D3B\u52A8\u8981\u5199 id\uFF08game_activities \u53EF\u67E5\uFF09");
|
|
1390
|
+
const when = (text, what) => {
|
|
1391
|
+
if (text == null)
|
|
1392
|
+
return void 0;
|
|
1393
|
+
const at = parseDateText(text, game.timezone, deps.now());
|
|
1394
|
+
if (at == null)
|
|
1395
|
+
throw new Error(`${what}\u300C${text}\u300D\u770B\u4E0D\u61C2\uFF1A\u5199\u6210 2026/10/25 04:00 \u6216 10/25 04:00`);
|
|
1396
|
+
return at;
|
|
1397
|
+
};
|
|
1398
|
+
const patch = {
|
|
1399
|
+
...a.name == null ? {} : { name: a.name },
|
|
1400
|
+
...a.starts_at == null ? {} : { startsAt: when(a.starts_at, "\u5F00\u59CB\u65F6\u95F4") },
|
|
1401
|
+
...a.ends_at == null ? {} : { endsAt: when(a.ends_at, "\u7ED3\u675F\u65F6\u95F4") },
|
|
1402
|
+
...a.kind == null ? {} : { kind: a.kind },
|
|
1403
|
+
...a.description == null ? {} : { description: a.description },
|
|
1404
|
+
...a.url == null ? {} : { url: a.url },
|
|
1405
|
+
...a.todo == null ? {} : { todo: a.todo }
|
|
1406
|
+
};
|
|
1407
|
+
for (const key of a.clear ?? [])
|
|
1408
|
+
patch[OWN_KEYS[key]] = null;
|
|
1409
|
+
const sessionId = exec.agent?.session.id;
|
|
1410
|
+
const activity = await deps.saveActivity(game.id, a.id ?? void 0, patch, a.image ?? void 0, sessionId);
|
|
1411
|
+
return { saved: brief(activity, game.timezone), note: a.id == null ? "\u5DF2\u52A0\u5230\u6D3B\u52A8\u65E5\u5386\uFF1B\u6E38\u620F\u9875\u548C\u65E5\u62A5\u91CC\u90FD\u80FD\u770B\u5230" : "\u5DF2\u6539\u597D" };
|
|
1412
|
+
}
|
|
1413
|
+
}),
|
|
1414
|
+
tool({
|
|
1415
|
+
name: "game_activity_remove",
|
|
1416
|
+
description: "\u53BB\u6389\u6D3B\u52A8\uFF1Awhat=mine \u53EA\u6536\u56DE\u7528\u6237\u81EA\u5DF1\u586B\u7684\u5185\u5BB9\uFF08\u540D\u5B57\u3001\u65F6\u95F4\u3001\u56FE\u7247\u7B49\u6062\u590D\u6210\u6765\u6E90\u7684\uFF1B\u53EA\u6709\u7528\u6237\u586B\u7684\u6D3B\u52A8\u4F1A\u6574\u4E2A\u53BB\u6389\uFF09\uFF1Bwhat=all \u628A\u6D3B\u52A8\u4ECE\u65E5\u5386\u53BB\u6389\uFF08\u6570\u636E\u7AD9\u8FD8\u5217\u7740\u7684\u8BDD\uFF0C\u4E0B\u6B21\u5237\u65B0\u4F1A\u518D\u51FA\u73B0\uFF09\u3002\u53EA\u5728\u7528\u6237\u8981\u6C42\u65F6\u7528\u3002",
|
|
1417
|
+
properties: {
|
|
1418
|
+
id: { type: "string", description: "\u6D3B\u52A8 id\uFF08game_activities \u53EF\u67E5\uFF09\u3002" },
|
|
1419
|
+
what: { type: "string", enum: ["mine", "all"], description: "mine\uFF1A\u53EA\u6536\u56DE\u7528\u6237\u586B\u7684\uFF1Ball\uFF1A\u6574\u4E2A\u53BB\u6389\uFF08\u9ED8\u8BA4\uFF09\u3002" }
|
|
1420
|
+
},
|
|
1421
|
+
required: ["id"],
|
|
1422
|
+
kind: "other",
|
|
1423
|
+
title: (a) => `${a["what"] === "mine" ? "\u6062\u590D" : "\u53BB\u6389"}\u6D3B\u52A8\uFF1A${String(a["id"] ?? "")}`,
|
|
1424
|
+
execute: async (args) => {
|
|
1425
|
+
const a = parse(external_exports.object({ id: external_exports.string(), what: external_exports.enum(["mine", "all"]).nullish() }), args);
|
|
1426
|
+
const activity = await deps.removeActivity(a.id, a.what ?? "all");
|
|
1427
|
+
const game = activity === void 0 ? void 0 : deps.games().find((g) => g.id === activity.game);
|
|
1428
|
+
return activity === void 0 || game === void 0 ? { removed: a.id } : { restored: brief(activity, game.timezone) };
|
|
1429
|
+
}
|
|
1430
|
+
}),
|
|
1210
1431
|
tool({
|
|
1211
1432
|
name: "game_launch",
|
|
1212
1433
|
description: "\u6E38\u620F\u6CA1\u5F00\u65F6\u542F\u52A8\u5B83\uFF1A\u7528\u73A9\u5B83\u7684\u811A\u672C\u5728\u300C\u542F\u52A8\u6E38\u620F\u300D\u91CC\u7684\u8BBE\u7F6E\uFF08\u6A21\u62DF\u5668\u91CC\u7684\u6E38\u620F\u4F1A\u5148\u542F\u52A8\u6A21\u62DF\u5668\uFF1BPC \u7248\u6253\u5F00\u8BBE\u7F6E\u597D\u7684\u7A0B\u5E8F\u6216\u542F\u52A8\u5668\uFF09\uFF0C\u5DF2\u7ECF\u5F00\u7740\u5C31\u4EC0\u4E48\u90FD\u4E0D\u505A\u3002\u6709\u811A\u672C\u6B63\u5728\u7528\u8FD9\u53F0\u6A21\u62DF\u5668\u6216\u9F20\u6807\u952E\u76D8\u65F6\u4F1A\u62D2\u7EDD\u3002\u542F\u52A8\u540E\u622A\u56FE\u786E\u8BA4\uFF1A\u5173\u6389\u516C\u544A\u548C\u66F4\u65B0\u63D0\u793A\uFF0C\u542F\u52A8\u5668\u9700\u8981\u70B9\u300C\u5F00\u59CB\u6E38\u620F\u300D\u5C31\u70B9\uFF1B\u8981\u8F93\u5165\u8D26\u53F7\u5BC6\u7801\u6216\u9A8C\u8BC1\u7801\u65F6\u505C\u4E0B\u4EA4\u7ED9\u7528\u6237\u3002",
|
|
@@ -1318,6 +1539,7 @@ var AdgGameIntel = class extends Service {
|
|
|
1318
1539
|
this.ready = (async () => {
|
|
1319
1540
|
await calendar.load();
|
|
1320
1541
|
await this.loadGames(log);
|
|
1542
|
+
await this.adoptEvidence().catch((error) => log.warn(`old screenshots not converted: ${String(error)}`));
|
|
1321
1543
|
daily.start();
|
|
1322
1544
|
})();
|
|
1323
1545
|
ctx.effect(() => () => this.daily.stop(), "adg-game-intel daily report");
|
|
@@ -1379,6 +1601,18 @@ var AdgGameIntel = class extends Service {
|
|
|
1379
1601
|
add: async (manifest, guide) => {
|
|
1380
1602
|
await this.ready;
|
|
1381
1603
|
return this.addGame(manifest, guide);
|
|
1604
|
+
},
|
|
1605
|
+
saveActivity: async (game, id, patch, image, sessionId) => {
|
|
1606
|
+
await this.ready;
|
|
1607
|
+
return this.saveActivity(game, id, patch, image === void 0 ? void 0 : await this.imageFrom(image, sessionId));
|
|
1608
|
+
},
|
|
1609
|
+
removeActivity: async (id, what) => {
|
|
1610
|
+
await this.ready;
|
|
1611
|
+
if (what === "mine")
|
|
1612
|
+
return this.resetActivity(id);
|
|
1613
|
+
if (!await this.removeActivity(id))
|
|
1614
|
+
throw new Error("\u6CA1\u6709\u8FD9\u4E2A\u6D3B\u52A8\uFF08\u53EF\u80FD\u5DF2\u7ECF\u7ED3\u675F\u88AB\u6E05\u6389\u4E86\uFF09");
|
|
1615
|
+
return void 0;
|
|
1382
1616
|
}
|
|
1383
1617
|
}))
|
|
1384
1618
|
registered.push(agent.tools.register({ ...tool2, execute: async (args, exec) => {
|
|
@@ -1430,9 +1664,13 @@ var AdgGameIntel = class extends Service {
|
|
|
1430
1664
|
return settings;
|
|
1431
1665
|
},
|
|
1432
1666
|
"games/evidence": async (params) => {
|
|
1667
|
+
await this.ready;
|
|
1433
1668
|
const id = params.activityId;
|
|
1434
|
-
|
|
1669
|
+
const screen = calendar.get(id)?.screen;
|
|
1670
|
+
if (screen?.evidence !== true)
|
|
1435
1671
|
throw new Error("\u8FD9\u4E2A\u6D3B\u52A8\u6CA1\u6709\u4FDD\u5B58\u622A\u56FE");
|
|
1672
|
+
if (screen.image !== void 0)
|
|
1673
|
+
return this.picture(screen.image);
|
|
1436
1674
|
return { mediaType: "image/png", data: (await readFile2(this.evidenceFile(id))).toString("base64") };
|
|
1437
1675
|
},
|
|
1438
1676
|
"games/image": async (params) => {
|
|
@@ -1491,9 +1729,18 @@ var AdgGameIntel = class extends Service {
|
|
|
1491
1729
|
},
|
|
1492
1730
|
"games/activity/remove": async (params) => {
|
|
1493
1731
|
await this.ready;
|
|
1494
|
-
await
|
|
1495
|
-
changed();
|
|
1732
|
+
await this.removeActivity(params.activityId);
|
|
1496
1733
|
return {};
|
|
1734
|
+
},
|
|
1735
|
+
"games/activity/save": async (params) => {
|
|
1736
|
+
await this.ready;
|
|
1737
|
+
const { game, activityId, image, todo, ...fields } = params;
|
|
1738
|
+
return this.saveActivity(game, activityId, { ...fields, ...todo === void 0 ? {} : { todo } }, image === void 0 ? void 0 : Buffer.from(image.data, "base64"));
|
|
1739
|
+
},
|
|
1740
|
+
"games/activity/reset": async (params) => {
|
|
1741
|
+
await this.ready;
|
|
1742
|
+
const activity = await this.resetActivity(params.activityId);
|
|
1743
|
+
return activity === void 0 ? {} : { activity };
|
|
1497
1744
|
}
|
|
1498
1745
|
}
|
|
1499
1746
|
});
|
|
@@ -1508,6 +1755,14 @@ var AdgGameIntel = class extends Service {
|
|
|
1508
1755
|
* gave are fetched: this is not a general-purpose proxy.
|
|
1509
1756
|
*/
|
|
1510
1757
|
async picture(url) {
|
|
1758
|
+
if (OWN_IMAGE.test(url) || SHOT_IMAGE.test(url)) {
|
|
1759
|
+
const [kind, file] = url.split(":");
|
|
1760
|
+
const mediaType2 = IMAGE_TYPES.find(([ext2]) => file.endsWith(`.${ext2}`))[1];
|
|
1761
|
+
const bytes2 = await readFile2(join2(this.imageDir(kind), file)).catch(() => {
|
|
1762
|
+
throw new Error("\u8FD9\u5F20\u56FE\u7247\u5DF2\u7ECF\u4E0D\u5728\u4E86");
|
|
1763
|
+
});
|
|
1764
|
+
return { mediaType: mediaType2, data: bytes2.toString("base64") };
|
|
1765
|
+
}
|
|
1511
1766
|
if (!this.calendar.pictures().has(url) && !this.games.some((g) => g.manifest.art === url))
|
|
1512
1767
|
throw new Error("\u8FD9\u5F20\u56FE\u7247\u4E0D\u662F\u6570\u636E\u7AD9\u6216\u6E38\u620F\u5305\u7ED9\u7684\u5730\u5740");
|
|
1513
1768
|
const name = createHash("sha256").update(url).digest("hex").slice(0, 32);
|
|
@@ -1584,6 +1839,96 @@ var AdgGameIntel = class extends Service {
|
|
|
1584
1839
|
await this.loadGames(this.log);
|
|
1585
1840
|
this.changed(gameId);
|
|
1586
1841
|
}
|
|
1842
|
+
// ── the user's own events ──
|
|
1843
|
+
/**
|
|
1844
|
+
* Add an event of the user's own, or write their word on one (see
|
|
1845
|
+
* `Calendar.saveOwn`); `image`: a new picture, kept under
|
|
1846
|
+
* `<data>/games/images/own/`. @throws Error with what is wrong.
|
|
1847
|
+
*/
|
|
1848
|
+
async saveActivity(gameId, activityId, patch, image) {
|
|
1849
|
+
const { manifest } = this.game(gameId);
|
|
1850
|
+
if (activityId !== void 0 && this.calendar.get(activityId)?.game !== manifest.id)
|
|
1851
|
+
throw new Error(`${manifest.name}\u6CA1\u6709\u6D3B\u52A8\u300C${activityId}\u300D\uFF08\u53EF\u80FD\u5DF2\u7ECF\u7ED3\u675F\u88AB\u6E05\u6389\u4E86\uFF1Bgame_activities \u53EF\u67E5\uFF09`);
|
|
1852
|
+
const cover = image === void 0 ? patch.cover : await this.keepImage(image);
|
|
1853
|
+
const activity = await this.calendar.saveOwn({ game: manifest.id, id: activityId }, { ...patch, ...cover === void 0 ? {} : { cover } }, this.clock.now(), manifest.timezone);
|
|
1854
|
+
await this.sweepImages();
|
|
1855
|
+
this.changed(manifest.id);
|
|
1856
|
+
if (activity === void 0)
|
|
1857
|
+
throw new Error("\u4EC0\u4E48\u90FD\u6CA1\u7559\u4E0B\uFF1A\u8FD9\u4E2A\u6D3B\u52A8\u53EA\u6709\u4F60\u586B\u7684\u5185\u5BB9\uFF0C\u6E05\u7A7A\u540E\u5C31\u4ECE\u65E5\u5386\u53BB\u6389\u4E86");
|
|
1858
|
+
return activity;
|
|
1859
|
+
}
|
|
1860
|
+
/** Take back what the user wrote on an event. @returns it as it is now; undefined when it went. */
|
|
1861
|
+
async resetActivity(activityId) {
|
|
1862
|
+
const before = this.calendar.get(activityId);
|
|
1863
|
+
if (before === void 0)
|
|
1864
|
+
throw new Error("\u6CA1\u6709\u8FD9\u4E2A\u6D3B\u52A8\uFF08\u53EF\u80FD\u5DF2\u7ECF\u7ED3\u675F\u88AB\u6E05\u6389\u4E86\uFF09");
|
|
1865
|
+
const timezone = this.games.find((g) => g.manifest.id === before.game)?.manifest.timezone ?? "Asia/Shanghai";
|
|
1866
|
+
const activity = await this.calendar.resetOwn(activityId, timezone);
|
|
1867
|
+
await this.sweepImages();
|
|
1868
|
+
this.changed(before.game);
|
|
1869
|
+
return activity;
|
|
1870
|
+
}
|
|
1871
|
+
async removeActivity(activityId) {
|
|
1872
|
+
const removed = await this.calendar.remove(activityId);
|
|
1873
|
+
await this.sweepImages();
|
|
1874
|
+
this.changed();
|
|
1875
|
+
return removed;
|
|
1876
|
+
}
|
|
1877
|
+
/**
|
|
1878
|
+
* A picture for an event, as the agent names it: an http(s) address (fetched
|
|
1879
|
+
* now and kept, so it stays when the page goes), a file on this computer
|
|
1880
|
+
* (a path relative to the workspace is fine), or `screenshot`, the last
|
|
1881
|
+
* screenshot of this conversation.
|
|
1882
|
+
*/
|
|
1883
|
+
async imageFrom(source, sessionId) {
|
|
1884
|
+
const from = source.trim();
|
|
1885
|
+
if (from === "screenshot") {
|
|
1886
|
+
const shot = sessionId === void 0 ? void 0 : this.ctx.get("adgIntervene")?.lastShot(sessionId);
|
|
1887
|
+
if (shot === void 0)
|
|
1888
|
+
throw new Error("\u8FD9\u4E2A\u5BF9\u8BDD\u8FD8\u6CA1\u6709\u622A\u56FE\uFF1A\u5148\u7528 screen_capture \u622A\u4E00\u5F20");
|
|
1889
|
+
return shot;
|
|
1890
|
+
}
|
|
1891
|
+
if (/^https?:\/\//i.test(from)) {
|
|
1892
|
+
const response = await fetch(from, { signal: AbortSignal.timeout(2e4), headers: { accept: "image/*", "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) MultiGameAssistant" } });
|
|
1893
|
+
if (!response.ok)
|
|
1894
|
+
throw new Error(`\u56FE\u7247\u8BFB\u4E0D\u5230\uFF1AHTTP ${response.status}`);
|
|
1895
|
+
return Buffer.from(await response.arrayBuffer());
|
|
1896
|
+
}
|
|
1897
|
+
const path = from.replace(/^file:\/\/\/?/i, "");
|
|
1898
|
+
const workspace = this.ctx.get("adgGateway")?.workspaceDir();
|
|
1899
|
+
const full = isAbsolute(path) || workspace === void 0 ? path : resolve(workspace, path);
|
|
1900
|
+
return readFile2(full).catch(() => {
|
|
1901
|
+
throw new Error(`\u8BFB\u4E0D\u5230\u56FE\u7247\u6587\u4EF6\uFF1A${full}`);
|
|
1902
|
+
});
|
|
1903
|
+
}
|
|
1904
|
+
/**
|
|
1905
|
+
* Keep a picture the user added (`own`) or a screenshot an event was read
|
|
1906
|
+
* from (`shot`), named by its content. @returns its address (`own:<hash>.<ext>`).
|
|
1907
|
+
*/
|
|
1908
|
+
async keepImage(bytes, kind = "own") {
|
|
1909
|
+
if (kind === "own" && bytes.length > MAX_IMAGE_BYTES)
|
|
1910
|
+
throw new Error("\u56FE\u7247\u592A\u5927\uFF08\u6700\u591A 8 MB\uFF09");
|
|
1911
|
+
const ext = imageType(bytes);
|
|
1912
|
+
if (ext === void 0)
|
|
1913
|
+
throw new Error("\u4E0D\u662F\u652F\u6301\u7684\u56FE\u7247\uFF08png\u3001jpg\u3001gif\u3001webp\u3001avif\uFF09");
|
|
1914
|
+
const file = `${createHash("sha256").update(bytes).digest("hex").slice(0, 32)}.${ext}`;
|
|
1915
|
+
const dir = this.imageDir(kind);
|
|
1916
|
+
await mkdir2(dir, { recursive: true });
|
|
1917
|
+
await writeFile(join2(dir, file), bytes);
|
|
1918
|
+
return `${kind}:${file}`;
|
|
1919
|
+
}
|
|
1920
|
+
imageDir(kind) {
|
|
1921
|
+
return join2(this.dir, "images", kind === "own" ? "own" : "shots");
|
|
1922
|
+
}
|
|
1923
|
+
/** Pictures the user added, and screenshots, that no event has any more. */
|
|
1924
|
+
async sweepImages() {
|
|
1925
|
+
for (const [kind, used] of [["own", this.calendar.ownImages()], ["shot", this.calendar.shotImages()]]) {
|
|
1926
|
+
const dir = this.imageDir(kind);
|
|
1927
|
+
const files = await readdir(dir).catch(() => []);
|
|
1928
|
+
await Promise.all(files.filter((f) => !used.has(`${kind}:${f}`)).map((f) => rm(join2(dir, f), { force: true }).catch(() => {
|
|
1929
|
+
})));
|
|
1930
|
+
}
|
|
1931
|
+
}
|
|
1587
1932
|
/**
|
|
1588
1933
|
* The scripts that play each game: the ones its pack lists, and installed
|
|
1589
1934
|
* scripts whose id, name, repository or pack names it (script-match.ts),
|
|
@@ -1715,6 +2060,7 @@ var AdgGameIntel = class extends Service {
|
|
|
1715
2060
|
results.push({ game: manifest.id, ok: failures.length === 0 || count > 0, count, ...failures.length === 0 ? {} : { detail: failures.join("\uFF1B") } });
|
|
1716
2061
|
this.changed(manifest.id);
|
|
1717
2062
|
}
|
|
2063
|
+
await this.sweepImages();
|
|
1718
2064
|
return results;
|
|
1719
2065
|
}
|
|
1720
2066
|
// ── what the agent read ──
|
|
@@ -1731,21 +2077,38 @@ var AdgGameIntel = class extends Service {
|
|
|
1731
2077
|
return { ...event, source: { id: link.id, name: link.name } };
|
|
1732
2078
|
return host === void 0 ? event : { ...event, source: { id: "agent", name: `${host}\uFF08agent \u67E5\u5230\uFF09` } };
|
|
1733
2079
|
});
|
|
1734
|
-
const
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
sessionId,
|
|
1738
|
-
...shot === void 0 ? {} : {
|
|
1739
|
-
evidence: async (activity) => {
|
|
1740
|
-
await mkdir2(join2(this.dir, "evidence"), { recursive: true });
|
|
1741
|
-
await writeFile(this.evidenceFile(activity.id), shot);
|
|
1742
|
-
return true;
|
|
1743
|
-
}
|
|
1744
|
-
}
|
|
2080
|
+
const kept = shot === void 0 ? void 0 : await this.keepImage(shot, "shot").catch((error) => {
|
|
2081
|
+
this.log.warn(`screenshot not kept: ${error instanceof Error ? error.message : String(error)}`);
|
|
2082
|
+
return void 0;
|
|
1745
2083
|
});
|
|
2084
|
+
const written = await this.calendar.applyRead(gameId, from, credited, { now: this.clock.now(), timeZone: manifest.timezone, sessionId, shot: kept });
|
|
2085
|
+
await this.sweepImages();
|
|
1746
2086
|
this.changed(gameId);
|
|
1747
2087
|
return written;
|
|
1748
2088
|
}
|
|
2089
|
+
/**
|
|
2090
|
+
* Screenshots kept before they were pictures: one file per event under
|
|
2091
|
+
* `evidence/`. Each becomes a `shot:` picture (and its event's background).
|
|
2092
|
+
*/
|
|
2093
|
+
async adoptEvidence() {
|
|
2094
|
+
const shots = /* @__PURE__ */ new Map();
|
|
2095
|
+
for (const a of this.calendar.list()) {
|
|
2096
|
+
if (a.screen?.evidence !== true || a.screen.image !== void 0)
|
|
2097
|
+
continue;
|
|
2098
|
+
const file = this.evidenceFile(a.id);
|
|
2099
|
+
const bytes = await readFile2(file).catch(() => void 0);
|
|
2100
|
+
if (bytes === void 0)
|
|
2101
|
+
continue;
|
|
2102
|
+
const kept = await this.keepImage(bytes, "shot").catch(() => void 0);
|
|
2103
|
+
if (kept === void 0)
|
|
2104
|
+
continue;
|
|
2105
|
+
shots.set(a.id, kept);
|
|
2106
|
+
await rm(file, { force: true }).catch(() => {
|
|
2107
|
+
});
|
|
2108
|
+
}
|
|
2109
|
+
await this.calendar.adoptShots(shots, (game) => this.games.find((g) => g.manifest.id === game)?.manifest.timezone ?? "Asia/Shanghai");
|
|
2110
|
+
}
|
|
2111
|
+
/** Where a screenshot was kept before `shot:` pictures. */
|
|
1749
2112
|
evidenceFile(activityId) {
|
|
1750
2113
|
return join2(this.dir, "evidence", `${activityId.replace(/[^\p{L}\p{N}-]+/gu, "_")}.png`);
|
|
1751
2114
|
}
|
|
@@ -1945,6 +2308,20 @@ ${guide.trim()}
|
|
|
1945
2308
|
return { channels, text };
|
|
1946
2309
|
}
|
|
1947
2310
|
};
|
|
2311
|
+
function imageType(bytes) {
|
|
2312
|
+
const ascii = (from, to) => String.fromCharCode(...bytes.subarray(from, to));
|
|
2313
|
+
if (bytes[0] === 137 && ascii(1, 4) === "PNG")
|
|
2314
|
+
return "png";
|
|
2315
|
+
if (bytes[0] === 255 && bytes[1] === 216 && bytes[2] === 255)
|
|
2316
|
+
return "jpg";
|
|
2317
|
+
if (ascii(0, 4) === "GIF8")
|
|
2318
|
+
return "gif";
|
|
2319
|
+
if (ascii(0, 4) === "RIFF" && ascii(8, 12) === "WEBP")
|
|
2320
|
+
return "webp";
|
|
2321
|
+
if (ascii(4, 8) === "ftyp" && /^avi[fs]$/.test(ascii(8, 12)))
|
|
2322
|
+
return "avif";
|
|
2323
|
+
return void 0;
|
|
2324
|
+
}
|
|
1948
2325
|
function hostName(url) {
|
|
1949
2326
|
try {
|
|
1950
2327
|
return new URL(url).hostname.replace(/^www\./, "");
|
|
@@ -1968,11 +2345,13 @@ export {
|
|
|
1968
2345
|
DEFAULT_SETTINGS,
|
|
1969
2346
|
DailyReport,
|
|
1970
2347
|
GAME_ROLE,
|
|
2348
|
+
OWN_FIELDS,
|
|
1971
2349
|
buildReport,
|
|
1972
2350
|
daysLeft,
|
|
1973
2351
|
lib_default as default,
|
|
1974
2352
|
gameTools,
|
|
1975
2353
|
idKey,
|
|
2354
|
+
imageType,
|
|
1976
2355
|
leftText,
|
|
1977
2356
|
localDay,
|
|
1978
2357
|
nameKey,
|
package/lib/gateway.js
CHANGED
|
@@ -17,9 +17,9 @@ import {
|
|
|
17
17
|
copyLabel,
|
|
18
18
|
lib_default,
|
|
19
19
|
streamFacts
|
|
20
|
-
} from "./chunk-
|
|
20
|
+
} from "./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
|
AGENT_PRESET,
|
package/lib/guard.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
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
|
GUARD_CAPABILITY
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-HPQCV6WO.js";
|
|
5
5
|
import "./chunk-2UFLGPDY.js";
|
|
6
6
|
|
|
7
7
|
// packages/guard/lib/index.js
|
package/lib/intervene.js
CHANGED
|
@@ -2,8 +2,8 @@ import { createRequire as __adgCreateRequire } from 'node:module'; import { dirn
|
|
|
2
2
|
import {
|
|
3
3
|
finalText,
|
|
4
4
|
sessionConversations
|
|
5
|
-
} from "./chunk-
|
|
6
|
-
import "./chunk-
|
|
5
|
+
} from "./chunk-BNGDT7YT.js";
|
|
6
|
+
import "./chunk-ZQ6KFVEO.js";
|
|
7
7
|
import {
|
|
8
8
|
writeFileAtomic
|
|
9
9
|
} from "./chunk-CCAB6XXZ.js";
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
INTERVENE_CAPABILITY,
|
|
12
12
|
UPDATE_RULE,
|
|
13
13
|
external_exports
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-HPQCV6WO.js";
|
|
15
15
|
import "./chunk-2UFLGPDY.js";
|
|
16
16
|
|
|
17
17
|
// packages/intervene/lib/index.js
|