@myclaw163/clawclaw-cli 0.6.74 → 0.6.77
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 +387 -377
- package/bin/clawclaw-cli.mjs +3 -3
- package/package.json +48 -48
- package/personas//347/220/206/346/231/272/346/270/251/345/222/214.md +23 -23
- package/personas//350/200/201/350/260/213/346/267/261/347/256/227.md +22 -22
- package/personas//350/257/232/346/201/263/347/233/264/347/216/207.md +22 -22
- package/personas//350/275/273/346/235/276/346/264/273/346/263/274.md +22 -22
- package/personas//351/207/216/346/200/247/345/217/233/351/200/206.md +23 -23
- package/scripts/check-skill-command-surface.mjs +116 -116
- package/scripts/find-hide-spots.py +157 -157
- package/scripts/postinstall.mjs +20 -20
- package/scripts/sync-bundled-skill.mjs +254 -245
- package/scripts/sync-bundled-skill.test.mjs +152 -152
- package/skills/clawclaw/SKILL.md +248 -246
- package/skills/clawclaw/references/CHATTERBOX.md +141 -141
- package/skills/clawclaw/references/COMMANDS.md +160 -155
- package/skills/clawclaw/references/GAME-MECHANICS.md +188 -188
- package/skills/clawclaw/references/HUB.md +48 -48
- package/skills/clawclaw/references/KNOWLEDGE.md +42 -42
- package/skills/clawclaw/references/STRATEGIES.md +59 -59
- package/skills/clawclaw/references/STREAM.md +93 -93
- package/skills/clawclaw/references/TACTICS.md +65 -65
- package/src/assets/clawclaw-ascii-map.txt +40 -40
- package/src/cli.ts +112 -110
- package/src/commands/_schema.ts +124 -124
- package/src/commands/account.ts +209 -209
- package/src/commands/data.test.ts +33 -0
- package/src/commands/data.ts +22 -0
- package/src/commands/do.test.ts +84 -84
- package/src/commands/do.ts +130 -130
- package/src/commands/events.test.ts +100 -71
- package/src/commands/events.ts +250 -221
- package/src/commands/game-map.test.ts +28 -28
- package/src/commands/game-start-plan.test.ts +84 -84
- package/src/commands/game.ts +1113 -1113
- package/src/commands/history-player.test.ts +102 -102
- package/src/commands/history.ts +573 -573
- package/src/commands/hub.test.ts +96 -96
- package/src/commands/hub.ts +234 -234
- package/src/commands/knowledge.test.ts +13 -13
- package/src/commands/knowledge.ts +139 -139
- package/src/commands/load.test.ts +51 -51
- package/src/commands/load.ts +13 -13
- package/src/commands/meeting-history.test.ts +106 -106
- package/src/commands/memory.ts +40 -40
- package/src/commands/peek.ts +45 -45
- package/src/commands/persona.ts +57 -57
- package/src/commands/setup/codex.ts +266 -266
- package/src/commands/skill.ts +128 -128
- package/src/commands/state.ts +46 -46
- package/src/commands/strategy.test.ts +153 -145
- package/src/commands/strategy.ts +183 -181
- package/src/commands/tts.ts +128 -128
- package/src/commands/upgrade.test.ts +82 -82
- package/src/commands/upgrade.ts +148 -148
- package/src/commands/watch.test.ts +999 -999
- package/src/commands/watch.ts +660 -660
- package/src/lib/auth.test.ts +86 -74
- package/src/lib/auth.ts +223 -186
- package/src/lib/command-meta.ts +37 -37
- package/src/lib/game-client.ts +403 -403
- package/src/lib/game-context.ts +92 -92
- package/src/lib/http-keepalive.ts +15 -15
- package/src/lib/http-transport.test.ts +42 -42
- package/src/lib/http-transport.ts +113 -113
- package/src/lib/hub-client.test.ts +56 -56
- package/src/lib/hub-client.ts +88 -88
- package/src/lib/hub-install.test.ts +98 -98
- package/src/lib/hub-install.ts +160 -121
- package/src/lib/hub-reminder.ts +78 -75
- package/src/lib/hub-unzip.test.ts +69 -69
- package/src/lib/hub-unzip.ts +62 -62
- package/src/lib/init-command.test.ts +75 -75
- package/src/lib/init-command.ts +130 -120
- package/src/lib/knowledge-store.test.ts +170 -170
- package/src/lib/knowledge-store.ts +369 -369
- package/src/lib/load-context.test.ts +52 -52
- package/src/lib/load-context.ts +52 -52
- package/src/lib/match-state.test.ts +134 -134
- package/src/lib/match-state.ts +94 -94
- package/src/lib/netease-tts.ts +83 -83
- package/src/lib/normalize.ts +42 -42
- package/src/lib/persona.test.ts +41 -41
- package/src/lib/persona.ts +72 -72
- package/src/lib/server-registry.ts +152 -152
- package/src/lib/skill-version.test.ts +48 -48
- package/src/lib/skill-version.ts +19 -19
- package/src/lib/strategy-export.test.ts +240 -232
- package/src/lib/strategy-export.ts +247 -242
- package/src/lib/tts-keys.ts +7 -7
- package/src/lib/tts-speech.test.ts +63 -63
- package/src/lib/tts-speech.ts +76 -76
- package/src/lib/user-data.test.ts +96 -0
- package/src/lib/user-data.ts +400 -0
- package/src/lib/workspace-argv.test.ts +49 -49
- package/src/lib/workspace-argv.ts +44 -44
- package/src/perception/player-history-store.test.ts +87 -87
- package/src/perception/player-history-store.ts +194 -194
- package/src/pipeline/event-format.test.ts +243 -243
- package/src/pipeline/event-format.ts +501 -501
- package/src/pipeline/event-hints.ts +195 -195
- package/src/pipeline/event-store.test.ts +28 -28
- package/src/pipeline/event-store.ts +193 -193
- package/src/pipeline/pipeline.ts +35 -35
- package/src/pipeline/player-projection.test.ts +168 -119
- package/src/pipeline/player-projection.ts +370 -380
- package/src/runtime/auto-upgrade.test.ts +66 -66
- package/src/runtime/auto-upgrade.ts +31 -31
- package/src/runtime/event-daemon.test.ts +209 -209
- package/src/runtime/event-daemon.ts +519 -519
- package/src/runtime/owner-control.ts +150 -150
- package/src/runtime/raw-ws-log.test.ts +33 -33
- package/src/runtime/raw-ws-log.ts +32 -32
- package/src/runtime/runtime-logger.ts +107 -107
- package/src/runtime/ws-client.test.ts +125 -125
- package/src/runtime/ws-client.ts +287 -287
- package/src/sdk/action.ts +166 -166
- package/src/sdk/index.ts +110 -110
- package/src/sdk/types.ts +161 -161
- package/src/strategies/avoid-lone.ts +12 -12
- package/src/strategies/avoid-players.knowledge.md +19 -19
- package/src/strategies/avoid-players.ts +16 -16
- package/src/strategies/corpse-patrol.ts +23 -23
- package/src/strategies/crab-sabotage.ts +22 -22
- package/src/strategies/custom-module.test.ts +270 -270
- package/src/strategies/find-player.ts +17 -17
- package/src/strategies/game-utils.test.ts +242 -242
- package/src/strategies/game-utils.ts +846 -846
- package/src/strategies/goals/anchor-linger.ts +77 -77
- package/src/strategies/goals/avoid-lone-top.ts +168 -168
- package/src/strategies/goals/avoid-players-top.test.ts +83 -83
- package/src/strategies/goals/avoid-players-top.ts +121 -121
- package/src/strategies/goals/conversation-goal.ts +51 -51
- package/src/strategies/goals/corpse-patrol-top.ts +113 -113
- package/src/strategies/goals/crab-octopus-reflexes.ts +101 -101
- package/src/strategies/goals/crab-sabotage-top.ts +197 -197
- package/src/strategies/goals/emergency-hunt-goal.ts +28 -28
- package/src/strategies/goals/find-player-top.ts +93 -93
- package/src/strategies/goals/flee-players-goal.ts +53 -53
- package/src/strategies/goals/follow-companion-goal.ts +106 -106
- package/src/strategies/goals/goal-manager.ts +41 -41
- package/src/strategies/goals/goal-root-strategy.ts +49 -49
- package/src/strategies/goals/goal.ts +28 -28
- package/src/strategies/goals/hide-top.ts +197 -197
- package/src/strategies/goals/keep-away-goal.ts +221 -221
- package/src/strategies/goals/kill-frenzy-top.ts +80 -80
- package/src/strategies/goals/kill-lone-top.ts +160 -160
- package/src/strategies/goals/kill-target-goal.ts +59 -59
- package/src/strategies/goals/kill-target-top.ts +109 -109
- package/src/strategies/goals/leaf-goal.ts +27 -27
- package/src/strategies/goals/linger-corpse-goal.ts +35 -35
- package/src/strategies/goals/lone-kill-core.ts +82 -82
- package/src/strategies/goals/lone-kill-goal.ts +24 -24
- package/src/strategies/goals/lone-kill-task-top.test.ts +85 -85
- package/src/strategies/goals/lone-kill-task-top.ts +133 -133
- package/src/strategies/goals/move-room-goal.ts +60 -60
- package/src/strategies/goals/normal-shrimp-top.test.ts +80 -80
- package/src/strategies/goals/normal-shrimp-top.ts +242 -242
- package/src/strategies/goals/paradise-fish-top.test.ts +126 -126
- package/src/strategies/goals/paradise-fish-top.ts +224 -224
- package/src/strategies/goals/patrol-top.ts +57 -57
- package/src/strategies/goals/report-patrol-top.ts +80 -80
- package/src/strategies/goals/safe-task-goal.ts +102 -102
- package/src/strategies/goals/social-task-top.ts +161 -161
- package/src/strategies/goals/task-kill-report-top.ts +163 -163
- package/src/strategies/goals/task-only-top.ts +57 -57
- package/src/strategies/goals/task-or-patrol-goal.ts +41 -41
- package/src/strategies/goals/task-report-top.ts +57 -57
- package/src/strategies/goals/wander-task-goal.ts +33 -33
- package/src/strategies/goals/warrior-shrimp-top.test.ts +87 -87
- package/src/strategies/goals/warrior-shrimp-top.ts +267 -267
- package/src/strategies/greeting.ts +53 -53
- package/src/strategies/hide-spots.ts +59 -59
- package/src/strategies/hide.ts +24 -24
- package/src/strategies/kill-frenzy.ts +13 -13
- package/src/strategies/kill-lone.knowledge.md +17 -17
- package/src/strategies/kill-lone.ts +14 -14
- package/src/strategies/kill-target.ts +19 -19
- package/src/strategies/loader.test.ts +678 -678
- package/src/strategies/loader.ts +181 -179
- package/src/strategies/lone-kill-task.ts +22 -22
- package/src/strategies/meeting-gate.test.ts +59 -59
- package/src/strategies/meeting-gate.ts +23 -23
- package/src/strategies/move-room.ts +16 -16
- package/src/strategies/new-events-backfill.ts +98 -98
- package/src/strategies/off-route-points.ts +105 -105
- package/src/strategies/paradise-fish.knowledge.md +19 -19
- package/src/strategies/paradise-fish.ts +26 -26
- package/src/strategies/pathfind/distance-field.ts +150 -150
- package/src/strategies/pathfind/escape-planner.test.ts +197 -197
- package/src/strategies/pathfind/escape-planner.ts +355 -355
- package/src/strategies/pathfind/walkable-grid.ts +117 -117
- package/src/strategies/patrol.ts +12 -12
- package/src/strategies/player-targets.ts +13 -13
- package/src/strategies/report-patrol.ts +12 -12
- package/src/strategies/shrimp-memory.knowledge.md +19 -19
- package/src/strategies/shrimp-memory.ts +26 -26
- package/src/strategies/social-task.test.ts +28 -28
- package/src/strategies/social-task.ts +50 -50
- package/src/strategies/spawn.ts +82 -82
- package/src/strategies/speech-module.ts +123 -123
- package/src/strategies/strategy-loop.test.ts +15 -15
- package/src/strategies/strategy-loop.ts +776 -776
- package/src/strategies/task-kill-report.ts +18 -18
- package/src/strategies/task-only.ts +12 -12
- package/src/strategies/task-report.ts +23 -23
- package/src/strategies/types.ts +109 -109
- package/src/strategies/warrior-memory.knowledge.md +21 -21
- package/src/strategies/warrior-memory.ts +17 -17
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
import type { StrategyEntry } from './types.js';
|
|
2
|
-
import { GoalRootStrategy } from './goals/goal-root-strategy.js';
|
|
3
|
-
import { TaskKillReportTop } from './goals/task-kill-report-top.js';
|
|
4
|
-
|
|
5
|
-
export const strategy: StrategyEntry = {
|
|
6
|
-
id: 'task-kill-report',
|
|
7
|
-
name: '任务刺客',
|
|
8
|
-
description: '需传入嫌疑目标(座位号或名字,可多人)。看到目标且冷却好,50内就出刀,否则追上去;冷却中贴身跟随。目标不在视野时,遇到尸体就报告;没尸体就做普通任务。',
|
|
9
|
-
create(args?: string[]) {
|
|
10
|
-
if (!args || args.length === 0) {
|
|
11
|
-
throw new Error('task-kill-report strategy requires suspected target seat numbers or player names as arguments.');
|
|
12
|
-
}
|
|
13
|
-
const targets = [...args];
|
|
14
|
-
return new GoalRootStrategy('task-kill-report', () => new TaskKillReportTop(targets), {
|
|
15
|
-
resetOnMeetingResume: false,
|
|
16
|
-
});
|
|
17
|
-
},
|
|
18
|
-
};
|
|
1
|
+
import type { StrategyEntry } from './types.js';
|
|
2
|
+
import { GoalRootStrategy } from './goals/goal-root-strategy.js';
|
|
3
|
+
import { TaskKillReportTop } from './goals/task-kill-report-top.js';
|
|
4
|
+
|
|
5
|
+
export const strategy: StrategyEntry = {
|
|
6
|
+
id: 'task-kill-report',
|
|
7
|
+
name: '任务刺客',
|
|
8
|
+
description: '需传入嫌疑目标(座位号或名字,可多人)。看到目标且冷却好,50内就出刀,否则追上去;冷却中贴身跟随。目标不在视野时,遇到尸体就报告;没尸体就做普通任务。',
|
|
9
|
+
create(args?: string[]) {
|
|
10
|
+
if (!args || args.length === 0) {
|
|
11
|
+
throw new Error('task-kill-report strategy requires suspected target seat numbers or player names as arguments.');
|
|
12
|
+
}
|
|
13
|
+
const targets = [...args];
|
|
14
|
+
return new GoalRootStrategy('task-kill-report', () => new TaskKillReportTop(targets), {
|
|
15
|
+
resetOnMeetingResume: false,
|
|
16
|
+
});
|
|
17
|
+
},
|
|
18
|
+
};
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import type { StrategyEntry } from './types.js';
|
|
2
|
-
import { GoalRootStrategy } from './goals/goal-root-strategy.js';
|
|
3
|
-
import { TaskOnlyTop } from './goals/task-only-top.js';
|
|
4
|
-
|
|
5
|
-
export const strategy: StrategyEntry = {
|
|
6
|
-
id: 'task-only',
|
|
7
|
-
name: '纯任务',
|
|
8
|
-
description: '专心做任务。紧急任务出现时优先处理,其次按顺序完成普通任务,如果是蟹,则蟹的伪装任务也会做。没有尸体报告和战斗行为。',
|
|
9
|
-
create() {
|
|
10
|
-
return new GoalRootStrategy('task-only', () => new TaskOnlyTop(), { resetOnMeetingResume: false });
|
|
11
|
-
},
|
|
12
|
-
};
|
|
1
|
+
import type { StrategyEntry } from './types.js';
|
|
2
|
+
import { GoalRootStrategy } from './goals/goal-root-strategy.js';
|
|
3
|
+
import { TaskOnlyTop } from './goals/task-only-top.js';
|
|
4
|
+
|
|
5
|
+
export const strategy: StrategyEntry = {
|
|
6
|
+
id: 'task-only',
|
|
7
|
+
name: '纯任务',
|
|
8
|
+
description: '专心做任务。紧急任务出现时优先处理,其次按顺序完成普通任务,如果是蟹,则蟹的伪装任务也会做。没有尸体报告和战斗行为。',
|
|
9
|
+
create() {
|
|
10
|
+
return new GoalRootStrategy('task-only', () => new TaskOnlyTop(), { resetOnMeetingResume: false });
|
|
11
|
+
},
|
|
12
|
+
};
|
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
import type { StrategyEntry } from './types.js';
|
|
2
|
-
import { GoalRootStrategy } from './goals/goal-root-strategy.js';
|
|
3
|
-
import { TaskReportTop } from './goals/task-report-top.js';
|
|
4
|
-
import { parseGreetingArgs } from './greeting.js';
|
|
5
|
-
|
|
6
|
-
class TaskReportStrategy extends GoalRootStrategy {
|
|
7
|
-
constructor(private readonly greetingPhrases: string[]) {
|
|
8
|
-
super('task-report', () => new TaskReportTop(greetingPhrases), { resetOnMeetingResume: false });
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
speechWarmupTexts(): string[] {
|
|
12
|
-
return this.greetingPhrases;
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export const strategy: StrategyEntry = {
|
|
17
|
-
id: 'task-report',
|
|
18
|
-
name: '尽责虾',
|
|
19
|
-
description: '遇尸体最优先:达到报告距离立刻报告,没达到距离就靠近准备报告。紧急任务出现时优先处理,其次按顺序完成普通任务。传入打招呼话术时,视野内出现人就随机发送一条,之后120秒内不再发言。(普通虾默认;进阶版见 shrimp-memory)参数:可选:1~3 条打招呼话术。',
|
|
20
|
-
create(args?: string[]) {
|
|
21
|
-
return new TaskReportStrategy(parseGreetingArgs(args, 'task-report'));
|
|
22
|
-
},
|
|
23
|
-
};
|
|
1
|
+
import type { StrategyEntry } from './types.js';
|
|
2
|
+
import { GoalRootStrategy } from './goals/goal-root-strategy.js';
|
|
3
|
+
import { TaskReportTop } from './goals/task-report-top.js';
|
|
4
|
+
import { parseGreetingArgs } from './greeting.js';
|
|
5
|
+
|
|
6
|
+
class TaskReportStrategy extends GoalRootStrategy {
|
|
7
|
+
constructor(private readonly greetingPhrases: string[]) {
|
|
8
|
+
super('task-report', () => new TaskReportTop(greetingPhrases), { resetOnMeetingResume: false });
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
speechWarmupTexts(): string[] {
|
|
12
|
+
return this.greetingPhrases;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export const strategy: StrategyEntry = {
|
|
17
|
+
id: 'task-report',
|
|
18
|
+
name: '尽责虾',
|
|
19
|
+
description: '遇尸体最优先:达到报告距离立刻报告,没达到距离就靠近准备报告。紧急任务出现时优先处理,其次按顺序完成普通任务。传入打招呼话术时,视野内出现人就随机发送一条,之后120秒内不再发言。(普通虾默认;进阶版见 shrimp-memory)参数:可选:1~3 条打招呼话术。',
|
|
20
|
+
create(args?: string[]) {
|
|
21
|
+
return new TaskReportStrategy(parseGreetingArgs(args, 'task-report'));
|
|
22
|
+
},
|
|
23
|
+
};
|
package/src/strategies/types.ts
CHANGED
|
@@ -1,109 +1,109 @@
|
|
|
1
|
-
import type { GameState, TaskInfo, TaskLocation, EmergencyInfo, CorpseInfo } from '../sdk/types.js';
|
|
2
|
-
import type { Action } from '../sdk/action.js';
|
|
3
|
-
import type { KnowledgeView } from '../lib/knowledge-store.js';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Minimal interface for custom modules (built-in and strategy-registered).
|
|
7
|
-
* Strategy authors implement this to inject custom analysis modules
|
|
8
|
-
* (e.g. CoMovementTracker, VisibilityTracker, SpeechAnalyzer) via ctx.customModules.
|
|
9
|
-
* The strategy-loop manages lifecycle through these hooks:
|
|
10
|
-
* - processEvents: called every tick with new events, tick number, and current game state
|
|
11
|
-
* - afterDecide: called after strategy.decide(), can filter/modify decisions (chained by registration order)
|
|
12
|
-
* - onMeetingResume: called after each meeting (decay or full reset)
|
|
13
|
-
* - onMapLoaded: called when fresh map data is available
|
|
14
|
-
*/
|
|
15
|
-
export interface CustomModule {
|
|
16
|
-
processEvents(events: any[], tick: number, state: GameState): void;
|
|
17
|
-
afterDecide?(decisions: BehaviorDecision[], state: GameState, ctx: StrategyContext): BehaviorDecision[];
|
|
18
|
-
onMeetingResume?(): void;
|
|
19
|
-
onMapLoaded?(rawRooms: any[]): void;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export interface BehaviorDecision {
|
|
23
|
-
action: Action;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export interface CorpseTarget {
|
|
27
|
-
x: number;
|
|
28
|
-
y: number;
|
|
29
|
-
name?: string;
|
|
30
|
-
room?: string;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export interface Strategy {
|
|
34
|
-
readonly name: string;
|
|
35
|
-
decide(state: GameState, ctx: StrategyContext): BehaviorDecision[];
|
|
36
|
-
/** Called when wandering resumes after a meeting pause. */
|
|
37
|
-
onMeetingResume?(): void;
|
|
38
|
-
/** Called by strategy-loop after getRoleInfo() resolves, allowing late config update. */
|
|
39
|
-
updateRole?(role: string): void;
|
|
40
|
-
/** Return custom analysis modules. Called once during setup, before the main loop. */
|
|
41
|
-
customModules?(): CustomModule[];
|
|
42
|
-
/** Optional texts used by strategy-loop for async speech audio warmup. */
|
|
43
|
-
speechWarmupTexts?(): string[];
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export interface StrategyEntry {
|
|
47
|
-
readonly id: string;
|
|
48
|
-
/**
|
|
49
|
-
* 中文展示名/代词,玩家与 agent 沟通时使用(如「守尸」「武士虾」)。会出现在
|
|
50
|
-
* `ccl strategy --list`/`--info` 输出里,并可作为 `ccl strategy <名>` 的输入。
|
|
51
|
-
* 注意:这与 `Strategy.name`(`create()` 返回对象的内部 id 名)不是一回事。
|
|
52
|
-
* 须全局唯一。
|
|
53
|
-
*/
|
|
54
|
-
readonly name: string;
|
|
55
|
-
readonly description: string;
|
|
56
|
-
create(args?: string[]): Strategy;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
export interface RoomTarget {
|
|
60
|
-
name: string;
|
|
61
|
-
x: number;
|
|
62
|
-
y: number;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
export interface StrategyContext {
|
|
66
|
-
taskData: TaskInfo[];
|
|
67
|
-
/**
|
|
68
|
-
* 全局任务站点(map 的 all_task_locations),strategy-loop 加载地图后写入。与 taskData(仅自己被
|
|
69
|
-
* 分配、带 status)不同:这是地图上所有任务点的位置,开局固定。用于「同伴停在任务点附近 → 在真实
|
|
70
|
-
* 任务点假装做任务」这类定点行为。首次地图加载前可能为空/未设置。
|
|
71
|
-
*/
|
|
72
|
-
taskLocations?: TaskLocation[];
|
|
73
|
-
emergency: EmergencyInfo | null;
|
|
74
|
-
taskLocalBlockedUntil: number;
|
|
75
|
-
reportCorpseTarget: CorpseTarget | null;
|
|
76
|
-
reportBlockedUntil: number;
|
|
77
|
-
notifications: string[];
|
|
78
|
-
lastProgressNotifyAt: number;
|
|
79
|
-
teammates: Set<string>;
|
|
80
|
-
alarmDone: boolean;
|
|
81
|
-
rooms: RoomTarget[];
|
|
82
|
-
playerNamesBySeat: Record<string, string>;
|
|
83
|
-
/** Set by strategy-loop when a move target is unreachable too many times. Patrol strategies should advance past the current room. */
|
|
84
|
-
forcePatrolAdvance: boolean;
|
|
85
|
-
blockedMoveTarget: { x: number; y: number } | null;
|
|
86
|
-
/** Own seat number, used by speech module for initiation arbitration. */
|
|
87
|
-
mySeat: number;
|
|
88
|
-
/** Speech-module notifications, flushed by strategy-loop as robot_speak_rule events. */
|
|
89
|
-
speechNotifications: string[];
|
|
90
|
-
/**
|
|
91
|
-
* Strategy → agent real-time briefings, flushed by strategy-loop as `strategy_alert`
|
|
92
|
-
* events (notable → surfaced live by `ccl watch`, unlike `notifications` which only
|
|
93
|
-
* land in the log as `type:'auto'`). Push **sparingly**, only on a decisive autonomous
|
|
94
|
-
* move the agent must account for when it next speaks/votes (e.g. the bot reported a
|
|
95
|
-
* corpse — possibly its own kill — to deflect). NOT for per-tick progress.
|
|
96
|
-
*/
|
|
97
|
-
agentAlerts: string[];
|
|
98
|
-
/**
|
|
99
|
-
* 跨 tick 的已知尸体记忆,由 strategy-loop 每 tick 用中心 CorpseMemory 写入:尸体从出现一直存在到
|
|
100
|
-
* 开会才清空(开会时由 strategy-loop 清空)。是 `state.corpses`(仅当前视野)的严格超集,含已离开
|
|
101
|
-
* 视野、之前看见过的尸体。策略应统一读它做尸体检测/接近/任务回避/死亡确认,而非只看 `state.corpses`。
|
|
102
|
-
* 通过 hasKnownCorpse / nearestKnownCorpse / firstAvailableTask 的 avoidCorpses 参数消费。
|
|
103
|
-
*/
|
|
104
|
-
knownCorpses?: CorpseInfo[];
|
|
105
|
-
knowledge?: KnowledgeView;
|
|
106
|
-
recentlyKilledTargets?: Map<string, number>;
|
|
107
|
-
/** Strategy-registered modules. strategy-loop auto-calls processEvents, afterDecide, onMeetingResume and onMapLoaded. */
|
|
108
|
-
customModules?: CustomModule[];
|
|
109
|
-
}
|
|
1
|
+
import type { GameState, TaskInfo, TaskLocation, EmergencyInfo, CorpseInfo } from '../sdk/types.js';
|
|
2
|
+
import type { Action } from '../sdk/action.js';
|
|
3
|
+
import type { KnowledgeView } from '../lib/knowledge-store.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Minimal interface for custom modules (built-in and strategy-registered).
|
|
7
|
+
* Strategy authors implement this to inject custom analysis modules
|
|
8
|
+
* (e.g. CoMovementTracker, VisibilityTracker, SpeechAnalyzer) via ctx.customModules.
|
|
9
|
+
* The strategy-loop manages lifecycle through these hooks:
|
|
10
|
+
* - processEvents: called every tick with new events, tick number, and current game state
|
|
11
|
+
* - afterDecide: called after strategy.decide(), can filter/modify decisions (chained by registration order)
|
|
12
|
+
* - onMeetingResume: called after each meeting (decay or full reset)
|
|
13
|
+
* - onMapLoaded: called when fresh map data is available
|
|
14
|
+
*/
|
|
15
|
+
export interface CustomModule {
|
|
16
|
+
processEvents(events: any[], tick: number, state: GameState): void;
|
|
17
|
+
afterDecide?(decisions: BehaviorDecision[], state: GameState, ctx: StrategyContext): BehaviorDecision[];
|
|
18
|
+
onMeetingResume?(): void;
|
|
19
|
+
onMapLoaded?(rawRooms: any[]): void;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface BehaviorDecision {
|
|
23
|
+
action: Action;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface CorpseTarget {
|
|
27
|
+
x: number;
|
|
28
|
+
y: number;
|
|
29
|
+
name?: string;
|
|
30
|
+
room?: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface Strategy {
|
|
34
|
+
readonly name: string;
|
|
35
|
+
decide(state: GameState, ctx: StrategyContext): BehaviorDecision[];
|
|
36
|
+
/** Called when wandering resumes after a meeting pause. */
|
|
37
|
+
onMeetingResume?(): void;
|
|
38
|
+
/** Called by strategy-loop after getRoleInfo() resolves, allowing late config update. */
|
|
39
|
+
updateRole?(role: string): void;
|
|
40
|
+
/** Return custom analysis modules. Called once during setup, before the main loop. */
|
|
41
|
+
customModules?(): CustomModule[];
|
|
42
|
+
/** Optional texts used by strategy-loop for async speech audio warmup. */
|
|
43
|
+
speechWarmupTexts?(): string[];
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface StrategyEntry {
|
|
47
|
+
readonly id: string;
|
|
48
|
+
/**
|
|
49
|
+
* 中文展示名/代词,玩家与 agent 沟通时使用(如「守尸」「武士虾」)。会出现在
|
|
50
|
+
* `ccl strategy --list`/`--info` 输出里,并可作为 `ccl strategy <名>` 的输入。
|
|
51
|
+
* 注意:这与 `Strategy.name`(`create()` 返回对象的内部 id 名)不是一回事。
|
|
52
|
+
* 须全局唯一。
|
|
53
|
+
*/
|
|
54
|
+
readonly name: string;
|
|
55
|
+
readonly description: string;
|
|
56
|
+
create(args?: string[]): Strategy;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export interface RoomTarget {
|
|
60
|
+
name: string;
|
|
61
|
+
x: number;
|
|
62
|
+
y: number;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export interface StrategyContext {
|
|
66
|
+
taskData: TaskInfo[];
|
|
67
|
+
/**
|
|
68
|
+
* 全局任务站点(map 的 all_task_locations),strategy-loop 加载地图后写入。与 taskData(仅自己被
|
|
69
|
+
* 分配、带 status)不同:这是地图上所有任务点的位置,开局固定。用于「同伴停在任务点附近 → 在真实
|
|
70
|
+
* 任务点假装做任务」这类定点行为。首次地图加载前可能为空/未设置。
|
|
71
|
+
*/
|
|
72
|
+
taskLocations?: TaskLocation[];
|
|
73
|
+
emergency: EmergencyInfo | null;
|
|
74
|
+
taskLocalBlockedUntil: number;
|
|
75
|
+
reportCorpseTarget: CorpseTarget | null;
|
|
76
|
+
reportBlockedUntil: number;
|
|
77
|
+
notifications: string[];
|
|
78
|
+
lastProgressNotifyAt: number;
|
|
79
|
+
teammates: Set<string>;
|
|
80
|
+
alarmDone: boolean;
|
|
81
|
+
rooms: RoomTarget[];
|
|
82
|
+
playerNamesBySeat: Record<string, string>;
|
|
83
|
+
/** Set by strategy-loop when a move target is unreachable too many times. Patrol strategies should advance past the current room. */
|
|
84
|
+
forcePatrolAdvance: boolean;
|
|
85
|
+
blockedMoveTarget: { x: number; y: number } | null;
|
|
86
|
+
/** Own seat number, used by speech module for initiation arbitration. */
|
|
87
|
+
mySeat: number;
|
|
88
|
+
/** Speech-module notifications, flushed by strategy-loop as robot_speak_rule events. */
|
|
89
|
+
speechNotifications: string[];
|
|
90
|
+
/**
|
|
91
|
+
* Strategy → agent real-time briefings, flushed by strategy-loop as `strategy_alert`
|
|
92
|
+
* events (notable → surfaced live by `ccl watch`, unlike `notifications` which only
|
|
93
|
+
* land in the log as `type:'auto'`). Push **sparingly**, only on a decisive autonomous
|
|
94
|
+
* move the agent must account for when it next speaks/votes (e.g. the bot reported a
|
|
95
|
+
* corpse — possibly its own kill — to deflect). NOT for per-tick progress.
|
|
96
|
+
*/
|
|
97
|
+
agentAlerts: string[];
|
|
98
|
+
/**
|
|
99
|
+
* 跨 tick 的已知尸体记忆,由 strategy-loop 每 tick 用中心 CorpseMemory 写入:尸体从出现一直存在到
|
|
100
|
+
* 开会才清空(开会时由 strategy-loop 清空)。是 `state.corpses`(仅当前视野)的严格超集,含已离开
|
|
101
|
+
* 视野、之前看见过的尸体。策略应统一读它做尸体检测/接近/任务回避/死亡确认,而非只看 `state.corpses`。
|
|
102
|
+
* 通过 hasKnownCorpse / nearestKnownCorpse / firstAvailableTask 的 avoidCorpses 参数消费。
|
|
103
|
+
*/
|
|
104
|
+
knownCorpses?: CorpseInfo[];
|
|
105
|
+
knowledge?: KnowledgeView;
|
|
106
|
+
recentlyKilledTargets?: Map<string, number>;
|
|
107
|
+
/** Strategy-registered modules. strategy-loop auto-calls processEvents, afterDecide, onMeetingResume and onMapLoaded. */
|
|
108
|
+
customModules?: CustomModule[];
|
|
109
|
+
}
|
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
# warrior-memory 知识契约
|
|
2
|
-
|
|
3
|
-
`warrior-memory` 只读取两档玩家标记,**未标记的一律默认「被怀疑」**:
|
|
4
|
-
|
|
5
|
-
| 标记 | 行为 |
|
|
6
|
-
|------|------|
|
|
7
|
-
| `hostile`(坏人) | 敌对:刀可用时主动追杀;刀冷却或枪虾无次数时硬回避 |
|
|
8
|
-
| `trusted`(好人) | 可信:绝不攻击,也不会因其在场而对被怀疑者后撤 |
|
|
9
|
-
| 未标记(被怀疑) | 默认回避观察,刀可用也**绝不出刀**(无自卫例外) |
|
|
10
|
-
|
|
11
|
-
**不对被怀疑者出刀(无自卫机制)**:武士虾只对【已确认 hostile / 启动猎杀目标】出刀。历史上的「被怀疑者持续贴身追击 → 诱饵死角试探 → 绝境自卫先手」整套已删除:几何上无法把「贴身跟我观察/盯防的好人」与「贴身追我的凶手」区分开(两者跟随轨迹一样),自卫出刀迟早误杀同阵营好人、触发 warrior_shrimp_self_destruct 直接崩盘,代价远大于收益。被怀疑者贴身追来也只回避(拉开距离 / 借人多互为目击掩护),绝不反杀。
|
|
12
|
-
|
|
13
|
-
被怀疑者(未标记)平时按陌生人处理:不主动猎杀;无 trusted 同伴且单个被怀疑者贴近 270px 内时先拉开距离,多个互为目击者时照常做任务;坏人刀冷时硬躲所有非好人。尸体场景对【未报警的身份不明者】只报警不灭口:站在尸体旁即便身边有被怀疑者,也绝不先手击杀,一律靠近报警;但若尸体旁是 hostile 或启动猎杀目标、刀可用,仍会现场先手击杀(凶手就在身边照杀)。
|
|
14
|
-
|
|
15
|
-
```bash
|
|
16
|
-
ccl knowledge mark 5 hostile --note "确认敌对"
|
|
17
|
-
ccl knowledge mark 3 trusted --note "不在场证明成立"
|
|
18
|
-
ccl knowledge del player 5 # 取消标记 → 回到默认「被怀疑」
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
启动参数 `ccl strategy warrior-memory -- 3 7` 仍表示本次策略运行的明确猎杀目标(等同坏人)。`role` 是纯身份事实,不直接控制策略。
|
|
1
|
+
# warrior-memory 知识契约
|
|
2
|
+
|
|
3
|
+
`warrior-memory` 只读取两档玩家标记,**未标记的一律默认「被怀疑」**:
|
|
4
|
+
|
|
5
|
+
| 标记 | 行为 |
|
|
6
|
+
|------|------|
|
|
7
|
+
| `hostile`(坏人) | 敌对:刀可用时主动追杀;刀冷却或枪虾无次数时硬回避 |
|
|
8
|
+
| `trusted`(好人) | 可信:绝不攻击,也不会因其在场而对被怀疑者后撤 |
|
|
9
|
+
| 未标记(被怀疑) | 默认回避观察,刀可用也**绝不出刀**(无自卫例外) |
|
|
10
|
+
|
|
11
|
+
**不对被怀疑者出刀(无自卫机制)**:武士虾只对【已确认 hostile / 启动猎杀目标】出刀。历史上的「被怀疑者持续贴身追击 → 诱饵死角试探 → 绝境自卫先手」整套已删除:几何上无法把「贴身跟我观察/盯防的好人」与「贴身追我的凶手」区分开(两者跟随轨迹一样),自卫出刀迟早误杀同阵营好人、触发 warrior_shrimp_self_destruct 直接崩盘,代价远大于收益。被怀疑者贴身追来也只回避(拉开距离 / 借人多互为目击掩护),绝不反杀。
|
|
12
|
+
|
|
13
|
+
被怀疑者(未标记)平时按陌生人处理:不主动猎杀;无 trusted 同伴且单个被怀疑者贴近 270px 内时先拉开距离,多个互为目击者时照常做任务;坏人刀冷时硬躲所有非好人。尸体场景对【未报警的身份不明者】只报警不灭口:站在尸体旁即便身边有被怀疑者,也绝不先手击杀,一律靠近报警;但若尸体旁是 hostile 或启动猎杀目标、刀可用,仍会现场先手击杀(凶手就在身边照杀)。
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
ccl knowledge mark 5 hostile --note "确认敌对"
|
|
17
|
+
ccl knowledge mark 3 trusted --note "不在场证明成立"
|
|
18
|
+
ccl knowledge del player 5 # 取消标记 → 回到默认「被怀疑」
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
启动参数 `ccl strategy warrior-memory -- 3 7` 仍表示本次策略运行的明确猎杀目标(等同坏人)。`role` 是纯身份事实,不直接控制策略。
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import type { StrategyEntry } from './types.js';
|
|
2
|
-
import { GoalRootStrategy } from './goals/goal-root-strategy.js';
|
|
3
|
-
import { WarriorShrimpTop } from './goals/warrior-shrimp-top.js';
|
|
4
|
-
import { parseTargetArgs } from './player-targets.js';
|
|
5
|
-
|
|
6
|
-
export const strategy: StrategyEntry = {
|
|
7
|
-
id: 'warrior-memory',
|
|
8
|
-
name: '武士虾',
|
|
9
|
-
description:
|
|
10
|
-
'带刀虾·记忆进阶版(武士虾/枪虾通用,好人带刀;kill-lone 的带记忆升级)。读取 ccl knowledge 两档标记(hostile=坏人 / trusted=好人),未标记的一律默认被怀疑:hostile 刀好时主动追杀、刀不好时硬回避,trusted 视为可信同伴且绝不攻击。**只对【已确认 hostile / 启动猎杀目标】出刀**——被怀疑者一律只回避、绝不出刀(无可信同伴且单个被怀疑者贴近270内时先拉开到300再做任务,多人互为目击者则照常做任务);不再有任何贴身追击判定/诱饵试探/绝境自卫(几何上分不开"贴身跟我观察的好人"和"贴身追我的凶手",自卫迟早误杀同阵营好人触发武士虾自爆,整套已删除)。发现尸体优先报警;尸体旁若是 hostile/启动猎杀目标且刀可用会现场先手击杀,但绝不会因尸体旁有未报警的身份不明者就灭口(已根治该误杀);无危险时优先紧急任务,否则做任务/巡逻。枪虾会尊重剩余出刀次数。',
|
|
11
|
-
create(args?: string[]) {
|
|
12
|
-
const huntTargets = args ? parseTargetArgs(args) : [];
|
|
13
|
-
return new GoalRootStrategy('warrior-memory', () => new WarriorShrimpTop(huntTargets), {
|
|
14
|
-
resetOnMeetingResume: false,
|
|
15
|
-
});
|
|
16
|
-
},
|
|
17
|
-
};
|
|
1
|
+
import type { StrategyEntry } from './types.js';
|
|
2
|
+
import { GoalRootStrategy } from './goals/goal-root-strategy.js';
|
|
3
|
+
import { WarriorShrimpTop } from './goals/warrior-shrimp-top.js';
|
|
4
|
+
import { parseTargetArgs } from './player-targets.js';
|
|
5
|
+
|
|
6
|
+
export const strategy: StrategyEntry = {
|
|
7
|
+
id: 'warrior-memory',
|
|
8
|
+
name: '武士虾',
|
|
9
|
+
description:
|
|
10
|
+
'带刀虾·记忆进阶版(武士虾/枪虾通用,好人带刀;kill-lone 的带记忆升级)。读取 ccl knowledge 两档标记(hostile=坏人 / trusted=好人),未标记的一律默认被怀疑:hostile 刀好时主动追杀、刀不好时硬回避,trusted 视为可信同伴且绝不攻击。**只对【已确认 hostile / 启动猎杀目标】出刀**——被怀疑者一律只回避、绝不出刀(无可信同伴且单个被怀疑者贴近270内时先拉开到300再做任务,多人互为目击者则照常做任务);不再有任何贴身追击判定/诱饵试探/绝境自卫(几何上分不开"贴身跟我观察的好人"和"贴身追我的凶手",自卫迟早误杀同阵营好人触发武士虾自爆,整套已删除)。发现尸体优先报警;尸体旁若是 hostile/启动猎杀目标且刀可用会现场先手击杀,但绝不会因尸体旁有未报警的身份不明者就灭口(已根治该误杀);无危险时优先紧急任务,否则做任务/巡逻。枪虾会尊重剩余出刀次数。',
|
|
11
|
+
create(args?: string[]) {
|
|
12
|
+
const huntTargets = args ? parseTargetArgs(args) : [];
|
|
13
|
+
return new GoalRootStrategy('warrior-memory', () => new WarriorShrimpTop(huntTargets), {
|
|
14
|
+
resetOnMeetingResume: false,
|
|
15
|
+
});
|
|
16
|
+
},
|
|
17
|
+
};
|