poi-plugin-gimmick-tracker 0.1.0
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 +47 -0
- package/i18n/zh-CN.json +35 -0
- package/index.js +1405 -0
- package/index.js.map +1 -0
- package/package.json +49 -0
package/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":["AIR_TEXT_TO_STATE: Record<string, AirState>","parsed: ParsedGuideCondition[]","match: RegExpExecArray | null","RANK_SCORE: Record<VictoryRank, number>","AIR_LABEL: Record<AirState, string>","parsed: unknown","path","visit","battle: BattleReference","condition","condition: GuideCondition","completion: FreeCompletion","appDataPath: string","path","dependencies: TrackerControllerDependencies","ipc","getStore","route","styles: Record<string, React.CSSProperties>","zhCN","Tag","Card","Elevation","Callout","HTMLSelect","Button","controller","pending","TextArea","HTMLTable","APPDATA_PATH","ipc","path"],"sources":["src/core/guide-parser.ts","src/core/conditions.ts","src/core/events.ts","src/core/types.ts","src/core/state-machine.ts","src/storage/index.ts","src/controller.ts","src/host/focus.ts","src/host/node-resolver.ts","i18n/zh-CN.json","src/ui/index.tsx","index-src.ts"],"sourcesContent":["import type { AirState, ConditionKind, VictoryRank } from './types'\n\nexport interface ParsedGuideCondition {\n kind: ConditionKind\n rawText: string\n nodeLabel?: string\n requiredRank?: VictoryRank\n requiredAirState?: AirState\n requiredCount: number\n}\n\nconst AIR_TEXT_TO_STATE: Record<string, AirState> = {\n 空确: 1,\n 空優: 2,\n 空优: 2,\n 空均: 3,\n 空劣: 4,\n}\n\nconst TOKEN_PATTERN =\n /([A-Za-z]\\d*)\\s*点\\s*(到达|到達)\\s*(\\d+)\\s*次|([A-Za-z]\\d*)\\s*点\\s*(SS|S|A|B|C|D|E)\\s*胜\\s*(\\d+)\\s*次|([A-Za-z]\\d*)\\s*点\\s*(空确|空優|空优|空均|空劣)\\s*(\\d+)\\s*次|(守家|基地防空)\\s*(空确|空優|空优|空均|空劣)\\s*(\\d+)\\s*次/gi\n\nexport function normalizeNodeLabel(value: string): string {\n return value.trim().toUpperCase()\n}\n\nexport function parseGuideText(text: string): ParsedGuideCondition[] {\n const normalized = text.replace(/[,;]/g, (value) => (value === ',' ? ',' : ';'))\n const parsed: ParsedGuideCondition[] = []\n let match: RegExpExecArray | null\n TOKEN_PATTERN.lastIndex = 0\n\n while ((match = TOKEN_PATTERN.exec(normalized)) !== null) {\n const rawText = match[0].replace(/\\s+/g, '')\n if (match[1] != null) {\n parsed.push({\n kind: 'node-arrival',\n nodeLabel: normalizeNodeLabel(match[1]),\n requiredCount: Number(match[3]),\n rawText,\n })\n continue\n }\n if (match[4] != null) {\n parsed.push({\n kind: 'victory-rank',\n nodeLabel: normalizeNodeLabel(match[4]),\n requiredRank: match[5].toUpperCase() as VictoryRank,\n requiredCount: Number(match[6]),\n rawText,\n })\n continue\n }\n if (match[7] != null) {\n parsed.push({\n kind: 'node-air-state',\n nodeLabel: normalizeNodeLabel(match[7]),\n requiredAirState: AIR_TEXT_TO_STATE[match[8]],\n requiredCount: Number(match[9]),\n rawText,\n })\n continue\n }\n parsed.push({\n kind: 'base-air-defense',\n requiredAirState: AIR_TEXT_TO_STATE[match[11]],\n requiredCount: Number(match[12]),\n rawText,\n })\n }\n\n return parsed.filter((item) => Number.isInteger(item.requiredCount) && item.requiredCount > 0)\n}\n","import type { ParsedGuideCondition } from './guide-parser'\nimport { normalizeNodeLabel } from './guide-parser'\nimport type {\n AirState,\n GuideCondition,\n MapRef,\n Observation,\n ReviewCandidate,\n TrackerState,\n VictoryRank,\n} from './types'\n\nconst RANK_SCORE: Record<VictoryRank, number> = {\n E: 0,\n D: 1,\n C: 2,\n B: 3,\n A: 4,\n S: 5,\n SS: 6,\n}\n\nconst AIR_LABEL: Record<AirState, string> = {\n 1: '空确',\n 2: '空优',\n 3: '空均',\n 4: '空劣',\n}\n\nexport function airStateLabel(state: AirState): string {\n return AIR_LABEL[state]\n}\n\nexport function meetsRank(actual: VictoryRank, required: VictoryRank): boolean {\n return RANK_SCORE[actual] >= RANK_SCORE[required]\n}\n\nexport function meetsAirState(actual: AirState, required: AirState): boolean {\n return actual <= required\n}\n\nexport function conditionSignature(\n map: Pick<MapRef, 'mapId'>,\n item: Pick<\n ParsedGuideCondition,\n 'kind' | 'nodeLabel' | 'requiredRank' | 'requiredAirState'\n >,\n): string {\n return [\n map.mapId,\n item.kind,\n item.nodeLabel == null ? '' : normalizeNodeLabel(item.nodeLabel),\n item.requiredRank ?? '',\n item.requiredAirState ?? '',\n ].join(':')\n}\n\nexport function observationMatches(condition: GuideCondition, observation: Observation): boolean {\n if (condition.mapId !== observation.mapId || condition.kind !== observation.kind) return false\n if (\n condition.nodeLabel != null &&\n normalizeNodeLabel(condition.nodeLabel) !== normalizeNodeLabel(observation.nodeLabel ?? '')\n ) {\n return false\n }\n if (condition.kind === 'victory-rank') {\n return (\n observation.kind === 'victory-rank' &&\n condition.requiredRank != null &&\n meetsRank(observation.rank, condition.requiredRank)\n )\n }\n if (condition.kind === 'node-air-state' || condition.kind === 'base-air-defense') {\n return (\n (observation.kind === 'node-air-state' || observation.kind === 'base-air-defense') &&\n condition.requiredAirState != null &&\n meetsAirState(observation.airState, condition.requiredAirState)\n )\n }\n return observation.kind === 'node-arrival'\n}\n\nexport function guideConditionLabel(condition: GuideCondition): string {\n const node = condition.nodeLabel == null ? '' : `${condition.nodeLabel}点`\n switch (condition.kind) {\n case 'node-arrival':\n return `${node}到达 ${condition.requiredCount}次`\n case 'victory-rank':\n return `${node}${condition.requiredRank}胜 ${condition.requiredCount}次`\n case 'node-air-state':\n return `${node}${airStateLabel(condition.requiredAirState!)} ${condition.requiredCount}次`\n case 'base-air-defense':\n return `守家${airStateLabel(condition.requiredAirState!)} ${condition.requiredCount}次`\n }\n}\n\nexport function observationLabel(observation: Observation): string {\n switch (observation.kind) {\n case 'node-arrival':\n return `${observation.nodeLabel}点到达`\n case 'victory-rank':\n return `${observation.nodeLabel}点${observation.rank}胜`\n case 'node-air-state':\n return `${observation.nodeLabel}点${airStateLabel(observation.airState)}`\n case 'base-air-defense':\n return `守家${airStateLabel(observation.airState)}`\n }\n}\n\nexport function buildReviewCandidates(\n state: TrackerState,\n mapId: number,\n observationIds: string[],\n): ReviewCandidate[] {\n const evidence = state.observations.filter((item) => observationIds.includes(item.id))\n const guides = state.guideConditions.filter(\n (condition) => condition.mapId === mapId && !condition.confirmed,\n )\n if (guides.length > 0) {\n return guides\n .map((condition) => ({\n id: `guide:${condition.id}`,\n mode: 'guide' as const,\n kind: condition.kind,\n label: guideConditionLabel(condition),\n conditionId: condition.id,\n matchedInSortie: evidence.some((item) => observationMatches(condition, item)),\n observedCount: condition.observedCount,\n requiredCount: condition.requiredCount,\n }))\n .sort((left, right) => Number(right.matchedInSortie) - Number(left.matchedInSortie))\n }\n\n return evidence.map((observation) => ({\n id: `free:${observation.id}`,\n mode: 'free' as const,\n kind: observation.kind,\n label: observationLabel(observation),\n observationId: observation.id,\n matchedInSortie: true,\n }))\n}\n","import type { AirState, GameResponseDetail, MapRef, VictoryRank } from './types'\n\nexport const MAP_PATHS = new Set([\n '/kcsapi/api_req_map/start',\n '/kcsapi/api_req_map/next',\n '/kcsapi/api_req_map/air_raid',\n])\n\nconst BATTLE_SUFFIXES = new Set([\n 'battle',\n 'airbattle',\n 'ld_airbattle',\n 'night_to_day',\n 'sp_midnight',\n 'midnight',\n 'midnight_battle',\n 'battle_water',\n 'each_battle',\n 'each_battle_water',\n 'ec_battle',\n 'ec_midnight_battle',\n 'ec_night_to_day',\n])\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n\nexport function asRecord(value: unknown): Record<string, unknown> | undefined {\n if (isRecord(value)) return value\n if (typeof value !== 'string') return undefined\n try {\n const parsed: unknown = JSON.parse(value)\n return isRecord(parsed) ? parsed : undefined\n } catch {\n return undefined\n }\n}\n\nexport function asNumber(value: unknown): number | undefined {\n if (typeof value === 'number' && Number.isFinite(value)) return value\n if (typeof value === 'string' && value.trim() !== '') {\n const parsed = Number(value)\n return Number.isFinite(parsed) ? parsed : undefined\n }\n return undefined\n}\n\nexport function isRelevantPath(path: string): boolean {\n return (\n path === '/kcsapi/api_port/port' ||\n MAP_PATHS.has(path) ||\n isBattlePath(path) ||\n isBattleResultPath(path)\n )\n}\n\nexport function isBattleResultPath(path: string): boolean {\n return path.startsWith('/kcsapi/') && path.endsWith('/battleresult')\n}\n\nexport function isBattlePath(path: string): boolean {\n if (!/^\\/kcsapi\\/api_req_(sortie|combined_battle|battle_midnight)\\//.test(path)) return false\n return BATTLE_SUFFIXES.has(path.slice(path.lastIndexOf('/') + 1))\n}\n\nexport function eventKey(detail: GameResponseDetail): string {\n return `${detail.path}|${detail.time}`\n}\n\nexport function extractMapRef(\n detail: GameResponseDetail,\n fallback?: Pick<MapRef, 'mapArea' | 'mapNo'>,\n): MapRef {\n const mapArea =\n asNumber(detail.body.api_maparea_id) ??\n asNumber(detail.postBody?.api_maparea_id) ??\n fallback?.mapArea ??\n 0\n const mapNo =\n asNumber(detail.body.api_mapinfo_no) ??\n asNumber(detail.postBody?.api_mapinfo_no) ??\n fallback?.mapNo ??\n 0\n return { mapArea, mapNo, mapId: mapArea * 10 + mapNo }\n}\n\nexport function extractNodeNo(body: Record<string, unknown>): number | undefined {\n return asNumber(body.api_no)\n}\n\nexport function extractBattleAirState(body: Record<string, unknown>): AirState | undefined {\n const kouku = asRecord(body.api_kouku)\n const stage1 = asRecord(kouku?.api_stage1)\n const value = asNumber(stage1?.api_disp_seiku)\n return value != null && value >= 1 && value <= 4 ? (value as AirState) : undefined\n}\n\nexport function extractVictoryRank(body: Record<string, unknown>): VictoryRank | undefined {\n const value = typeof body.api_win_rank === 'string' ? body.api_win_rank.toUpperCase() : ''\n return ['SS', 'S', 'A', 'B', 'C', 'D', 'E'].includes(value)\n ? (value as VictoryRank)\n : undefined\n}\n\nexport function extractDestructionBattles(body: Record<string, unknown>): Record<string, unknown>[] {\n const raw = body.api_destruction_battle\n const values = Array.isArray(raw) ? raw : raw == null ? [] : [raw]\n return values.map(asRecord).filter((item): item is Record<string, unknown> => item != null)\n}\n\nexport function extractDefenseAirState(entry: Record<string, unknown>): AirState | undefined {\n const attack = asRecord(entry.api_air_base_attack)\n const stage1 = asRecord(attack?.api_stage1)\n const value = asNumber(stage1?.api_disp_seiku)\n return value != null && value >= 1 && value <= 4 ? (value as AirState) : undefined\n}\n\nexport function hasPortSignal(detail: GameResponseDetail): boolean {\n const eventObject = asRecord(detail.body.api_event_object)\n return detail.path === '/kcsapi/api_port/port' && asNumber(eventObject?.api_m_flag2) === 1\n}\n\nexport function hasBattleResultSignal(detail: GameResponseDetail): boolean {\n return isBattleResultPath(detail.path) && asNumber(detail.body.api_m2) === 1\n}\n\nexport function hasDefenseSignal(entry: Record<string, unknown>): boolean {\n return asNumber(entry.api_m2) === 1\n}\n\nexport function extractPortMemberId(detail: GameResponseDetail): unknown {\n if (detail.path !== '/kcsapi/api_port/port') return undefined\n return asRecord(detail.body.api_basic)?.api_member_id\n}\n","export const PLUGIN_ID = 'poi-plugin-gimmick-tracker'\nexport const SCHEMA_VERSION = 1 as const\n\nexport type AirState = 1 | 2 | 3 | 4\nexport type VictoryRank = 'SS' | 'S' | 'A' | 'B' | 'C' | 'D' | 'E'\nexport type ConditionKind =\n | 'node-arrival'\n | 'victory-rank'\n | 'node-air-state'\n | 'base-air-defense'\n\nexport interface MapRef {\n mapArea: number\n mapNo: number\n mapId: number\n}\n\nexport interface BattleReference {\n timestamp: number\n path: string\n kind?: 'battle' | 'fleet-air-raid' | 'base-air-defense'\n}\n\nexport interface BaseDefenseEvent {\n timestamp: number\n path: string\n airState?: AirState\n}\n\nexport type TimelineEventKind = 'node' | 'fleet-air-raid' | 'base-air-defense'\n\nexport interface SortieTimelineEvent {\n id: string\n kind: TimelineEventKind\n occurredAt: number\n sourcePath: string\n nodeVisitId?: string\n nodeNo?: number\n nodeLabel?: string\n airState?: AirState\n}\n\nexport interface NodeVisit extends MapRef {\n id: string\n nodeNo: number\n nodeLabel: string\n arrivedAt: number\n sourcePath: string\n battle?: BattleReference\n battleEvents?: BattleReference[]\n baseDefenseEvents?: BaseDefenseEvent[]\n rank?: VictoryRank\n airState?: AirState\n}\n\ninterface ObservationBase extends MapRef {\n id: string\n kind: ConditionKind\n observedAt: number\n sourcePath: string\n sortieId: string\n nodeNo?: number\n nodeLabel?: string\n battle?: BattleReference\n}\n\nexport interface NodeArrivalObservation extends ObservationBase {\n kind: 'node-arrival'\n nodeNo: number\n nodeLabel: string\n}\n\nexport interface VictoryObservation extends ObservationBase {\n kind: 'victory-rank'\n nodeNo: number\n nodeLabel: string\n rank: VictoryRank\n}\n\nexport interface NodeAirObservation extends ObservationBase {\n kind: 'node-air-state'\n nodeNo: number\n nodeLabel: string\n airState: AirState\n}\n\nexport interface BaseAirDefenseObservation extends ObservationBase {\n kind: 'base-air-defense'\n airState: AirState\n}\n\nexport type Observation =\n | NodeArrivalObservation\n | VictoryObservation\n | NodeAirObservation\n | BaseAirDefenseObservation\n\nexport interface GuideCondition extends MapRef {\n id: string\n kind: ConditionKind\n rawText: string\n nodeLabel?: string\n requiredRank?: VictoryRank\n requiredAirState?: AirState\n requiredCount: number\n observedCount: number\n confirmed: boolean\n confirmedAt?: number\n confirmedByReviewId?: string\n createdAt: number\n}\n\nexport interface ReviewCandidate {\n id: string\n mode: 'guide' | 'free'\n kind: ConditionKind\n label: string\n conditionId?: string\n observationId?: string\n matchedInSortie: boolean\n observedCount?: number\n requiredCount?: number\n}\n\nexport type TriggerSource = 'port' | 'battleresult' | 'air-defense'\nexport type ReviewStatus = 'pending' | 'confirmed' | 'ignored'\n\nexport interface PendingReview extends MapRef {\n id: string\n sortieId: string\n startedAt: number\n detectedAt: number\n triggerSources: TriggerSource[]\n sealed: boolean\n routeComplete: boolean\n route: NodeVisit[]\n timeline: SortieTimelineEvent[]\n observationIds: string[]\n candidates: ReviewCandidate[]\n status: ReviewStatus\n selectedCandidateIds?: string[]\n resolvedAt?: number\n}\n\nexport interface FreeCompletion extends MapRef {\n id: string\n kind: ConditionKind\n label: string\n reviewId: string\n observationId: string\n confirmedAt: number\n}\n\nexport interface ActiveSortie extends MapRef {\n id: string\n startedAt: number\n captureComplete: boolean\n route: NodeVisit[]\n timeline: SortieTimelineEvent[]\n observationIds: string[]\n lastBattle?: BattleReference\n}\n\nexport interface TrackerState {\n schemaVersion: typeof SCHEMA_VERSION\n activeSortie?: ActiveSortie\n observations: Observation[]\n guideConditions: GuideCondition[]\n reviews: PendingReview[]\n freeCompletions: FreeCompletion[]\n processedEventKeys: string[]\n updatedAt: number\n}\n\nexport interface GameResponseDetail {\n method?: string\n path: string\n body: Record<string, unknown>\n postBody?: Record<string, unknown>\n time: number\n}\n\nexport type NodeResolver = (input: {\n mapArea: number\n mapNo: number\n apiNo: number\n}) => string\n\nexport function createInitialState(now = 0): TrackerState {\n return {\n schemaVersion: SCHEMA_VERSION,\n observations: [],\n guideConditions: [],\n reviews: [],\n freeCompletions: [],\n processedEventKeys: [],\n updatedAt: now,\n }\n}\n\nexport function cloneState(state: TrackerState): TrackerState {\n return JSON.parse(JSON.stringify(state)) as TrackerState\n}\n\nexport function mapLabel(map: Pick<MapRef, 'mapArea' | 'mapNo' | 'mapId'>): string {\n return map.mapArea > 0 && map.mapNo > 0 ? `${map.mapArea}-${map.mapNo}` : `地图 #${map.mapId}`\n}\n","import {\n buildReviewCandidates,\n conditionSignature,\n observationMatches,\n} from './conditions'\nimport {\n eventKey,\n extractBattleAirState,\n extractDefenseAirState,\n extractDestructionBattles,\n extractMapRef,\n extractNodeNo,\n extractVictoryRank,\n hasBattleResultSignal,\n hasDefenseSignal,\n hasPortSignal,\n isBattlePath,\n isBattleResultPath,\n isRelevantPath,\n MAP_PATHS,\n} from './events'\nimport { parseGuideText } from './guide-parser'\nimport type {\n ActiveSortie,\n BaseAirDefenseObservation,\n BattleReference,\n FreeCompletion,\n GameResponseDetail,\n GuideCondition,\n MapRef,\n NodeAirObservation,\n NodeArrivalObservation,\n NodeResolver,\n Observation,\n PendingReview,\n TrackerState,\n TriggerSource,\n VictoryObservation,\n} from './types'\nimport { cloneState } from './types'\n\nexport interface TransitionResult {\n state: TrackerState\n changed: boolean\n shouldFocus: boolean\n}\n\nexport interface ImportGuideResult {\n state: TrackerState\n importedCount: number\n}\n\nconst MAX_PROCESSED_EVENT_KEYS = 2048\n\nfunction safeNodeLabel(resolver: NodeResolver, map: MapRef, apiNo: number): string {\n try {\n const value = resolver({ mapArea: map.mapArea, mapNo: map.mapNo, apiNo }).trim()\n return value === '' ? `#${apiNo}` : value\n } catch {\n return `#${apiNo}`\n }\n}\n\nfunction createSortie(\n detail: GameResponseDetail,\n map: MapRef,\n captureComplete: boolean,\n): ActiveSortie {\n return {\n ...map,\n id: `${captureComplete ? 'sortie' : 'partial'}:${map.mapId}:${detail.time}`,\n startedAt: detail.time,\n captureComplete,\n route: [],\n timeline: [],\n observationIds: [],\n }\n}\n\nfunction appendObservation(\n state: TrackerState,\n sortie: ActiveSortie,\n observation: Observation,\n): boolean {\n if (state.observations.some((item) => item.id === observation.id)) return false\n state.observations.push(observation)\n sortie.observationIds.push(observation.id)\n for (const condition of state.guideConditions) {\n if (observationMatches(condition, observation)) condition.observedCount += 1\n }\n return true\n}\n\nfunction currentNode(sortie: ActiveSortie) {\n return sortie.route.at(-1)\n}\n\nfunction addNodeVisit(\n state: TrackerState,\n sortie: ActiveSortie,\n detail: GameResponseDetail,\n nodeResolver: NodeResolver,\n): void {\n const nodeNo = extractNodeNo(detail.body)\n if (nodeNo == null) return\n const id = `${eventKey(detail)}:node`\n if (sortie.route.some((visit) => visit.id === id)) return\n const nodeLabel = safeNodeLabel(nodeResolver, sortie, nodeNo)\n const visit = {\n id,\n mapArea: sortie.mapArea,\n mapNo: sortie.mapNo,\n mapId: sortie.mapId,\n nodeNo,\n nodeLabel,\n arrivedAt: detail.time,\n sourcePath: detail.path,\n }\n sortie.route.push(visit)\n sortie.timeline.push({\n id: `${id}:timeline`,\n kind: 'node',\n occurredAt: detail.time,\n sourcePath: detail.path,\n nodeVisitId: id,\n nodeNo,\n nodeLabel,\n })\n const observation: NodeArrivalObservation = {\n id: `${id}:arrival`,\n kind: 'node-arrival',\n mapArea: sortie.mapArea,\n mapNo: sortie.mapNo,\n mapId: sortie.mapId,\n nodeNo,\n nodeLabel,\n observedAt: detail.time,\n sourcePath: detail.path,\n sortieId: sortie.id,\n }\n appendObservation(state, sortie, observation)\n}\n\nfunction addBattle(\n state: TrackerState,\n sortie: ActiveSortie,\n detail: GameResponseDetail,\n): void {\n const battle: BattleReference = {\n timestamp: detail.time,\n path: detail.path,\n kind: detail.path.endsWith('/ld_airbattle') ? 'fleet-air-raid' : 'battle',\n }\n sortie.lastBattle = battle\n const node = currentNode(sortie)\n if (node != null) {\n node.battle = battle\n ;(node.battleEvents ??= []).push(battle)\n }\n const airState = extractBattleAirState(detail.body)\n if (battle.kind === 'fleet-air-raid') {\n sortie.timeline.push({\n id: `${eventKey(detail)}:fleet-air-raid`,\n kind: 'fleet-air-raid',\n occurredAt: detail.time,\n sourcePath: detail.path,\n nodeVisitId: node?.id,\n nodeNo: node?.nodeNo,\n nodeLabel: node?.nodeLabel,\n airState,\n })\n }\n if (node == null || airState == null) return\n node.airState = airState\n const observation: NodeAirObservation = {\n id: `${eventKey(detail)}:node-air`,\n kind: 'node-air-state',\n mapArea: sortie.mapArea,\n mapNo: sortie.mapNo,\n mapId: sortie.mapId,\n nodeNo: node.nodeNo,\n nodeLabel: node.nodeLabel,\n airState,\n observedAt: detail.time,\n sourcePath: detail.path,\n sortieId: sortie.id,\n battle,\n }\n appendObservation(state, sortie, observation)\n}\n\nfunction addBattleResult(\n state: TrackerState,\n sortie: ActiveSortie,\n detail: GameResponseDetail,\n): void {\n const rank = extractVictoryRank(detail.body)\n const node = currentNode(sortie)\n if (rank == null || node == null) return\n node.rank = rank\n const observation: VictoryObservation = {\n id: `${eventKey(detail)}:victory`,\n kind: 'victory-rank',\n mapArea: sortie.mapArea,\n mapNo: sortie.mapNo,\n mapId: sortie.mapId,\n nodeNo: node.nodeNo,\n nodeLabel: node.nodeLabel,\n rank,\n observedAt: detail.time,\n sourcePath: detail.path,\n sortieId: sortie.id,\n battle: sortie.lastBattle,\n }\n appendObservation(state, sortie, observation)\n}\n\nfunction addDefenseBattles(\n state: TrackerState,\n sortie: ActiveSortie,\n detail: GameResponseDetail,\n): { signal: boolean } {\n const entries = extractDestructionBattles(detail.body)\n let signal = false\n entries.forEach((entry, index) => {\n signal ||= hasDefenseSignal(entry)\n const airState = extractDefenseAirState(entry)\n const node = currentNode(sortie)\n sortie.timeline.push({\n id: `${eventKey(detail)}:defense:${index}:timeline`,\n kind: 'base-air-defense',\n occurredAt: detail.time,\n sourcePath: detail.path,\n nodeVisitId: node?.id,\n nodeNo: node?.nodeNo,\n nodeLabel: node?.nodeLabel,\n airState,\n })\n if (node != null) {\n ;(node.baseDefenseEvents ??= []).push({\n timestamp: detail.time,\n path: detail.path,\n airState,\n })\n }\n if (airState == null) return\n const observation: BaseAirDefenseObservation = {\n id: `${eventKey(detail)}:defense:${index}`,\n kind: 'base-air-defense',\n mapArea: sortie.mapArea,\n mapNo: sortie.mapNo,\n mapId: sortie.mapId,\n airState,\n observedAt: detail.time,\n sourcePath: detail.path,\n sortieId: sortie.id,\n battle: { timestamp: detail.time, path: detail.path, kind: 'base-air-defense' },\n }\n appendObservation(state, sortie, observation)\n })\n return { signal }\n}\n\nfunction reviewFromSortie(\n state: TrackerState,\n sortie: ActiveSortie,\n source: TriggerSource,\n detectedAt: number,\n sealed: boolean,\n): PendingReview {\n return {\n id: `review:${sortie.id}`,\n sortieId: sortie.id,\n startedAt: sortie.startedAt,\n mapArea: sortie.mapArea,\n mapNo: sortie.mapNo,\n mapId: sortie.mapId,\n detectedAt,\n triggerSources: [source],\n sealed,\n routeComplete: sortie.captureComplete,\n route: cloneState({\n schemaVersion: 1,\n observations: [],\n guideConditions: [],\n reviews: [],\n freeCompletions: [],\n processedEventKeys: [],\n updatedAt: 0,\n activeSortie: sortie,\n }).activeSortie!.route,\n timeline: JSON.parse(JSON.stringify(sortie.timeline)) as PendingReview['timeline'],\n observationIds: [...sortie.observationIds],\n candidates: buildReviewCandidates(state, sortie.mapId, sortie.observationIds),\n status: 'pending',\n }\n}\n\nfunction orphanReview(state: TrackerState, source: TriggerSource, detectedAt: number): PendingReview {\n const sortieId = `orphan:${detectedAt}`\n return {\n id: `review:${sortieId}`,\n sortieId,\n startedAt: detectedAt,\n mapArea: 0,\n mapNo: 0,\n mapId: 0,\n detectedAt,\n triggerSources: [source],\n sealed: source === 'port',\n routeComplete: false,\n route: [],\n timeline: [],\n observationIds: [],\n candidates: buildReviewCandidates(state, 0, []),\n status: 'pending',\n }\n}\n\nfunction triggerReview(\n state: TrackerState,\n sortie: ActiveSortie | undefined,\n source: TriggerSource,\n detectedAt: number,\n sealed: boolean,\n): boolean {\n if (sortie == null && source === 'port') {\n const recentOrphan = [...state.reviews]\n .reverse()\n .find(\n (item) =>\n item.status === 'pending' &&\n item.sortieId.startsWith('orphan:') &&\n !item.sealed &&\n item.triggerSources.includes('battleresult') &&\n !item.triggerSources.includes('port') &&\n detectedAt - item.detectedAt <= 10 * 60 * 1000,\n )\n if (recentOrphan != null) {\n if (!recentOrphan.triggerSources.includes(source)) recentOrphan.triggerSources.push(source)\n recentOrphan.sealed ||= sealed || source === 'port'\n return false\n }\n }\n const candidate =\n sortie == null\n ? orphanReview(state, source, detectedAt)\n : reviewFromSortie(state, sortie, source, detectedAt, sealed)\n const existing = state.reviews.find((item) => item.id === candidate.id)\n if (existing == null) {\n state.reviews.push(candidate)\n return true\n }\n if (!existing.triggerSources.includes(source)) existing.triggerSources.push(source)\n existing.sealed ||= sealed\n if (sortie != null) {\n existing.routeComplete = sortie.captureComplete\n existing.route = candidate.route\n existing.timeline = candidate.timeline\n existing.observationIds = candidate.observationIds\n if (existing.status === 'pending') existing.candidates = candidate.candidates\n }\n return false\n}\n\nfunction syncReviewForActiveSortie(state: TrackerState, sealed = false): void {\n const sortie = state.activeSortie\n if (sortie == null) return\n const review = state.reviews.find((item) => item.sortieId === sortie.id)\n if (review == null) return\n review.sealed ||= sealed\n review.routeComplete = sortie.captureComplete\n review.route = JSON.parse(JSON.stringify(sortie.route)) as PendingReview['route']\n review.timeline = JSON.parse(JSON.stringify(sortie.timeline)) as PendingReview['timeline']\n review.observationIds = [...sortie.observationIds]\n if (review.status === 'pending') {\n review.candidates = buildReviewCandidates(state, sortie.mapId, sortie.observationIds)\n }\n}\n\nfunction handleMapEvent(\n state: TrackerState,\n detail: GameResponseDetail,\n nodeResolver: NodeResolver,\n): boolean {\n const isStart = detail.path === '/kcsapi/api_req_map/start'\n if (isStart) {\n const map = extractMapRef(detail)\n state.activeSortie = createSortie(detail, map, true)\n } else if (state.activeSortie == null) {\n const map = extractMapRef(detail)\n state.activeSortie = createSortie(detail, map, false)\n } else {\n const map = extractMapRef(detail, state.activeSortie)\n Object.assign(state.activeSortie, map)\n }\n\n const sortie = state.activeSortie\n if (detail.path !== '/kcsapi/api_req_map/air_raid') {\n addNodeVisit(state, sortie, detail, nodeResolver)\n }\n const defense = addDefenseBattles(state, sortie, detail)\n let shouldFocus = false\n if (defense.signal) {\n shouldFocus = triggerReview(state, sortie, 'air-defense', detail.time, false)\n }\n syncReviewForActiveSortie(state)\n return shouldFocus\n}\n\nexport function applyGameResponse(\n previous: TrackerState,\n detail: GameResponseDetail,\n nodeResolver: NodeResolver,\n): TransitionResult {\n if (!isRelevantPath(detail.path)) {\n return { state: previous, changed: false, shouldFocus: false }\n }\n const key = eventKey(detail)\n if (previous.processedEventKeys.includes(key)) {\n return { state: previous, changed: false, shouldFocus: false }\n }\n\n const state = cloneState(previous)\n state.processedEventKeys.push(key)\n if (state.processedEventKeys.length > MAX_PROCESSED_EVENT_KEYS) {\n state.processedEventKeys.splice(0, state.processedEventKeys.length - MAX_PROCESSED_EVENT_KEYS)\n }\n let shouldFocus = false\n\n if (MAP_PATHS.has(detail.path)) {\n shouldFocus = handleMapEvent(state, detail, nodeResolver)\n } else if (isBattleResultPath(detail.path)) {\n if (state.activeSortie != null) addBattleResult(state, state.activeSortie, detail)\n if (hasBattleResultSignal(detail)) {\n shouldFocus = triggerReview(\n state,\n state.activeSortie,\n 'battleresult',\n detail.time,\n false,\n )\n }\n syncReviewForActiveSortie(state)\n } else if (isBattlePath(detail.path)) {\n if (state.activeSortie != null) {\n addBattle(state, state.activeSortie, detail)\n syncReviewForActiveSortie(state)\n }\n } else if (detail.path === '/kcsapi/api_port/port') {\n if (hasPortSignal(detail)) {\n shouldFocus = triggerReview(state, state.activeSortie, 'port', detail.time, true)\n }\n syncReviewForActiveSortie(state, true)\n state.activeSortie = undefined\n }\n\n state.updatedAt = detail.time\n return { state, changed: true, shouldFocus }\n}\n\nfunction refreshPendingCandidates(state: TrackerState): void {\n for (const review of state.reviews) {\n if (review.status !== 'pending') continue\n review.candidates = buildReviewCandidates(state, review.mapId, review.observationIds)\n }\n}\n\nexport function importGuideConditions(\n previous: TrackerState,\n text: string,\n map: MapRef,\n now: number,\n): ImportGuideResult {\n const parsed = parseGuideText(text)\n if (parsed.length === 0) return { state: previous, importedCount: 0 }\n const state = cloneState(previous)\n const unique = new Map<string, (typeof parsed)[number]>()\n for (const item of parsed) unique.set(conditionSignature(map, item), item)\n\n for (const [signature, item] of unique) {\n const id = `guide:${signature}`\n const existing = state.guideConditions.find((condition) => condition.id === id)\n if (existing != null) {\n existing.rawText = item.rawText\n existing.requiredCount = item.requiredCount\n existing.observedCount = state.observations.filter((observation) =>\n observationMatches(existing, observation),\n ).length\n continue\n }\n const condition: GuideCondition = {\n ...map,\n id,\n kind: item.kind,\n rawText: item.rawText,\n nodeLabel: item.nodeLabel,\n requiredRank: item.requiredRank,\n requiredAirState: item.requiredAirState,\n requiredCount: item.requiredCount,\n observedCount: 0,\n confirmed: false,\n createdAt: now,\n }\n condition.observedCount = state.observations.filter((observation) =>\n observationMatches(condition, observation),\n ).length\n state.guideConditions.push(condition)\n }\n refreshPendingCandidates(state)\n state.updatedAt = now\n return { state, importedCount: unique.size }\n}\n\nexport function confirmReview(\n previous: TrackerState,\n reviewId: string,\n candidateIds: string[],\n now: number,\n): TrackerState {\n if (candidateIds.length === 0) return previous\n const state = cloneState(previous)\n const review = state.reviews.find((item) => item.id === reviewId)\n if (review == null || review.status !== 'pending') return previous\n const selected = review.candidates.filter((candidate) => candidateIds.includes(candidate.id))\n if (selected.length === 0) return previous\n\n const mapHasGuide = state.guideConditions.some((condition) => condition.mapId === review.mapId)\n for (const candidate of selected) {\n if (candidate.mode === 'guide' && candidate.conditionId != null) {\n const condition = state.guideConditions.find((item) => item.id === candidate.conditionId)\n if (condition != null && !condition.confirmed) {\n condition.confirmed = true\n condition.confirmedAt = now\n condition.confirmedByReviewId = review.id\n }\n continue\n }\n if (mapHasGuide || candidate.observationId == null) continue\n const observation = state.observations.find((item) => item.id === candidate.observationId)\n if (observation == null) continue\n const completion: FreeCompletion = {\n mapArea: review.mapArea,\n mapNo: review.mapNo,\n mapId: review.mapId,\n id: `free-completion:${review.id}:${candidate.observationId}`,\n kind: candidate.kind,\n label: candidate.label,\n reviewId: review.id,\n observationId: candidate.observationId,\n confirmedAt: now,\n }\n if (!state.freeCompletions.some((item) => item.id === completion.id)) {\n state.freeCompletions.push(completion)\n }\n }\n review.status = 'confirmed'\n review.selectedCandidateIds = selected.map((candidate) => candidate.id)\n review.resolvedAt = now\n refreshPendingCandidates(state)\n state.updatedAt = now\n return state\n}\n\nexport function ignoreReview(previous: TrackerState, reviewId: string, now: number): TrackerState {\n const state = cloneState(previous)\n const review = state.reviews.find((item) => item.id === reviewId)\n if (review == null || review.status !== 'pending') return previous\n review.status = 'ignored'\n review.resolvedAt = now\n state.updatedAt = now\n return state\n}\n","import { existsSync, mkdirSync, readFileSync, renameSync, unlinkSync, writeFileSync } from 'fs'\nimport { join } from 'path'\n\nimport { createInitialState, SCHEMA_VERSION, type TrackerState } from '../core'\n\nexport interface TrackerStorage {\n load(memberId: string): TrackerState\n save(memberId: string, state: TrackerState): void\n}\n\nexport function normalizeMemberId(value: unknown): string | undefined {\n if (value == null) return undefined\n const normalized = typeof value === 'number' ? String(value) : typeof value === 'string' ? value : ''\n return /^\\d+$/.test(normalized) ? normalized : undefined\n}\n\nfunction hydrateState(value: unknown): TrackerState {\n if (typeof value !== 'object' || value == null) return createInitialState()\n const raw = value as Partial<TrackerState>\n if (raw.schemaVersion !== SCHEMA_VERSION) return createInitialState()\n const reviews = Array.isArray(raw.reviews)\n ? raw.reviews.map((review) => ({\n ...review,\n startedAt:\n typeof review.startedAt === 'number'\n ? review.startedAt\n : review.route?.[0]?.arrivedAt ?? review.detectedAt,\n timeline: Array.isArray(review.timeline) ? review.timeline : [],\n }))\n : []\n const activeSortie =\n raw.activeSortie != null\n ? {\n ...raw.activeSortie,\n timeline: Array.isArray(raw.activeSortie.timeline) ? raw.activeSortie.timeline : [],\n }\n : undefined\n return {\n ...createInitialState(typeof raw.updatedAt === 'number' ? raw.updatedAt : 0),\n ...raw,\n schemaVersion: SCHEMA_VERSION,\n observations: Array.isArray(raw.observations) ? raw.observations : [],\n guideConditions: Array.isArray(raw.guideConditions) ? raw.guideConditions : [],\n reviews,\n freeCompletions: Array.isArray(raw.freeCompletions) ? raw.freeCompletions : [],\n processedEventKeys: Array.isArray(raw.processedEventKeys) ? raw.processedEventKeys : [],\n activeSortie,\n }\n}\n\nexport class FileTrackerStorage implements TrackerStorage {\n constructor(private readonly appDataPath: string) {}\n\n statePath(memberId: string): string {\n const safe = normalizeMemberId(memberId)\n if (safe == null) throw new Error('Invalid memberId')\n return join(this.appDataPath, 'gimmick-tracker', safe, 'state-v1.json')\n }\n\n load(memberId: string): TrackerState {\n const path = this.statePath(memberId)\n if (!existsSync(path)) return createInitialState()\n try {\n return hydrateState(JSON.parse(readFileSync(path, 'utf8')) as unknown)\n } catch {\n return createInitialState()\n }\n }\n\n save(memberId: string, state: TrackerState): void {\n const path = this.statePath(memberId)\n const directory = join(path, '..')\n mkdirSync(directory, { recursive: true })\n const temporary = `${path}.${process.pid}.${Date.now()}.tmp`\n try {\n writeFileSync(temporary, `${JSON.stringify(state, null, 2)}\\n`, 'utf8')\n renameSync(temporary, path)\n } catch (error) {\n try {\n if (existsSync(temporary)) unlinkSync(temporary)\n } catch {\n // Preserve the original write error.\n }\n throw error\n }\n }\n}\n\nexport class MemoryTrackerStorage implements TrackerStorage {\n readonly states = new Map<string, TrackerState>()\n\n load(memberId: string): TrackerState {\n const state = this.states.get(memberId)\n return state == null ? createInitialState() : JSON.parse(JSON.stringify(state)) as TrackerState\n }\n\n save(memberId: string, state: TrackerState): void {\n this.states.set(memberId, JSON.parse(JSON.stringify(state)) as TrackerState)\n }\n}\n","import {\n applyGameResponse,\n asRecord,\n confirmReview,\n createInitialState,\n extractPortMemberId,\n ignoreReview,\n importGuideConditions,\n type GameResponseDetail,\n type MapRef,\n type NodeResolver,\n type TrackerState,\n} from './core'\nimport type { FocusMethod } from './host'\nimport { normalizeMemberId, type TrackerStorage } from './storage'\n\nexport interface EventTargetLike {\n addEventListener(type: string, listener: (event: unknown) => void): void\n removeEventListener(type: string, listener: (event: unknown) => void): void\n}\n\nexport interface TrackerControllerDependencies {\n storage: TrackerStorage\n focus: { focusPlugin(id: string): FocusMethod | string }\n pluginId: string\n nodeResolver: NodeResolver\n getMemberId?: () => unknown\n now?: () => number\n onError?: (error: unknown) => void\n}\n\nfunction parseEvent(event: unknown): GameResponseDetail | undefined {\n if (typeof event !== 'object' || event == null) return undefined\n const detail = (event as { detail?: unknown }).detail\n if (typeof detail !== 'object' || detail == null) return undefined\n const value = detail as Record<string, unknown>\n if (typeof value.path !== 'string' || typeof value.time !== 'number') return undefined\n return {\n method: typeof value.method === 'string' ? value.method : undefined,\n path: value.path,\n body: asRecord(value.body) ?? {},\n postBody: asRecord(value.postBody),\n time: value.time,\n }\n}\n\nfunction mergeById<T extends { id: string }>(stored: T[], transient: T[]): T[] {\n const merged = new Map(stored.map((item) => [item.id, item]))\n for (const item of transient) merged.set(item.id, item)\n return [...merged.values()]\n}\n\nexport class TrackerController {\n private state: TrackerState = createInitialState()\n private readonly subscribers = new Set<() => void>()\n private eventTarget?: EventTargetLike\n private memberId?: string\n private started = false\n\n private readonly handleResponse = (event: unknown): void => {\n const detail = parseEvent(event)\n if (detail == null) return\n try {\n const preferred = this.readPreferredMemberId()\n const portMember = normalizeMemberId(extractPortMemberId(detail))\n this.switchMember(portMember ?? preferred)\n const result = applyGameResponse(this.state, detail, this.dependencies.nodeResolver)\n if (!result.changed) return\n this.state = result.state\n this.persist()\n this.emit()\n if (result.shouldFocus) {\n try {\n this.dependencies.focus.focusPlugin(this.dependencies.pluginId)\n } catch (error) {\n this.report(error)\n }\n }\n } catch (error) {\n this.report(error)\n }\n }\n\n constructor(private readonly dependencies: TrackerControllerDependencies) {}\n\n start(target: EventTargetLike): void {\n if (this.started) return\n this.started = true\n this.eventTarget = target\n this.switchMember(this.readPreferredMemberId())\n target.addEventListener('game.response', this.handleResponse)\n this.emit()\n }\n\n stop(): void {\n if (!this.started) return\n this.eventTarget?.removeEventListener('game.response', this.handleResponse)\n this.eventTarget = undefined\n this.started = false\n }\n\n getSnapshot = (): TrackerState => this.state\n\n subscribe = (subscriber: () => void): (() => void) => {\n this.subscribers.add(subscriber)\n return () => this.subscribers.delete(subscriber)\n }\n\n currentMap(): MapRef | undefined {\n if (this.state.activeSortie != null && this.state.activeSortie.mapId > 0) {\n return {\n mapArea: this.state.activeSortie.mapArea,\n mapNo: this.state.activeSortie.mapNo,\n mapId: this.state.activeSortie.mapId,\n }\n }\n const review = [...this.state.reviews].reverse().find((item) => item.mapId > 0)\n if (review != null) {\n return { mapArea: review.mapArea, mapNo: review.mapNo, mapId: review.mapId }\n }\n const observation = this.state.observations.at(-1)\n return observation == null\n ? undefined\n : {\n mapArea: observation.mapArea,\n mapNo: observation.mapNo,\n mapId: observation.mapId,\n }\n }\n\n importGuide(text: string, map = this.currentMap()): number {\n if (map == null) return 0\n const result = importGuideConditions(this.state, text, map, this.now())\n if (result.state === this.state) return result.importedCount\n this.state = result.state\n this.persist()\n this.emit()\n return result.importedCount\n }\n\n confirm(reviewId: string, candidateIds: string[]): void {\n const next = confirmReview(this.state, reviewId, candidateIds, this.now())\n if (next === this.state) return\n this.state = next\n this.persist()\n this.emit()\n }\n\n ignore(reviewId: string): void {\n const next = ignoreReview(this.state, reviewId, this.now())\n if (next === this.state) return\n this.state = next\n this.persist()\n this.emit()\n }\n\n private now(): number {\n return this.dependencies.now?.() ?? Date.now()\n }\n\n private readPreferredMemberId(): string | undefined {\n try {\n return normalizeMemberId(this.dependencies.getMemberId?.())\n } catch (error) {\n this.report(error)\n return undefined\n }\n }\n\n private switchMember(next: string | undefined): void {\n if (next == null || next === this.memberId) return\n if (this.memberId != null) this.persist()\n const transient = this.memberId == null ? this.state : undefined\n this.memberId = next\n try {\n const stored = this.dependencies.storage.load(next)\n if (transient == null || (transient.updatedAt === 0 && transient.activeSortie == null)) {\n this.state = stored\n return\n }\n this.state = {\n ...stored,\n activeSortie: transient.activeSortie ?? stored.activeSortie,\n observations: mergeById(stored.observations, transient.observations),\n guideConditions: mergeById(stored.guideConditions, transient.guideConditions),\n reviews: mergeById(stored.reviews, transient.reviews),\n freeCompletions: mergeById(stored.freeCompletions, transient.freeCompletions),\n processedEventKeys: [...new Set([\n ...stored.processedEventKeys,\n ...transient.processedEventKeys,\n ])].slice(-2048),\n updatedAt: Math.max(stored.updatedAt, transient.updatedAt),\n }\n } catch (error) {\n this.state = transient ?? createInitialState()\n this.report(error)\n }\n }\n\n private persist(): void {\n if (this.memberId == null) return\n try {\n this.dependencies.storage.save(this.memberId, this.state)\n } catch (error) {\n this.report(error)\n }\n }\n\n private emit(): void {\n for (const subscriber of this.subscribers) subscriber()\n }\n\n private report(error: unknown): void {\n this.dependencies.onError?.(error)\n }\n}\n","export interface IpcLike {\n access(scope: string): { ipcFocusPlugin?: (id: string) => void } | undefined\n}\n\nexport interface FocusAdapterDependencies {\n primaryIpc?: IpcLike\n legacyIpc?: IpcLike\n dispatch?: (action: unknown) => unknown\n getStore?: (path: string) => unknown\n success?: (message: string) => unknown\n}\n\nexport type FocusMethod = 'ipc' | 'legacy-ipc' | 'dispatch' | 'notice' | 'none'\n\nfunction tryIpc(ipc: IpcLike | undefined, id: string): boolean {\n try {\n const focus = ipc?.access('MainWindow')?.ipcFocusPlugin\n if (typeof focus !== 'function') return false\n focus(id)\n return true\n } catch {\n return false\n }\n}\n\nexport function createFocusAdapter(dependencies: FocusAdapterDependencies) {\n return {\n focusPlugin(id: string): FocusMethod {\n if (tryIpc(dependencies.primaryIpc, id)) return 'ipc'\n if (tryIpc(dependencies.legacyIpc, id)) return 'legacy-ipc'\n try {\n if (typeof dependencies.dispatch === 'function') {\n const doubleTabbed = Boolean(dependencies.getStore?.('config.poi.tabarea.double'))\n const tabInfo = doubleTabbed\n ? { activePluginName: id }\n : { activeMainTab: id, activePluginName: id }\n dependencies.dispatch({\n type: '@@TabSwitch',\n payload: { tabInfo, autoSwitch: false },\n })\n return 'dispatch'\n }\n } catch {\n // Continue to the non-throwing notification fallback.\n }\n try {\n if (typeof dependencies.success === 'function') {\n dependencies.success('检测到机关变化,请打开机关条件追踪器确认。')\n return 'notice'\n }\n } catch {\n // Host notifications must never break response handling.\n }\n return 'none'\n },\n }\n}\n","import type { NodeResolver } from '../core'\n\nexport type StoreGetter = (path?: string) => unknown\n\nexport function createFcdNodeResolver(getStore: StoreGetter): NodeResolver {\n return ({ mapArea, mapNo, apiNo }) => {\n const fallback = `#${apiNo}`\n try {\n const fcdMap = getStore('fcd.map')\n if (typeof fcdMap !== 'object' || fcdMap == null) return fallback\n const map = (fcdMap as Record<string, unknown>)[`${mapArea}-${mapNo}`]\n if (typeof map !== 'object' || map == null) return fallback\n const route = (map as Record<string, unknown>).route\n if (typeof route !== 'object' || route == null) return fallback\n const edge = (route as Record<string, unknown>)[String(apiNo)]\n if (!Array.isArray(edge) || typeof edge[1] !== 'string' || edge[1].trim() === '') {\n return fallback\n }\n return edge[1]\n } catch {\n return fallback\n }\n }\n}\n","{\n \"机关条件追踪器\": \"机关条件追踪器\",\n \"记录出击路线并在机关触发后请用户确认完成条件\": \"记录出击路线并在机关触发后请用户确认完成条件\",\n \"title\": \"机关条件追踪器\",\n \"subtitle\": \"平时安静记录;检测到机关变化后才请你确认。数据只保存在本机。\",\n \"activeMap\": \"当前海域\",\n \"pendingReviews\": \"待确认触发\",\n \"pending\": \"待确认\",\n \"noPending\": \"暂无待确认触发。普通出击不会自动切换到本页。\",\n \"unknownMap\": \"未知海域\",\n \"route\": \"本次路线\",\n \"incompleteRoute\": \"未捕获到完整出击:插件可能在出击中途加载,或仅收到了回港信号。\",\n \"emptyRoute\": \"没有可显示的节点路线。\",\n \"candidates\": \"这次完成了哪一项?\",\n \"chooseCandidate\": \"请选择本次完成条件(● 表示本次有直接证据)\",\n \"noCandidates\": \"没有足够事实生成候选;可忽略本次,或先导入攻略条件后再观察下一次出击。\",\n \"matchedThisSortie\": \"本次有证据\",\n \"confirm\": \"确认完成\",\n \"ignore\": \"忽略本次\",\n \"ignored\": \"已忽略\",\n \"guide\": \"导入攻略条件\",\n \"guidePlaceholder\": \"例如:D点S胜2次;C2点到达2次 A2点空优1次,守家空优2次\",\n \"import\": \"导入到当前海域\",\n \"importNeedMap\": \"尚未识别当前海域,请先捕获一次地图出击。\",\n \"importSuccess\": \"已识别 {count} 条条件。\",\n \"noMatch\": \"未识别到受支持的条件格式。\",\n \"completed\": \"按海域的上次触发与完成清单\",\n \"lastTriggeredSortie\": \"上一次触发出击\",\n \"triggerHistory\": \"每次机关触发出击\",\n \"noCompleted\": \"尚未导入攻略条件,也没有自由完成记录。\",\n \"observed\": \"观测\",\n \"confirmed\": \"已确认\",\n \"unconfirmed\": \"未确认\",\n \"freeRecord\": \"无攻略时的自由记录\"\n}\n","import {\n Button,\n Callout,\n Card,\n Elevation,\n HTMLSelect,\n HTMLTable,\n Tag,\n TextArea,\n} from '@blueprintjs/core'\nimport React, { useMemo, useState, useSyncExternalStore } from 'react'\n\nimport zhCN from '../../i18n/zh-CN.json'\nimport { airStateLabel, guideConditionLabel, mapLabel, type PendingReview } from '../core'\nimport type { TrackerController } from '../controller'\n\nconst styles: Record<string, React.CSSProperties> = {\n root: { padding: 16, height: '100%', overflow: 'auto', boxSizing: 'border-box' },\n header: { display: 'flex', justifyContent: 'space-between', gap: 16, alignItems: 'center' },\n section: { marginTop: 16 },\n review: { marginTop: 12 },\n reviewGrid: { display: 'grid', gridTemplateColumns: 'minmax(260px, 1.2fr) minmax(280px, .8fr)', gap: 18 },\n route: { display: 'flex', flexWrap: 'wrap', gap: 6, marginTop: 8 },\n historyRow: { display: 'grid', gridTemplateColumns: 'minmax(280px, 1fr) auto', gap: 16, padding: '10px 0', borderBottom: '1px solid rgba(128,128,128,.18)' },\n candidate: { padding: '6px 0', borderBottom: '1px solid rgba(128,128,128,.18)' },\n actions: { display: 'flex', gap: 8, marginTop: 12 },\n guideRow: { display: 'grid', gridTemplateColumns: '1fr auto auto', gap: 12, alignItems: 'center' },\n muted: { color: '#738091' },\n}\n\ntype TextKey = keyof typeof zhCN\nconst t = (key: TextKey): string => zhCN[key]\n\nfunction routeBadge(review: PendingReview, index: number): React.ReactNode {\n const visit = review.route[index]\n const details = [visit.rank == null ? undefined : `${visit.rank}胜`]\n if (visit.airState != null) details.push(airStateLabel(visit.airState))\n if (visit.battleEvents?.some((event) => event.kind === 'fleet-air-raid')) details.push('舰队空袭')\n for (const defense of visit.baseDefenseEvents ?? []) {\n details.push(`基地防空${defense.airState == null ? '' : ` · ${airStateLabel(defense.airState)}`}`)\n }\n return (\n <Tag\n key={visit.id}\n minimal={index !== review.route.length - 1}\n title={new Date(visit.arrivedAt).toLocaleString()}\n >\n {visit.nodeLabel}\n {details.filter(Boolean).length > 0 ? ` · ${details.filter(Boolean).join(' · ')}` : ''}\n </Tag>\n )\n}\n\nfunction formatSortieTime(review: PendingReview): string {\n const startedAt = review.startedAt ?? review.route[0]?.arrivedAt ?? review.detectedAt\n return `${new Date(startedAt).toLocaleString()} ~ ${new Date(review.detectedAt).toLocaleString()}`\n}\n\nfunction timelineBadge(review: PendingReview, event: PendingReview['timeline'][number]): React.ReactNode {\n if (event.kind === 'node') {\n const index = review.route.findIndex((visit) => visit.id === event.nodeVisitId)\n if (index >= 0) return routeBadge(review, index)\n }\n const label = event.kind === 'fleet-air-raid' ? '舰队空袭' : '基地防空'\n const parts = [event.nodeLabel == null ? undefined : `${event.nodeLabel}点`, label]\n if (event.airState != null) parts.push(airStateLabel(event.airState))\n return (\n <Tag key={event.id} intent={event.kind === 'base-air-defense' ? 'warning' : 'primary'} title={new Date(event.occurredAt).toLocaleString()}>\n {parts.filter(Boolean).join(' · ')}\n </Tag>\n )\n}\n\nfunction sortieTimeline(review: PendingReview): React.ReactNode {\n const timeline = review.timeline ?? []\n if (timeline.length > 0) {\n return <div style={styles.route}>{timeline.map((event) => timelineBadge(review, event))}</div>\n }\n if (review.route.length > 0) {\n return <div style={styles.route}>{review.route.map((_, index) => routeBadge(review, index))}</div>\n }\n return <span style={styles.muted}>{t('emptyRoute')}</span>\n}\n\nfunction PendingCard({\n review,\n selected,\n setSelected,\n controller,\n}: {\n review: PendingReview\n selected: string\n setSelected: (id: string) => void\n controller: TrackerController\n}) {\n const selectedCandidate = review.candidates.find((candidate) => candidate.id === selected)\n return (\n <Card style={styles.review} elevation={Elevation.ONE}>\n <div style={styles.header}>\n <div>\n <strong>{review.mapId > 0 ? mapLabel(review) : t('unknownMap')}</strong>{' '}\n <Tag intent=\"warning\">{t('pending')}</Tag>\n <div style={styles.muted}>{formatSortieTime(review)}</div>\n </div>\n <div style={styles.route}>\n {review.triggerSources.map((source) => (\n <Tag key={source} minimal>\n {source}\n </Tag>\n ))}\n </div>\n </div>\n <div style={styles.reviewGrid}>\n <div>\n <h4>{t('route')}</h4>\n {!review.routeComplete && <Callout intent=\"warning\">{t('incompleteRoute')}</Callout>}\n {sortieTimeline(review)}\n </div>\n <div>\n <h4>{t('candidates')}</h4>\n {review.candidates.length === 0 ? (\n <Callout>{t('noCandidates')}</Callout>\n ) : (\n <>\n <HTMLSelect\n fill\n value={selected}\n onChange={(event) => setSelected(event.currentTarget.value)}\n >\n <option value=\"\">{t('chooseCandidate')}</option>\n {review.candidates.map((candidate) => (\n <option key={candidate.id} value={candidate.id}>\n {candidate.matchedInSortie ? '● ' : ''}{candidate.label}\n {candidate.observedCount == null\n ? ''\n : ` · ${t('observed')} ${candidate.observedCount}/${candidate.requiredCount}`}\n </option>\n ))}\n </HTMLSelect>\n {selectedCandidate?.matchedInSortie && (\n <Callout style={{ marginTop: 8 }} intent=\"success\">{t('matchedThisSortie')}</Callout>\n )}\n </>\n )}\n <div style={styles.actions}>\n <Button\n intent=\"primary\"\n disabled={selected === ''}\n onClick={() => controller.confirm(review.id, [selected])}\n >\n {t('confirm')}\n </Button>\n <Button onClick={() => controller.ignore(review.id)}>{t('ignore')}</Button>\n </div>\n </div>\n </div>\n </Card>\n )\n}\n\nexport function createTrackerView(controller: TrackerController): React.ComponentType {\n return function GimmickTrackerView() {\n const state = useSyncExternalStore(controller.subscribe, controller.getSnapshot, controller.getSnapshot)\n const [guideText, setGuideText] = useState('')\n const [message, setMessage] = useState('')\n const [selected, setSelected] = useState<Record<string, string>>({})\n const pending = state.reviews.filter((review) => review.status === 'pending')\n const currentMap = controller.currentMap()\n const mapIds = useMemo(\n () =>\n [...new Set([\n ...state.guideConditions.map((item) => item.mapId),\n ...state.freeCompletions.map((item) => item.mapId),\n ...state.reviews.filter((item) => item.mapId > 0).map((item) => item.mapId),\n ])].sort((left, right) => left - right),\n [state.guideConditions, state.freeCompletions, state.reviews],\n )\n\n const importGuide = () => {\n if (currentMap == null) {\n setMessage(t('importNeedMap'))\n return\n }\n const count = controller.importGuide(guideText, currentMap)\n setMessage(count > 0 ? t('importSuccess').replace('{count}', String(count)) : t('noMatch'))\n }\n\n return (\n <main style={styles.root}>\n <header style={styles.header}>\n <div>\n <h2 style={{ margin: 0 }}>{t('title')}</h2>\n <p style={{ ...styles.muted, marginBottom: 0 }}>{t('subtitle')}</p>\n </div>\n {currentMap != null && <Tag large>{t('activeMap')}: {mapLabel(currentMap)}</Tag>}\n </header>\n\n <section style={styles.section}>\n <h3>{t('pendingReviews')}</h3>\n {pending.length === 0 ? (\n <Callout>{t('noPending')}</Callout>\n ) : (\n pending.map((review) => (\n <PendingCard\n key={review.id}\n review={review}\n controller={controller}\n selected={selected[review.id] ?? ''}\n setSelected={(id) => setSelected((value) => ({ ...value, [review.id]: id }))}\n />\n ))\n )}\n </section>\n\n <section style={styles.section}>\n <h3>{t('guide')}</h3>\n <TextArea\n fill\n rows={4}\n value={guideText}\n placeholder={t('guidePlaceholder')}\n onChange={(event) => setGuideText(event.currentTarget.value)}\n />\n <div style={styles.actions}>\n <Button intent=\"primary\" onClick={importGuide}>{t('import')}</Button>\n {message !== '' && <span style={styles.muted}>{message}</span>}\n </div>\n </section>\n\n <section style={styles.section}>\n <h3>{t('completed')}</h3>\n {mapIds.length === 0 ? (\n <Callout>{t('noCompleted')}</Callout>\n ) : (\n mapIds.map((mapId) => {\n const guides = state.guideConditions.filter((item) => item.mapId === mapId)\n const free = state.freeCompletions.filter((item) => item.mapId === mapId)\n const reviews = state.reviews.filter((item) => item.mapId === mapId)\n const lastReview = reviews.at(-1)\n const map = guides[0] ?? free[0] ?? lastReview\n return (\n <Card key={mapId} style={styles.review} elevation={Elevation.ZERO}>\n <h4>{map == null ? `#${mapId}` : mapLabel(map)}</h4>\n {reviews.length > 0 && (\n <div style={{ marginBottom: 16 }}>\n <strong>{t('triggerHistory')}</strong>\n {[...reviews].reverse().map((review) => {\n const selectedLabels = review.candidates\n .filter((candidate) => review.selectedCandidateIds?.includes(candidate.id))\n .map((candidate) => candidate.label)\n return (\n <div key={review.id} style={styles.historyRow}>\n <div>{sortieTimeline(review)}</div>\n <div style={{ textAlign: 'right' }}>\n <div style={styles.muted}>{formatSortieTime(review)}</div>\n <Tag\n intent={review.status === 'confirmed' ? 'success' : review.status === 'pending' ? 'warning' : 'none'}\n >\n {review.status === 'confirmed'\n ? t('confirmed')\n : review.status === 'pending'\n ? t('pending')\n : t('ignored')}\n </Tag>\n {selectedLabels.length > 0 && <div>{selectedLabels.join('、')}</div>}\n </div>\n </div>\n )\n })}\n </div>\n )}\n <HTMLTable compact striped style={{ width: '100%' }}>\n <tbody>\n {guides.map((condition) => (\n <tr key={condition.id}>\n <td>{guideConditionLabel(condition)}</td>\n <td>{t('observed')} {condition.observedCount}/{condition.requiredCount}</td>\n <td>\n <Tag intent={condition.confirmed ? 'success' : 'none'}>\n {condition.confirmed ? t('confirmed') : t('unconfirmed')}\n </Tag>\n </td>\n </tr>\n ))}\n {free.map((completion) => (\n <tr key={completion.id}>\n <td>{completion.label}</td>\n <td>{t('freeRecord')}</td>\n <td><Tag intent=\"success\">{t('confirmed')}</Tag></td>\n </tr>\n ))}\n </tbody>\n </HTMLTable>\n </Card>\n )\n })\n )}\n </section>\n </main>\n )\n }\n}\n","import { dispatch, getStore } from 'views/create-store'\nimport { APPDATA_PATH, ipc } from 'views/env'\n\nimport { PLUGIN_ID } from './src/core'\nimport { TrackerController } from './src/controller'\nimport { createFocusAdapter, createFcdNodeResolver } from './src/host'\nimport { FileTrackerStorage } from './src/storage'\nimport { createTrackerView } from './src/ui'\n\nconst appDataPath = window.APPDATA_PATH ?? APPDATA_PATH\nconst controller = new TrackerController({\n storage: new FileTrackerStorage(appDataPath),\n focus: createFocusAdapter({\n primaryIpc: ipc,\n legacyIpc: window.ipc,\n dispatch,\n getStore: (path) => getStore(path),\n success: window.success,\n }),\n pluginId: PLUGIN_ID,\n nodeResolver: createFcdNodeResolver((path) => getStore(path)),\n getMemberId: () => getStore('info.basic.api_member_id'),\n onError: (error) => console.error(`[${PLUGIN_ID}]`, error),\n})\n\nexport const reactClass = createTrackerView(controller)\nexport const windowMode = false\n\nexport function pluginDidLoad(): void {\n controller.start(window)\n}\n\nexport function pluginWillUnload(): void {\n controller.stop()\n}\n"],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "poi-plugin-gimmick-tracker",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Track and confirm KanColle event-map gimmick conditions in poi.",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"files": [
|
|
7
|
+
"index.js",
|
|
8
|
+
"index.js.map",
|
|
9
|
+
"i18n",
|
|
10
|
+
"README.md"
|
|
11
|
+
],
|
|
12
|
+
"scripts": {
|
|
13
|
+
"build": "tsdown",
|
|
14
|
+
"typecheck": "tsc --noEmit",
|
|
15
|
+
"test": "vitest run",
|
|
16
|
+
"prepack": "npm run build"
|
|
17
|
+
},
|
|
18
|
+
"peerDependencies": {
|
|
19
|
+
"@blueprintjs/core": ">=5.7.2 <7",
|
|
20
|
+
"react": "^18.3.1",
|
|
21
|
+
"react-dom": "^18.3.1"
|
|
22
|
+
},
|
|
23
|
+
"devDependencies": {
|
|
24
|
+
"@blueprintjs/core": "^5.7.2",
|
|
25
|
+
"@types/node": "^22.0.0",
|
|
26
|
+
"@types/react": "^18.3.0",
|
|
27
|
+
"@types/react-dom": "^18.3.0",
|
|
28
|
+
"react": "^18.3.1",
|
|
29
|
+
"react-dom": "^18.3.1",
|
|
30
|
+
"tsdown": "^0.17.0",
|
|
31
|
+
"typescript": "^5.8.0",
|
|
32
|
+
"vitest": "^3.2.0"
|
|
33
|
+
},
|
|
34
|
+
"engines": {
|
|
35
|
+
"node": ">=22"
|
|
36
|
+
},
|
|
37
|
+
"license": "MIT",
|
|
38
|
+
"author": "inoryirony",
|
|
39
|
+
"poiPlugin": {
|
|
40
|
+
"id": "poi-plugin-gimmick-tracker",
|
|
41
|
+
"title": "机关条件追踪器",
|
|
42
|
+
"name": "机关条件追踪器",
|
|
43
|
+
"description": "记录出击路线并在机关触发后请用户确认完成条件",
|
|
44
|
+
"icon": "fa/check-square-o",
|
|
45
|
+
"priority": 120,
|
|
46
|
+
"earliestCompatibleMain": "11.1.0",
|
|
47
|
+
"i18nDir": "i18n"
|
|
48
|
+
}
|
|
49
|
+
}
|