@myclaw163/clawclaw-cli 0.6.60 → 0.6.61
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 +440 -440
- 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/postinstall.mjs +20 -20
- package/scripts/sync-bundled-skill.mjs +244 -244
- package/scripts/sync-bundled-skill.test.mjs +152 -152
- package/skills/clawclaw/SKILL.md +244 -244
- package/skills/clawclaw/references/CHATTERBOX.md +142 -142
- package/skills/clawclaw/references/COMMANDS.md +129 -129
- package/skills/clawclaw/references/GAME-MECHANICS.md +186 -186
- package/skills/clawclaw/references/HUB.md +48 -48
- package/skills/clawclaw/references/KNOWLEDGE.md +43 -43
- package/skills/clawclaw/references/STRATEGIES.md +57 -57
- package/skills/clawclaw/references/STREAM.md +59 -59
- package/skills/clawclaw/references/TACTICS.md +65 -65
- package/src/assets/clawclaw-ascii-map.txt +40 -40
- package/src/cli.ts +110 -110
- package/src/commands/_schema.ts +109 -109
- package/src/commands/account.ts +209 -209
- package/src/commands/config.ts +30 -30
- package/src/commands/do.test.ts +73 -73
- package/src/commands/do.ts +126 -126
- package/src/commands/events.ts +22 -22
- package/src/commands/game-map.test.ts +28 -28
- package/src/commands/game-start-plan.test.ts +84 -84
- package/src/commands/game.ts +1027 -1027
- 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 +19 -19
- package/src/commands/knowledge.ts +168 -168
- 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 +248 -248
- package/src/commands/setup/hermes.test.ts +96 -96
- package/src/commands/setup/hermes.ts +76 -76
- package/src/commands/setup/index.ts +13 -13
- package/src/commands/setup/openclaw.test.ts +114 -114
- package/src/commands/setup/openclaw.ts +147 -147
- package/src/commands/skill.ts +128 -128
- package/src/commands/state.ts +46 -46
- package/src/commands/strategy.test.ts +135 -135
- package/src/commands/strategy.ts +180 -180
- 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 +969 -969
- package/src/commands/watch.ts +720 -720
- package/src/lib/auth.test.ts +59 -59
- package/src/lib/auth.ts +186 -186
- package/src/lib/command-meta.ts +37 -37
- package/src/lib/game-client.ts +391 -391
- package/src/lib/host-config-patcher.test.ts +130 -130
- package/src/lib/host-config-patcher.ts +151 -151
- 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 +121 -121
- package/src/lib/hub-reminder.ts +56 -56
- 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 +120 -120
- package/src/lib/knowledge-store.test.ts +180 -180
- package/src/lib/knowledge-store.ts +374 -374
- 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 +232 -232
- package/src/lib/strategy-export.ts +242 -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/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-store.ts +124 -124
- package/src/pipeline/pipeline.ts +35 -35
- package/src/runtime/auto-upgrade.test.ts +66 -66
- package/src/runtime/auto-upgrade.ts +31 -31
- package/src/runtime/event-daemon.test.ts +107 -107
- package/src/runtime/event-daemon.ts +409 -409
- 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 +104 -104
- package/src/runtime/ws-client.ts +272 -272
- package/src/sdk/action.ts +166 -166
- package/src/sdk/index.ts +110 -110
- package/src/sdk/types.ts +146 -146
- package/src/strategies/avoid-lone.ts +11 -11
- package/src/strategies/avoid-players.knowledge.md +20 -20
- package/src/strategies/avoid-players.ts +15 -15
- package/src/strategies/corpse-patrol.ts +22 -22
- package/src/strategies/crab-sabotage.ts +21 -21
- package/src/strategies/custom-module.test.ts +269 -269
- package/src/strategies/find-player.ts +16 -16
- package/src/strategies/game-utils.test.ts +190 -190
- package/src/strategies/game-utils.ts +782 -744
- 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 +91 -91
- package/src/strategies/goals/crab-octopus-reflexes.ts +93 -93
- 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/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/keep-away-goal.ts +209 -209
- 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 +25 -25
- package/src/strategies/goals/linger-corpse-goal.ts +79 -79
- 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 +86 -86
- 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 +219 -219
- 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 +86 -86
- package/src/strategies/goals/warrior-shrimp-top.ts +248 -248
- package/src/strategies/greeting.ts +53 -53
- package/src/strategies/kill-frenzy.ts +12 -12
- package/src/strategies/kill-lone.knowledge.md +20 -20
- package/src/strategies/kill-lone.ts +13 -13
- package/src/strategies/kill-target.ts +18 -18
- package/src/strategies/loader.test.ts +678 -678
- package/src/strategies/loader.ts +172 -172
- package/src/strategies/lone-kill-task.ts +21 -21
- package/src/strategies/meeting-gate.test.ts +59 -59
- package/src/strategies/meeting-gate.ts +23 -23
- package/src/strategies/move-room.ts +15 -15
- package/src/strategies/new-events-backfill.ts +98 -98
- package/src/strategies/paradise-fish.knowledge.md +20 -20
- package/src/strategies/paradise-fish.ts +25 -25
- 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 +11 -11
- package/src/strategies/player-targets.ts +13 -13
- package/src/strategies/report-patrol.ts +11 -11
- package/src/strategies/shrimp-memory.knowledge.md +20 -20
- package/src/strategies/shrimp-memory.ts +25 -25
- package/src/strategies/social-task.test.ts +28 -28
- package/src/strategies/social-task.ts +49 -49
- package/src/strategies/spawn.ts +82 -82
- package/src/strategies/speech-module.ts +123 -123
- package/src/strategies/strategy-loop.ts +767 -763
- package/src/strategies/task-kill-report.ts +17 -17
- package/src/strategies/task-only.ts +11 -11
- package/src/strategies/task-report.ts +22 -22
- package/src/strategies/types.ts +96 -96
- package/src/strategies/warrior-memory.knowledge.md +20 -20
- package/src/strategies/warrior-memory.ts +16 -16
|
@@ -1,168 +1,168 @@
|
|
|
1
|
-
import { Command } from 'commander';
|
|
2
|
-
import { KnowledgeStore, type KnowledgeSetInput, type PlayerMark } from '../lib/knowledge-store.js';
|
|
3
|
-
|
|
4
|
-
const PLAYER_MARKS = new Set<PlayerMark>(['suspect', 'hostile', 'trusted']);
|
|
5
|
-
const LEGACY_MARK_TAGS = ['avoid', 'kill_if_armed', 'cleared', 'protected', 'do_not_kill'];
|
|
6
|
-
|
|
7
|
-
const LEGACY_SUSPECT_VERDICTS: Record<string, PlayerMark> = {
|
|
8
|
-
suspect: 'suspect', suspicious: 'suspect', avoid: 'suspect',
|
|
9
|
-
hostile: 'hostile', impostor: 'hostile', bad: 'hostile',
|
|
10
|
-
trusted: 'trusted', cleared: 'trusted', clear: 'trusted', innocent: 'trusted', safe: 'trusted',
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
export function normalizePlayerMark(mark?: string): PlayerMark | null {
|
|
14
|
-
const normalized = mark?.trim().toLowerCase() as PlayerMark | undefined;
|
|
15
|
-
return normalized && PLAYER_MARKS.has(normalized) ? normalized : null;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export function normalizeLegacySuspectVerdict(verdict?: string): PlayerMark | null {
|
|
19
|
-
return LEGACY_SUSPECT_VERDICTS[(verdict ?? 'suspect').trim().toLowerCase()] ?? null;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/** "true"/"false"/数字 自动转类型,其余按字符串。 */
|
|
23
|
-
function coerceValue(raw: string | undefined): unknown {
|
|
24
|
-
if (raw == null) return true;
|
|
25
|
-
if (raw === 'true') return true;
|
|
26
|
-
if (raw === 'false') return false;
|
|
27
|
-
if (raw !== '' && !Number.isNaN(Number(raw))) return Number(raw);
|
|
28
|
-
return raw;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
function collectTag(value: string, prev: string[]): string[] {
|
|
32
|
-
return [...prev, value];
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
function print(data: unknown): void {
|
|
36
|
-
console.log(JSON.stringify(data, null, 2));
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
function fail(error: string, message: string): never {
|
|
40
|
-
console.error(JSON.stringify({ error, message }, null, 2));
|
|
41
|
-
process.exit(1);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
function setPlayerMark(store: KnowledgeStore, player: string, mark: PlayerMark, opts: { confidence?: number; note?: string }) {
|
|
45
|
-
const removeTags = [
|
|
46
|
-
...[...PLAYER_MARKS].filter(candidate => candidate !== mark),
|
|
47
|
-
...LEGACY_MARK_TAGS,
|
|
48
|
-
];
|
|
49
|
-
return store.set({
|
|
50
|
-
type: 'player',
|
|
51
|
-
selector: player,
|
|
52
|
-
tags: [mark],
|
|
53
|
-
removeTags,
|
|
54
|
-
confidence: opts.confidence,
|
|
55
|
-
note: opts.note,
|
|
56
|
-
});
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
export function createKnowledgeCommand(): Command {
|
|
60
|
-
const cmd = new Command('knowledge')
|
|
61
|
-
.alias('kn')
|
|
62
|
-
.description('Per-game structured knowledge that a running strategy can query (no restart needed)');
|
|
63
|
-
|
|
64
|
-
cmd
|
|
65
|
-
.command('set [type] [selector] [key] [value]')
|
|
66
|
-
.description('Advanced: upsert arbitrary facts/tags. Use `knowledge mark` for player strategy behavior.')
|
|
67
|
-
.option('--tag <tag>', 'Custom tag, repeatable', collectTag, [])
|
|
68
|
-
.option('--confidence <n>', 'Confidence 0..1', parseFloat)
|
|
69
|
-
.option('--note <text>', 'Free-text reason')
|
|
70
|
-
.option('--json <json>', 'Provide the whole input object as JSON instead of positional args')
|
|
71
|
-
.action((type: string | undefined, selector: string | undefined, key: string | undefined, value: string | undefined, opts: {
|
|
72
|
-
tag: string[]; confidence?: number; note?: string; json?: string;
|
|
73
|
-
}) => {
|
|
74
|
-
try {
|
|
75
|
-
const store = KnowledgeStore.forActiveAccount();
|
|
76
|
-
let input: KnowledgeSetInput;
|
|
77
|
-
if (opts.json) {
|
|
78
|
-
input = JSON.parse(opts.json) as KnowledgeSetInput;
|
|
79
|
-
} else {
|
|
80
|
-
if (!type || !selector) {
|
|
81
|
-
fail('missing_args', 'Usage: ccl knowledge set <type> <selector> [key] [value] [--tag ...] — or: ccl knowledge set --json "{...}"');
|
|
82
|
-
}
|
|
83
|
-
input = {
|
|
84
|
-
type,
|
|
85
|
-
selector,
|
|
86
|
-
key,
|
|
87
|
-
value: key != null ? coerceValue(value) : undefined,
|
|
88
|
-
tags: opts.tag.length > 0 ? opts.tag : undefined,
|
|
89
|
-
confidence: opts.confidence,
|
|
90
|
-
note: opts.note,
|
|
91
|
-
};
|
|
92
|
-
}
|
|
93
|
-
const entry = store.set(input);
|
|
94
|
-
print({ ok: true, gameId: store.gameId ?? null, subject: entry });
|
|
95
|
-
} catch (e) {
|
|
96
|
-
fail('knowledge_set_failed', e instanceof Error ? e.message : String(e));
|
|
97
|
-
}
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
cmd
|
|
101
|
-
.command('mark <player> <mark>')
|
|
102
|
-
.description('Set the strategy mark for a player: suspect | hostile | trusted')
|
|
103
|
-
.option('--confidence <n>', 'Confidence 0..1', parseFloat)
|
|
104
|
-
.option('--note <text>', 'Free-text reason')
|
|
105
|
-
.action((player: string, rawMark: string, opts: { confidence?: number; note?: string }) => {
|
|
106
|
-
const mark = normalizePlayerMark(rawMark);
|
|
107
|
-
if (!mark) fail('invalid_mark', `Unknown mark '${rawMark}'. Use: suspect | hostile | trusted.`);
|
|
108
|
-
try {
|
|
109
|
-
const store = KnowledgeStore.forActiveAccount();
|
|
110
|
-
const entry = setPlayerMark(store, player, mark, opts);
|
|
111
|
-
print({ ok: true, gameId: store.gameId ?? null, mark, subject: entry });
|
|
112
|
-
} catch (e) {
|
|
113
|
-
fail('knowledge_mark_failed', e instanceof Error ? e.message : String(e));
|
|
114
|
-
}
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
cmd
|
|
118
|
-
.command('suspect <player> [verdict]')
|
|
119
|
-
.description('Legacy alias for `knowledge mark`: suspect(default) | impostor/hostile | cleared/trusted')
|
|
120
|
-
.option('--confidence <n>', 'Confidence 0..1', parseFloat)
|
|
121
|
-
.option('--note <text>', 'Free-text reason')
|
|
122
|
-
.action((player: string, verdict: string | undefined, opts: { confidence?: number; note?: string }) => {
|
|
123
|
-
const mark = normalizeLegacySuspectVerdict(verdict);
|
|
124
|
-
if (!mark) fail('invalid_verdict', `Unknown verdict '${verdict}'. Prefer: ccl knowledge mark <player> suspect|hostile|trusted.`);
|
|
125
|
-
try {
|
|
126
|
-
const store = KnowledgeStore.forActiveAccount();
|
|
127
|
-
const entry = setPlayerMark(store, player, mark, opts);
|
|
128
|
-
print({ ok: true, gameId: store.gameId ?? null, mark, subject: entry, deprecated_command: 'suspect' });
|
|
129
|
-
} catch (e) {
|
|
130
|
-
fail('knowledge_set_failed', e instanceof Error ? e.message : String(e));
|
|
131
|
-
}
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
cmd
|
|
135
|
-
.command('get [type] [selector]')
|
|
136
|
-
.description('Read knowledge: all, all of a type, or one subject')
|
|
137
|
-
.action((type: string | undefined, selector: string | undefined) => {
|
|
138
|
-
const store = KnowledgeStore.forActiveAccount();
|
|
139
|
-
const file = store.list();
|
|
140
|
-
if (type && selector) {
|
|
141
|
-
print({ gameId: file.gameId ?? null, subject: file.subjects[`${type}:${selector}`] ?? null });
|
|
142
|
-
return;
|
|
143
|
-
}
|
|
144
|
-
const subjects = Object.values(file.subjects).filter((s) => !type || s.type === type);
|
|
145
|
-
print({ gameId: file.gameId ?? null, count: subjects.length, subjects });
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
cmd
|
|
149
|
-
.command('del <type> <selector> [key]')
|
|
150
|
-
.description('Delete a subject, or just one fact (key) / tag (--tag)')
|
|
151
|
-
.option('--tag <tag>', 'Delete only this tag')
|
|
152
|
-
.action((type: string, selector: string, key: string | undefined, opts: { tag?: string }) => {
|
|
153
|
-
const store = KnowledgeStore.forActiveAccount();
|
|
154
|
-
const removed = store.del(type, selector, { key, tag: opts.tag });
|
|
155
|
-
print({ ok: removed, gameId: store.gameId ?? null });
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
cmd
|
|
159
|
-
.command('clear')
|
|
160
|
-
.description('Clear all knowledge for the current game')
|
|
161
|
-
.action(() => {
|
|
162
|
-
const store = KnowledgeStore.forActiveAccount();
|
|
163
|
-
store.clear();
|
|
164
|
-
print({ ok: true, gameId: store.gameId ?? null });
|
|
165
|
-
});
|
|
166
|
-
|
|
167
|
-
return cmd;
|
|
168
|
-
}
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { KnowledgeStore, type KnowledgeSetInput, type PlayerMark } from '../lib/knowledge-store.js';
|
|
3
|
+
|
|
4
|
+
const PLAYER_MARKS = new Set<PlayerMark>(['suspect', 'hostile', 'trusted']);
|
|
5
|
+
const LEGACY_MARK_TAGS = ['avoid', 'kill_if_armed', 'cleared', 'protected', 'do_not_kill'];
|
|
6
|
+
|
|
7
|
+
const LEGACY_SUSPECT_VERDICTS: Record<string, PlayerMark> = {
|
|
8
|
+
suspect: 'suspect', suspicious: 'suspect', avoid: 'suspect',
|
|
9
|
+
hostile: 'hostile', impostor: 'hostile', bad: 'hostile',
|
|
10
|
+
trusted: 'trusted', cleared: 'trusted', clear: 'trusted', innocent: 'trusted', safe: 'trusted',
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export function normalizePlayerMark(mark?: string): PlayerMark | null {
|
|
14
|
+
const normalized = mark?.trim().toLowerCase() as PlayerMark | undefined;
|
|
15
|
+
return normalized && PLAYER_MARKS.has(normalized) ? normalized : null;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function normalizeLegacySuspectVerdict(verdict?: string): PlayerMark | null {
|
|
19
|
+
return LEGACY_SUSPECT_VERDICTS[(verdict ?? 'suspect').trim().toLowerCase()] ?? null;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** "true"/"false"/数字 自动转类型,其余按字符串。 */
|
|
23
|
+
function coerceValue(raw: string | undefined): unknown {
|
|
24
|
+
if (raw == null) return true;
|
|
25
|
+
if (raw === 'true') return true;
|
|
26
|
+
if (raw === 'false') return false;
|
|
27
|
+
if (raw !== '' && !Number.isNaN(Number(raw))) return Number(raw);
|
|
28
|
+
return raw;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function collectTag(value: string, prev: string[]): string[] {
|
|
32
|
+
return [...prev, value];
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function print(data: unknown): void {
|
|
36
|
+
console.log(JSON.stringify(data, null, 2));
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function fail(error: string, message: string): never {
|
|
40
|
+
console.error(JSON.stringify({ error, message }, null, 2));
|
|
41
|
+
process.exit(1);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function setPlayerMark(store: KnowledgeStore, player: string, mark: PlayerMark, opts: { confidence?: number; note?: string }) {
|
|
45
|
+
const removeTags = [
|
|
46
|
+
...[...PLAYER_MARKS].filter(candidate => candidate !== mark),
|
|
47
|
+
...LEGACY_MARK_TAGS,
|
|
48
|
+
];
|
|
49
|
+
return store.set({
|
|
50
|
+
type: 'player',
|
|
51
|
+
selector: player,
|
|
52
|
+
tags: [mark],
|
|
53
|
+
removeTags,
|
|
54
|
+
confidence: opts.confidence,
|
|
55
|
+
note: opts.note,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function createKnowledgeCommand(): Command {
|
|
60
|
+
const cmd = new Command('knowledge')
|
|
61
|
+
.alias('kn')
|
|
62
|
+
.description('Per-game structured knowledge that a running strategy can query (no restart needed)');
|
|
63
|
+
|
|
64
|
+
cmd
|
|
65
|
+
.command('set [type] [selector] [key] [value]')
|
|
66
|
+
.description('Advanced: upsert arbitrary facts/tags. Use `knowledge mark` for player strategy behavior.')
|
|
67
|
+
.option('--tag <tag>', 'Custom tag, repeatable', collectTag, [])
|
|
68
|
+
.option('--confidence <n>', 'Confidence 0..1', parseFloat)
|
|
69
|
+
.option('--note <text>', 'Free-text reason')
|
|
70
|
+
.option('--json <json>', 'Provide the whole input object as JSON instead of positional args')
|
|
71
|
+
.action((type: string | undefined, selector: string | undefined, key: string | undefined, value: string | undefined, opts: {
|
|
72
|
+
tag: string[]; confidence?: number; note?: string; json?: string;
|
|
73
|
+
}) => {
|
|
74
|
+
try {
|
|
75
|
+
const store = KnowledgeStore.forActiveAccount();
|
|
76
|
+
let input: KnowledgeSetInput;
|
|
77
|
+
if (opts.json) {
|
|
78
|
+
input = JSON.parse(opts.json) as KnowledgeSetInput;
|
|
79
|
+
} else {
|
|
80
|
+
if (!type || !selector) {
|
|
81
|
+
fail('missing_args', 'Usage: ccl knowledge set <type> <selector> [key] [value] [--tag ...] — or: ccl knowledge set --json "{...}"');
|
|
82
|
+
}
|
|
83
|
+
input = {
|
|
84
|
+
type,
|
|
85
|
+
selector,
|
|
86
|
+
key,
|
|
87
|
+
value: key != null ? coerceValue(value) : undefined,
|
|
88
|
+
tags: opts.tag.length > 0 ? opts.tag : undefined,
|
|
89
|
+
confidence: opts.confidence,
|
|
90
|
+
note: opts.note,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
const entry = store.set(input);
|
|
94
|
+
print({ ok: true, gameId: store.gameId ?? null, subject: entry });
|
|
95
|
+
} catch (e) {
|
|
96
|
+
fail('knowledge_set_failed', e instanceof Error ? e.message : String(e));
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
cmd
|
|
101
|
+
.command('mark <player> <mark>')
|
|
102
|
+
.description('Set the strategy mark for a player: suspect | hostile | trusted')
|
|
103
|
+
.option('--confidence <n>', 'Confidence 0..1', parseFloat)
|
|
104
|
+
.option('--note <text>', 'Free-text reason')
|
|
105
|
+
.action((player: string, rawMark: string, opts: { confidence?: number; note?: string }) => {
|
|
106
|
+
const mark = normalizePlayerMark(rawMark);
|
|
107
|
+
if (!mark) fail('invalid_mark', `Unknown mark '${rawMark}'. Use: suspect | hostile | trusted.`);
|
|
108
|
+
try {
|
|
109
|
+
const store = KnowledgeStore.forActiveAccount();
|
|
110
|
+
const entry = setPlayerMark(store, player, mark, opts);
|
|
111
|
+
print({ ok: true, gameId: store.gameId ?? null, mark, subject: entry });
|
|
112
|
+
} catch (e) {
|
|
113
|
+
fail('knowledge_mark_failed', e instanceof Error ? e.message : String(e));
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
cmd
|
|
118
|
+
.command('suspect <player> [verdict]')
|
|
119
|
+
.description('Legacy alias for `knowledge mark`: suspect(default) | impostor/hostile | cleared/trusted')
|
|
120
|
+
.option('--confidence <n>', 'Confidence 0..1', parseFloat)
|
|
121
|
+
.option('--note <text>', 'Free-text reason')
|
|
122
|
+
.action((player: string, verdict: string | undefined, opts: { confidence?: number; note?: string }) => {
|
|
123
|
+
const mark = normalizeLegacySuspectVerdict(verdict);
|
|
124
|
+
if (!mark) fail('invalid_verdict', `Unknown verdict '${verdict}'. Prefer: ccl knowledge mark <player> suspect|hostile|trusted.`);
|
|
125
|
+
try {
|
|
126
|
+
const store = KnowledgeStore.forActiveAccount();
|
|
127
|
+
const entry = setPlayerMark(store, player, mark, opts);
|
|
128
|
+
print({ ok: true, gameId: store.gameId ?? null, mark, subject: entry, deprecated_command: 'suspect' });
|
|
129
|
+
} catch (e) {
|
|
130
|
+
fail('knowledge_set_failed', e instanceof Error ? e.message : String(e));
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
cmd
|
|
135
|
+
.command('get [type] [selector]')
|
|
136
|
+
.description('Read knowledge: all, all of a type, or one subject')
|
|
137
|
+
.action((type: string | undefined, selector: string | undefined) => {
|
|
138
|
+
const store = KnowledgeStore.forActiveAccount();
|
|
139
|
+
const file = store.list();
|
|
140
|
+
if (type && selector) {
|
|
141
|
+
print({ gameId: file.gameId ?? null, subject: file.subjects[`${type}:${selector}`] ?? null });
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
const subjects = Object.values(file.subjects).filter((s) => !type || s.type === type);
|
|
145
|
+
print({ gameId: file.gameId ?? null, count: subjects.length, subjects });
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
cmd
|
|
149
|
+
.command('del <type> <selector> [key]')
|
|
150
|
+
.description('Delete a subject, or just one fact (key) / tag (--tag)')
|
|
151
|
+
.option('--tag <tag>', 'Delete only this tag')
|
|
152
|
+
.action((type: string, selector: string, key: string | undefined, opts: { tag?: string }) => {
|
|
153
|
+
const store = KnowledgeStore.forActiveAccount();
|
|
154
|
+
const removed = store.del(type, selector, { key, tag: opts.tag });
|
|
155
|
+
print({ ok: removed, gameId: store.gameId ?? null });
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
cmd
|
|
159
|
+
.command('clear')
|
|
160
|
+
.description('Clear all knowledge for the current game')
|
|
161
|
+
.action(() => {
|
|
162
|
+
const store = KnowledgeStore.forActiveAccount();
|
|
163
|
+
store.clear();
|
|
164
|
+
print({ ok: true, gameId: store.gameId ?? null });
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
return cmd;
|
|
168
|
+
}
|
|
@@ -1,51 +1,51 @@
|
|
|
1
|
-
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
-
|
|
3
|
-
vi.mock('../lib/load-context.js', () => ({
|
|
4
|
-
loadContext: vi.fn(() => ({ persona: { exists: true }, memory: { exists: false } })),
|
|
5
|
-
}));
|
|
6
|
-
|
|
7
|
-
vi.mock('../runtime/auto-upgrade.js', () => ({
|
|
8
|
-
runAutoUpgradeOnLoad: vi.fn(),
|
|
9
|
-
}));
|
|
10
|
-
|
|
11
|
-
import { runAutoUpgradeOnLoad } from '../runtime/auto-upgrade.js';
|
|
12
|
-
import { createLoadCommand } from './load.js';
|
|
13
|
-
|
|
14
|
-
describe('load command', () => {
|
|
15
|
-
let logSpy: ReturnType<typeof vi.spyOn>;
|
|
16
|
-
let errorSpy: ReturnType<typeof vi.spyOn>;
|
|
17
|
-
|
|
18
|
-
beforeEach(() => {
|
|
19
|
-
vi.mocked(runAutoUpgradeOnLoad).mockClear();
|
|
20
|
-
logSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
|
|
21
|
-
errorSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
afterEach(() => {
|
|
25
|
-
logSpy.mockRestore();
|
|
26
|
-
errorSpy.mockRestore();
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
it('runs auto-upgrade check before printing JSON load context', async () => {
|
|
30
|
-
const cmd = createLoadCommand();
|
|
31
|
-
await cmd.parseAsync(['node', 'load'], { from: 'node' });
|
|
32
|
-
|
|
33
|
-
expect(runAutoUpgradeOnLoad).toHaveBeenCalledOnce();
|
|
34
|
-
expect(logSpy).toHaveBeenCalledOnce();
|
|
35
|
-
expect(JSON.parse(String(logSpy.mock.calls[0][0]))).toEqual({
|
|
36
|
-
persona: { exists: true },
|
|
37
|
-
memory: { exists: false },
|
|
38
|
-
});
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
it('routes auto-upgrade notifications to stderr', async () => {
|
|
42
|
-
vi.mocked(runAutoUpgradeOnLoad).mockImplementation(({ notify }: any) => {
|
|
43
|
-
notify('[clawclaw-cli] auto-upgrade installed 0.6.39');
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
const cmd = createLoadCommand();
|
|
47
|
-
await cmd.parseAsync(['node', 'load'], { from: 'node' });
|
|
48
|
-
|
|
49
|
-
expect(errorSpy).toHaveBeenCalledWith('[clawclaw-cli] auto-upgrade installed 0.6.39');
|
|
50
|
-
});
|
|
51
|
-
});
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
+
|
|
3
|
+
vi.mock('../lib/load-context.js', () => ({
|
|
4
|
+
loadContext: vi.fn(() => ({ persona: { exists: true }, memory: { exists: false } })),
|
|
5
|
+
}));
|
|
6
|
+
|
|
7
|
+
vi.mock('../runtime/auto-upgrade.js', () => ({
|
|
8
|
+
runAutoUpgradeOnLoad: vi.fn(),
|
|
9
|
+
}));
|
|
10
|
+
|
|
11
|
+
import { runAutoUpgradeOnLoad } from '../runtime/auto-upgrade.js';
|
|
12
|
+
import { createLoadCommand } from './load.js';
|
|
13
|
+
|
|
14
|
+
describe('load command', () => {
|
|
15
|
+
let logSpy: ReturnType<typeof vi.spyOn>;
|
|
16
|
+
let errorSpy: ReturnType<typeof vi.spyOn>;
|
|
17
|
+
|
|
18
|
+
beforeEach(() => {
|
|
19
|
+
vi.mocked(runAutoUpgradeOnLoad).mockClear();
|
|
20
|
+
logSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
|
|
21
|
+
errorSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
afterEach(() => {
|
|
25
|
+
logSpy.mockRestore();
|
|
26
|
+
errorSpy.mockRestore();
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('runs auto-upgrade check before printing JSON load context', async () => {
|
|
30
|
+
const cmd = createLoadCommand();
|
|
31
|
+
await cmd.parseAsync(['node', 'load'], { from: 'node' });
|
|
32
|
+
|
|
33
|
+
expect(runAutoUpgradeOnLoad).toHaveBeenCalledOnce();
|
|
34
|
+
expect(logSpy).toHaveBeenCalledOnce();
|
|
35
|
+
expect(JSON.parse(String(logSpy.mock.calls[0][0]))).toEqual({
|
|
36
|
+
persona: { exists: true },
|
|
37
|
+
memory: { exists: false },
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('routes auto-upgrade notifications to stderr', async () => {
|
|
42
|
+
vi.mocked(runAutoUpgradeOnLoad).mockImplementation(({ notify }: any) => {
|
|
43
|
+
notify('[clawclaw-cli] auto-upgrade installed 0.6.39');
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
const cmd = createLoadCommand();
|
|
47
|
+
await cmd.parseAsync(['node', 'load'], { from: 'node' });
|
|
48
|
+
|
|
49
|
+
expect(errorSpy).toHaveBeenCalledWith('[clawclaw-cli] auto-upgrade installed 0.6.39');
|
|
50
|
+
});
|
|
51
|
+
});
|
package/src/commands/load.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { Command } from 'commander';
|
|
2
|
-
import { loadContext } from '../lib/load-context.js';
|
|
3
|
-
import { runAutoUpgradeOnLoad } from '../runtime/auto-upgrade.js';
|
|
4
|
-
|
|
5
|
-
export function createLoadCommand(): Command {
|
|
6
|
-
return new Command('load')
|
|
7
|
-
.description('Read active account persona and memory files')
|
|
8
|
-
.action(() => {
|
|
9
|
-
runAutoUpgradeOnLoad({ notify: (message) => console.error(message) });
|
|
10
|
-
const snapshot = loadContext();
|
|
11
|
-
console.log(JSON.stringify(snapshot, null, 2));
|
|
12
|
-
});
|
|
13
|
-
}
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { loadContext } from '../lib/load-context.js';
|
|
3
|
+
import { runAutoUpgradeOnLoad } from '../runtime/auto-upgrade.js';
|
|
4
|
+
|
|
5
|
+
export function createLoadCommand(): Command {
|
|
6
|
+
return new Command('load')
|
|
7
|
+
.description('Read active account persona and memory files')
|
|
8
|
+
.action(() => {
|
|
9
|
+
runAutoUpgradeOnLoad({ notify: (message) => console.error(message) });
|
|
10
|
+
const snapshot = loadContext();
|
|
11
|
+
console.log(JSON.stringify(snapshot, null, 2));
|
|
12
|
+
});
|
|
13
|
+
}
|